black format all (#4014)
This commit is contained in:
@@ -28,14 +28,7 @@ sys.path.insert(0, "../")
|
||||
|
||||
|
||||
class DocVQAExample(object):
|
||||
|
||||
def __init__(self,
|
||||
question,
|
||||
doc_tokens,
|
||||
doc_boxes=[],
|
||||
answer=None,
|
||||
labels=None,
|
||||
image=None):
|
||||
def __init__(self, question, doc_tokens, doc_boxes=[], answer=None, labels=None, image=None):
|
||||
self.question = question
|
||||
self.doc_tokens = doc_tokens
|
||||
self.doc_boxes = doc_boxes
|
||||
@@ -47,13 +40,7 @@ class DocVQAExample(object):
|
||||
class DocVQAFeatures(object):
|
||||
"""A single set of features of data."""
|
||||
|
||||
def __init__(self,
|
||||
example_index,
|
||||
input_ids,
|
||||
input_mask,
|
||||
segment_ids,
|
||||
boxes=None,
|
||||
label=None):
|
||||
def __init__(self, example_index, input_ids, input_mask, segment_ids, boxes=None, label=None):
|
||||
self.example_index = example_index
|
||||
self.input_ids = input_ids
|
||||
self.input_mask = input_mask
|
||||
@@ -63,15 +50,9 @@ class DocVQAFeatures(object):
|
||||
|
||||
|
||||
class DocVQA(Dataset):
|
||||
|
||||
def __init__(self,
|
||||
args,
|
||||
tokenizer,
|
||||
label2id_map,
|
||||
max_seq_len=512,
|
||||
max_query_length=20,
|
||||
max_doc_length=512,
|
||||
max_span_num=1):
|
||||
def __init__(
|
||||
self, args, tokenizer, label2id_map, max_seq_len=512, max_query_length=20, max_doc_length=512, max_span_num=1
|
||||
):
|
||||
super(DocVQA, self).__init__()
|
||||
self.tokenizer = tokenizer
|
||||
self.label2id_map = label2id_map
|
||||
@@ -113,17 +94,16 @@ class DocVQA(Dataset):
|
||||
continue
|
||||
num_left_context = position - doc_span.start
|
||||
num_right_context = end - position
|
||||
score = min(num_left_context,
|
||||
num_right_context) + 0.01 * doc_span.length
|
||||
score = min(num_left_context, num_right_context) + 0.01 * doc_span.length
|
||||
if best_score is None or score > best_score:
|
||||
best_score = score
|
||||
best_span_index = span_index
|
||||
|
||||
return cur_span_index == best_span_index
|
||||
|
||||
def convert_examples_to_features(self, examples, tokenizer, label_map,
|
||||
max_seq_length, max_span_num,
|
||||
max_doc_length, max_query_length):
|
||||
def convert_examples_to_features(
|
||||
self, examples, tokenizer, label_map, max_seq_length, max_span_num, max_doc_length, max_query_length
|
||||
):
|
||||
|
||||
if "[CLS]" in self.tokenizer.get_vocab():
|
||||
start_token = "[CLS]"
|
||||
@@ -188,8 +168,7 @@ class DocVQA(Dataset):
|
||||
segment_ids.append(0)
|
||||
for i in range(doc_span.length):
|
||||
split_token_index = doc_span.start + i
|
||||
is_max_context = self.check_is_max_context(
|
||||
doc_spans, doc_span_index, split_token_index)
|
||||
is_max_context = self.check_is_max_context(doc_spans, doc_span_index, split_token_index)
|
||||
token_is_max_context[len(tokens)] = is_max_context
|
||||
tokens.append(all_doc_tokens[split_token_index])
|
||||
boxes_tokens.append(all_doc_boxes_tokens[split_token_index])
|
||||
@@ -292,12 +271,10 @@ class DocVQA(Dataset):
|
||||
question = sample["question"]
|
||||
doc_tokens = sample["document"]
|
||||
doc_boxes = sample["document_bbox"]
|
||||
labels = sample['labels'] if not is_test else []
|
||||
labels = sample["labels"] if not is_test else []
|
||||
|
||||
x_min, y_min = min(doc_boxes, key=lambda x: x[0])[0], min(
|
||||
doc_boxes, key=lambda x: x[2])[2]
|
||||
x_max, y_max = max(doc_boxes, key=lambda x: x[1])[1], max(
|
||||
doc_boxes, key=lambda x: x[3])[3]
|
||||
x_min, y_min = min(doc_boxes, key=lambda x: x[0])[0], min(doc_boxes, key=lambda x: x[2])[2]
|
||||
x_max, y_max = max(doc_boxes, key=lambda x: x[1])[1], max(doc_boxes, key=lambda x: x[3])[3]
|
||||
width = x_max - x_min
|
||||
height = y_max - y_min
|
||||
|
||||
@@ -308,12 +285,15 @@ class DocVQA(Dataset):
|
||||
scale_x = 1000 / max(width, height)
|
||||
scale_y = 1000 / max(width, height)
|
||||
|
||||
scaled_doc_boxes = [[
|
||||
round((b[0] - x_min) * scale_x),
|
||||
round((b[2] - y_min) * scale_y),
|
||||
round((b[1] - x_min) * scale_x),
|
||||
round((b[3] - y_min) * scale_y)
|
||||
] for b in doc_boxes]
|
||||
scaled_doc_boxes = [
|
||||
[
|
||||
round((b[0] - x_min) * scale_x),
|
||||
round((b[2] - y_min) * scale_y),
|
||||
round((b[1] - x_min) * scale_x),
|
||||
round((b[3] - y_min) * scale_y),
|
||||
]
|
||||
for b in doc_boxes
|
||||
]
|
||||
|
||||
for box, oribox in zip(scaled_doc_boxes, doc_boxes):
|
||||
if box[0] < 0:
|
||||
@@ -326,10 +306,9 @@ class DocVQA(Dataset):
|
||||
if pos > 1000:
|
||||
print(width, height, box, oribox)
|
||||
|
||||
example = DocVQAExample(question=question,
|
||||
doc_tokens=doc_tokens,
|
||||
doc_boxes=scaled_doc_boxes,
|
||||
labels=labels)
|
||||
example = DocVQAExample(
|
||||
question=question, doc_tokens=doc_tokens, doc_boxes=scaled_doc_boxes, labels=labels
|
||||
)
|
||||
examples.append(example)
|
||||
return examples
|
||||
|
||||
@@ -339,7 +318,7 @@ class DocVQA(Dataset):
|
||||
dataset = self.args.train_file
|
||||
elif self.args.do_test:
|
||||
dataset = self.args.test_file
|
||||
with open(dataset, 'r', encoding='utf8') as f:
|
||||
with open(dataset, "r", encoding="utf8") as f:
|
||||
for index, line in enumerate(f):
|
||||
data.append(json.loads(line.strip()))
|
||||
|
||||
@@ -353,30 +332,32 @@ class DocVQA(Dataset):
|
||||
max_seq_length=self.max_seq_len,
|
||||
max_doc_length=self.max_doc_length,
|
||||
max_span_num=self.max_span_num,
|
||||
max_query_length=self.max_query_length)
|
||||
max_query_length=self.max_query_length,
|
||||
)
|
||||
|
||||
all_input_ids = paddle.to_tensor([f.input_ids for f in features],
|
||||
dtype="int64")
|
||||
all_input_mask = paddle.to_tensor([f.input_mask for f in features],
|
||||
dtype="int64")
|
||||
all_segment_ids = paddle.to_tensor([f.segment_ids for f in features],
|
||||
dtype="int64")
|
||||
all_bboxes = paddle.to_tensor([f.boxes for f in features],
|
||||
dtype="int64")
|
||||
all_labels = paddle.to_tensor([f.label for f in features],
|
||||
dtype="int64")
|
||||
all_input_ids = paddle.to_tensor([f.input_ids for f in features], dtype="int64")
|
||||
all_input_mask = paddle.to_tensor([f.input_mask for f in features], dtype="int64")
|
||||
all_segment_ids = paddle.to_tensor([f.segment_ids for f in features], dtype="int64")
|
||||
all_bboxes = paddle.to_tensor([f.boxes for f in features], dtype="int64")
|
||||
all_labels = paddle.to_tensor([f.label for f in features], dtype="int64")
|
||||
self.sample_list = [
|
||||
np.array(all_input_ids),
|
||||
np.array(all_input_mask),
|
||||
np.array(all_segment_ids),
|
||||
np.array(all_bboxes),
|
||||
np.array(all_labels)
|
||||
np.array(all_labels),
|
||||
]
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.sample_list[0][idx], self.sample_list[1][
|
||||
idx], self.sample_list[2][idx], self.sample_list[3][
|
||||
idx], self.sample_list[4][idx]
|
||||
return (
|
||||
self.sample_list[0][idx],
|
||||
self.sample_list[1][idx],
|
||||
self.sample_list[2][idx],
|
||||
self.sample_list[3][idx],
|
||||
self.sample_list[4][idx],
|
||||
)
|
||||
|
||||
def __len__(self, ):
|
||||
def __len__(
|
||||
self,
|
||||
):
|
||||
return self.sample_list[0].shape[0]
|
||||
|
||||
@@ -21,8 +21,7 @@ from paddlenlp.transformers import LayoutXLMPretrainedModel
|
||||
|
||||
|
||||
class Crf_decoding(paddle.fluid.dygraph.Layer):
|
||||
|
||||
def __init__(self, param_attr, size=None, is_test=True, dtype='float32'):
|
||||
def __init__(self, param_attr, size=None, is_test=True, dtype="float32"):
|
||||
super(Crf_decoding, self).__init__()
|
||||
|
||||
self._dtype = dtype
|
||||
@@ -30,9 +29,8 @@ class Crf_decoding(paddle.fluid.dygraph.Layer):
|
||||
self._is_test = is_test
|
||||
self._param_attr = param_attr
|
||||
self._transition = self.create_parameter(
|
||||
attr=self._param_attr,
|
||||
shape=[self._size + 2, self._size],
|
||||
dtype=self._dtype)
|
||||
attr=self._param_attr, shape=[self._size + 2, self._size], dtype=self._dtype
|
||||
)
|
||||
|
||||
@property
|
||||
def weight(self):
|
||||
@@ -44,30 +42,23 @@ class Crf_decoding(paddle.fluid.dygraph.Layer):
|
||||
|
||||
def forward(self, input, label=None, length=None):
|
||||
|
||||
viterbi_path = self._helper.create_variable_for_type_inference(
|
||||
dtype=self._dtype)
|
||||
this_inputs = {
|
||||
"Emission": [input],
|
||||
"Transition": self._transition,
|
||||
"Label": label
|
||||
}
|
||||
viterbi_path = self._helper.create_variable_for_type_inference(dtype=self._dtype)
|
||||
this_inputs = {"Emission": [input], "Transition": self._transition, "Label": label}
|
||||
if length is not None:
|
||||
this_inputs['Length'] = [length]
|
||||
self._helper.append_op(type='crf_decoding',
|
||||
inputs=this_inputs,
|
||||
outputs={"ViterbiPath": [viterbi_path]},
|
||||
attrs={
|
||||
"is_test": self._is_test,
|
||||
})
|
||||
this_inputs["Length"] = [length]
|
||||
self._helper.append_op(
|
||||
type="crf_decoding",
|
||||
inputs=this_inputs,
|
||||
outputs={"ViterbiPath": [viterbi_path]},
|
||||
attrs={
|
||||
"is_test": self._is_test,
|
||||
},
|
||||
)
|
||||
return viterbi_path
|
||||
|
||||
|
||||
class Chunk_eval(paddle.fluid.dygraph.Layer):
|
||||
|
||||
def __init__(self,
|
||||
num_chunk_types,
|
||||
chunk_scheme,
|
||||
excluded_chunk_types=None):
|
||||
def __init__(self, num_chunk_types, chunk_scheme, excluded_chunk_types=None):
|
||||
super(Chunk_eval, self).__init__()
|
||||
self.num_chunk_types = num_chunk_types
|
||||
self.chunk_scheme = chunk_scheme
|
||||
@@ -75,48 +66,39 @@ class Chunk_eval(paddle.fluid.dygraph.Layer):
|
||||
|
||||
def forward(self, input, label, seq_length=None):
|
||||
|
||||
precision = self._helper.create_variable_for_type_inference(
|
||||
dtype="float32")
|
||||
recall = self._helper.create_variable_for_type_inference(
|
||||
dtype="float32")
|
||||
f1_score = self._helper.create_variable_for_type_inference(
|
||||
dtype="float32")
|
||||
num_infer_chunks = self._helper.create_variable_for_type_inference(
|
||||
dtype="int64")
|
||||
num_label_chunks = self._helper.create_variable_for_type_inference(
|
||||
dtype="int64")
|
||||
num_correct_chunks = self._helper.create_variable_for_type_inference(
|
||||
dtype="int64")
|
||||
precision = self._helper.create_variable_for_type_inference(dtype="float32")
|
||||
recall = self._helper.create_variable_for_type_inference(dtype="float32")
|
||||
f1_score = self._helper.create_variable_for_type_inference(dtype="float32")
|
||||
num_infer_chunks = self._helper.create_variable_for_type_inference(dtype="int64")
|
||||
num_label_chunks = self._helper.create_variable_for_type_inference(dtype="int64")
|
||||
num_correct_chunks = self._helper.create_variable_for_type_inference(dtype="int64")
|
||||
|
||||
this_input = {"Inference": [input], "Label": [label]}
|
||||
if seq_length is not None:
|
||||
this_input["SeqLength"] = [seq_length]
|
||||
|
||||
self._helper.append_op(type='chunk_eval',
|
||||
inputs=this_input,
|
||||
outputs={
|
||||
"Precision": [precision],
|
||||
"Recall": [recall],
|
||||
"F1-Score": [f1_score],
|
||||
"NumInferChunks": [num_infer_chunks],
|
||||
"NumLabelChunks": [num_label_chunks],
|
||||
"NumCorrectChunks": [num_correct_chunks]
|
||||
},
|
||||
attrs={
|
||||
"num_chunk_types":
|
||||
self.num_chunk_types,
|
||||
"chunk_scheme":
|
||||
self.chunk_scheme,
|
||||
"excluded_chunk_types":
|
||||
self.excluded_chunk_types or []
|
||||
})
|
||||
return (precision, recall, f1_score, num_infer_chunks, num_label_chunks,
|
||||
num_correct_chunks)
|
||||
self._helper.append_op(
|
||||
type="chunk_eval",
|
||||
inputs=this_input,
|
||||
outputs={
|
||||
"Precision": [precision],
|
||||
"Recall": [recall],
|
||||
"F1-Score": [f1_score],
|
||||
"NumInferChunks": [num_infer_chunks],
|
||||
"NumLabelChunks": [num_label_chunks],
|
||||
"NumCorrectChunks": [num_correct_chunks],
|
||||
},
|
||||
attrs={
|
||||
"num_chunk_types": self.num_chunk_types,
|
||||
"chunk_scheme": self.chunk_scheme,
|
||||
"excluded_chunk_types": self.excluded_chunk_types or [],
|
||||
},
|
||||
)
|
||||
return (precision, recall, f1_score, num_infer_chunks, num_label_chunks, num_correct_chunks)
|
||||
|
||||
|
||||
class Linear_chain_crf(paddle.fluid.dygraph.Layer):
|
||||
|
||||
def __init__(self, param_attr, size=None, is_test=False, dtype='float32'):
|
||||
def __init__(self, param_attr, size=None, is_test=False, dtype="float32"):
|
||||
super(Linear_chain_crf, self).__init__()
|
||||
|
||||
self._param_attr = param_attr
|
||||
@@ -124,9 +106,8 @@ class Linear_chain_crf(paddle.fluid.dygraph.Layer):
|
||||
self._size = size
|
||||
self._is_test = is_test
|
||||
self._transition = self.create_parameter(
|
||||
attr=self._param_attr,
|
||||
shape=[self._size + 2, self._size],
|
||||
dtype=self._dtype)
|
||||
attr=self._param_attr, shape=[self._size + 2, self._size], dtype=self._dtype
|
||||
)
|
||||
|
||||
@property
|
||||
def weight(self):
|
||||
@@ -138,37 +119,30 @@ class Linear_chain_crf(paddle.fluid.dygraph.Layer):
|
||||
|
||||
def forward(self, input, label, length=None):
|
||||
|
||||
alpha = self._helper.create_variable_for_type_inference(
|
||||
dtype=self._dtype)
|
||||
emission_exps = self._helper.create_variable_for_type_inference(
|
||||
dtype=self._dtype)
|
||||
transition_exps = self._helper.create_variable_for_type_inference(
|
||||
dtype=self._dtype)
|
||||
log_likelihood = self._helper.create_variable_for_type_inference(
|
||||
dtype=self._dtype)
|
||||
this_inputs = {
|
||||
"Emission": [input],
|
||||
"Transition": self._transition,
|
||||
"Label": [label]
|
||||
}
|
||||
alpha = self._helper.create_variable_for_type_inference(dtype=self._dtype)
|
||||
emission_exps = self._helper.create_variable_for_type_inference(dtype=self._dtype)
|
||||
transition_exps = self._helper.create_variable_for_type_inference(dtype=self._dtype)
|
||||
log_likelihood = self._helper.create_variable_for_type_inference(dtype=self._dtype)
|
||||
this_inputs = {"Emission": [input], "Transition": self._transition, "Label": [label]}
|
||||
if length is not None:
|
||||
this_inputs['Length'] = [length]
|
||||
self._helper.append_op(type='linear_chain_crf',
|
||||
inputs=this_inputs,
|
||||
outputs={
|
||||
"Alpha": [alpha],
|
||||
"EmissionExps": [emission_exps],
|
||||
"TransitionExps": transition_exps,
|
||||
"LogLikelihood": log_likelihood
|
||||
},
|
||||
attrs={
|
||||
"is_test": self._is_test,
|
||||
})
|
||||
this_inputs["Length"] = [length]
|
||||
self._helper.append_op(
|
||||
type="linear_chain_crf",
|
||||
inputs=this_inputs,
|
||||
outputs={
|
||||
"Alpha": [alpha],
|
||||
"EmissionExps": [emission_exps],
|
||||
"TransitionExps": transition_exps,
|
||||
"LogLikelihood": log_likelihood,
|
||||
},
|
||||
attrs={
|
||||
"is_test": self._is_test,
|
||||
},
|
||||
)
|
||||
return log_likelihood
|
||||
|
||||
|
||||
class LayoutXLMForTokenClassification_with_CRF(LayoutXLMPretrainedModel):
|
||||
|
||||
def __init__(self, layoutxlm, num_classes, dropout=None):
|
||||
super(LayoutXLMForTokenClassification_with_CRF, self).__init__()
|
||||
self.num_classes = num_classes
|
||||
@@ -176,40 +150,36 @@ class LayoutXLMForTokenClassification_with_CRF(LayoutXLMPretrainedModel):
|
||||
self.layoutxlm = LayoutXLMModel(**layoutxlm)
|
||||
else:
|
||||
self.layoutxlm = layoutxlm
|
||||
self.dropout = nn.Dropout(dropout if dropout is not None else self.
|
||||
layoutxlm.config["hidden_dropout_prob"])
|
||||
self.emission_classifier = nn.Linear(
|
||||
self.layoutxlm.config["hidden_size"], self.num_classes)
|
||||
self.dropout = nn.Dropout(dropout if dropout is not None else self.layoutxlm.config["hidden_dropout_prob"])
|
||||
self.emission_classifier = nn.Linear(self.layoutxlm.config["hidden_size"], self.num_classes)
|
||||
self.emission_classifier.apply(self.init_weights)
|
||||
self.linear_chain_crf = Linear_chain_crf(
|
||||
size=self.num_classes,
|
||||
param_attr=paddle.fluid.ParamAttr(name='liner_chain_crfw'))
|
||||
self.crf_decoding = Crf_decoding(
|
||||
param_attr=paddle.fluid.ParamAttr(name='crfw_decode'),
|
||||
size=self.num_classes)
|
||||
size=self.num_classes, param_attr=paddle.fluid.ParamAttr(name="liner_chain_crfw")
|
||||
)
|
||||
self.crf_decoding = Crf_decoding(param_attr=paddle.fluid.ParamAttr(name="crfw_decode"), size=self.num_classes)
|
||||
self.crf_decoding.weight = self.linear_chain_crf.weight
|
||||
self.crfw = fluid.layers.create_parameter(
|
||||
shape=[self.num_classes + 2, self.num_classes],
|
||||
dtype='float32',
|
||||
name='crfw')
|
||||
shape=[self.num_classes + 2, self.num_classes], dtype="float32", name="crfw"
|
||||
)
|
||||
self.mask_crfw = fluid.layers.create_parameter(
|
||||
shape=[self.num_classes + 2, self.num_classes],
|
||||
dtype='float32',
|
||||
name='mask_matrix')
|
||||
shape=[self.num_classes + 2, self.num_classes], dtype="float32", name="mask_matrix"
|
||||
)
|
||||
|
||||
def get_input_embeddings(self):
|
||||
return self.layoutxlm.embeddings.word_embeddings
|
||||
|
||||
def forward(self,
|
||||
input_ids=None,
|
||||
bbox=None,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
labels=None,
|
||||
image=None,
|
||||
position_ids=None,
|
||||
head_mask=None,
|
||||
is_train=False):
|
||||
def forward(
|
||||
self,
|
||||
input_ids=None,
|
||||
bbox=None,
|
||||
attention_mask=None,
|
||||
token_type_ids=None,
|
||||
labels=None,
|
||||
image=None,
|
||||
position_ids=None,
|
||||
head_mask=None,
|
||||
is_train=False,
|
||||
):
|
||||
|
||||
input_ids = input_ids.squeeze(axis=1)
|
||||
bbox = bbox.squeeze(axis=1)
|
||||
@@ -226,16 +196,13 @@ class LayoutXLMForTokenClassification_with_CRF(LayoutXLMPretrainedModel):
|
||||
)
|
||||
seq_length = input_ids.shape[1]
|
||||
# sequence out and image out
|
||||
sequence_logits, image_output = outputs[0][:, :seq_length], outputs[
|
||||
0][:, seq_length:]
|
||||
sequence_logits, image_output = outputs[0][:, :seq_length], outputs[0][:, seq_length:]
|
||||
emission = self.emission_classifier(sequence_logits)
|
||||
length = paddle.sum(attention_mask, axis=1)
|
||||
labels = labels.reshape([-1, seq_length, 1])
|
||||
|
||||
# standard crf loss
|
||||
crf_cost = self.linear_chain_crf(input=emission,
|
||||
label=labels,
|
||||
length=length)
|
||||
crf_cost = self.linear_chain_crf(input=emission, label=labels, length=length)
|
||||
crf_decode = self.crf_decoding(input=emission, length=length)
|
||||
if is_train:
|
||||
return [crf_cost]
|
||||
|
||||
@@ -81,12 +81,10 @@ def get_label_maps():
|
||||
def main(args):
|
||||
os.makedirs(args.output_dir, exist_ok=True)
|
||||
logging.basicConfig(
|
||||
filename=os.path.join(args.output_dir, "train.log")
|
||||
if paddle.distributed.get_rank() == 0 else None,
|
||||
filename=os.path.join(args.output_dir, "train.log") if paddle.distributed.get_rank() == 0 else None,
|
||||
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
||||
datefmt="%m/%d/%Y %H:%M:%S",
|
||||
level=logging.INFO
|
||||
if paddle.distributed.get_rank() == 0 else logging.WARN,
|
||||
level=logging.INFO if paddle.distributed.get_rank() == 0 else logging.WARN,
|
||||
)
|
||||
|
||||
ch = logging.StreamHandler()
|
||||
@@ -103,74 +101,62 @@ def main(args):
|
||||
tokenizer = LayoutXLMTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
if args.do_test:
|
||||
model = LayoutXLMForTokenClassification_with_CRF.from_pretrained(
|
||||
args.init_checkpoint)
|
||||
evaluate(args,
|
||||
model,
|
||||
tokenizer,
|
||||
label2id_map,
|
||||
id2label_map,
|
||||
pad_token_label_id,
|
||||
global_step=0)
|
||||
model = LayoutXLMForTokenClassification_with_CRF.from_pretrained(args.init_checkpoint)
|
||||
evaluate(args, model, tokenizer, label2id_map, id2label_map, pad_token_label_id, global_step=0)
|
||||
exit(0)
|
||||
|
||||
if args.init_checkpoint:
|
||||
logger.info('Init checkpoint from {}'.format(args.init_checkpoint))
|
||||
model = LayoutXLMForTokenClassification_with_CRF.from_pretrained(
|
||||
args.init_checkpoint)
|
||||
logger.info("Init checkpoint from {}".format(args.init_checkpoint))
|
||||
model = LayoutXLMForTokenClassification_with_CRF.from_pretrained(args.init_checkpoint)
|
||||
else:
|
||||
base_model = LayoutXLMModel.from_pretrained(args.model_name_or_path)
|
||||
model = LayoutXLMForTokenClassification_with_CRF(
|
||||
base_model, num_classes=len(label2id_map), dropout=None)
|
||||
model = LayoutXLMForTokenClassification_with_CRF(base_model, num_classes=len(label2id_map), dropout=None)
|
||||
|
||||
# dist mode
|
||||
if paddle.distributed.get_world_size() > 1:
|
||||
model = paddle.DataParallel(model)
|
||||
|
||||
train_dataset = DocVQA(args,
|
||||
tokenizer,
|
||||
label2id_map,
|
||||
max_seq_len=args.max_seq_len,
|
||||
max_query_length=args.max_query_length,
|
||||
max_doc_length=args.max_doc_length,
|
||||
max_span_num=args.max_span_num)
|
||||
train_dataset = DocVQA(
|
||||
args,
|
||||
tokenizer,
|
||||
label2id_map,
|
||||
max_seq_len=args.max_seq_len,
|
||||
max_query_length=args.max_query_length,
|
||||
max_doc_length=args.max_doc_length,
|
||||
max_span_num=args.max_span_num,
|
||||
)
|
||||
|
||||
train_sampler = paddle.io.DistributedBatchSampler(
|
||||
train_dataset, batch_size=args.per_gpu_train_batch_size, shuffle=False)
|
||||
train_dataset, batch_size=args.per_gpu_train_batch_size, shuffle=False
|
||||
)
|
||||
|
||||
args.train_batch_size = args.per_gpu_train_batch_size * max(
|
||||
1, paddle.distributed.get_world_size())
|
||||
args.train_batch_size = args.per_gpu_train_batch_size * max(1, paddle.distributed.get_world_size())
|
||||
|
||||
train_dataloader = paddle.io.DataLoader(train_dataset,
|
||||
batch_sampler=train_sampler,
|
||||
num_workers=0,
|
||||
use_shared_memory=True,
|
||||
collate_fn=None)
|
||||
train_dataloader = paddle.io.DataLoader(
|
||||
train_dataset, batch_sampler=train_sampler, num_workers=0, use_shared_memory=True, collate_fn=None
|
||||
)
|
||||
|
||||
t_total = len(train_dataloader) * args.num_train_epochs
|
||||
# build linear decay with warmup lr sch
|
||||
lr_scheduler = paddle.optimizer.lr.PolynomialDecay(
|
||||
learning_rate=args.learning_rate,
|
||||
decay_steps=t_total,
|
||||
end_lr=0.0,
|
||||
power=1.0)
|
||||
learning_rate=args.learning_rate, decay_steps=t_total, end_lr=0.0, power=1.0
|
||||
)
|
||||
if args.warmup_steps > 0:
|
||||
lr_scheduler = paddle.optimizer.lr.LinearWarmup(
|
||||
lr_scheduler,
|
||||
args.warmup_steps,
|
||||
start_lr=0,
|
||||
end_lr=args.learning_rate)
|
||||
lr_scheduler, args.warmup_steps, start_lr=0, end_lr=args.learning_rate
|
||||
)
|
||||
|
||||
optimizer = paddle.optimizer.AdamW(learning_rate=lr_scheduler,
|
||||
parameters=model.parameters(),
|
||||
epsilon=args.adam_epsilon,
|
||||
weight_decay=args.weight_decay)
|
||||
optimizer = paddle.optimizer.AdamW(
|
||||
learning_rate=lr_scheduler,
|
||||
parameters=model.parameters(),
|
||||
epsilon=args.adam_epsilon,
|
||||
weight_decay=args.weight_decay,
|
||||
)
|
||||
|
||||
logger.info("***** Running training *****")
|
||||
logger.info(" Num examples = %d", len(train_dataset))
|
||||
logger.info(" Num Epochs = %d", args.num_train_epochs)
|
||||
logger.info(" Instantaneous batch size per GPU = %d",
|
||||
args.per_gpu_train_batch_size)
|
||||
logger.info(" Instantaneous batch size per GPU = %d", args.per_gpu_train_batch_size)
|
||||
logger.info(
|
||||
" Total train batch size (w. parallel, distributed) = %d",
|
||||
args.train_batch_size * paddle.distributed.get_world_size(),
|
||||
@@ -182,27 +168,34 @@ def main(args):
|
||||
set_seed(args)
|
||||
best_metrics = None
|
||||
for epoch_id in range(args.num_train_epochs):
|
||||
print('epoch id:{}'.format(epoch_id))
|
||||
print("epoch id:{}".format(epoch_id))
|
||||
for step, batch in enumerate(train_dataloader):
|
||||
model.train()
|
||||
input_ids, input_mask, segment_ids, bboxes, labels = batch
|
||||
if input_ids.shape[0] != args.per_gpu_train_batch_size:
|
||||
continue
|
||||
outputs = model(input_ids=input_ids,
|
||||
bbox=bboxes,
|
||||
attention_mask=input_mask,
|
||||
token_type_ids=segment_ids,
|
||||
labels=labels,
|
||||
is_train=True)
|
||||
outputs = model(
|
||||
input_ids=input_ids,
|
||||
bbox=bboxes,
|
||||
attention_mask=input_mask,
|
||||
token_type_ids=segment_ids,
|
||||
labels=labels,
|
||||
is_train=True,
|
||||
)
|
||||
# model outputs are always tuple in paddlenlp (see doc)
|
||||
loss = outputs[0]
|
||||
loss = loss.mean()
|
||||
if global_step % 50 == 0:
|
||||
logger.info(
|
||||
"[epoch {}/{}][iter: {}/{}] lr: {:.5f}, train loss: {:.5f}, "
|
||||
.format(epoch_id, args.num_train_epochs, step,
|
||||
len(train_dataloader), lr_scheduler.get_lr(),
|
||||
loss.numpy()[0]))
|
||||
"[epoch {}/{}][iter: {}/{}] lr: {:.5f}, train loss: {:.5f}, ".format(
|
||||
epoch_id,
|
||||
args.num_train_epochs,
|
||||
step,
|
||||
len(train_dataloader),
|
||||
lr_scheduler.get_lr(),
|
||||
loss.numpy()[0],
|
||||
)
|
||||
)
|
||||
|
||||
loss.backward()
|
||||
tr_loss += loss.item()
|
||||
@@ -211,17 +204,14 @@ def main(args):
|
||||
optimizer.clear_grad()
|
||||
global_step += 1
|
||||
|
||||
if paddle.distributed.get_rank(
|
||||
) == 0 and args.save_steps > 0 and global_step % args.save_steps == 0:
|
||||
if paddle.distributed.get_rank() == 0 and args.save_steps > 0 and global_step % args.save_steps == 0:
|
||||
# Save model checkpoint
|
||||
output_dir = os.path.join(args.output_dir,
|
||||
"checkpoint-{}".format(global_step))
|
||||
output_dir = os.path.join(args.output_dir, "checkpoint-{}".format(global_step))
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
if paddle.distributed.get_rank() == 0:
|
||||
model.save_pretrained(output_dir)
|
||||
tokenizer.save_pretrained(output_dir)
|
||||
paddle.save(args,
|
||||
os.path.join(output_dir, "training_args.bin"))
|
||||
paddle.save(args, os.path.join(output_dir, "training_args.bin"))
|
||||
logger.info("Saving model checkpoint to %s", output_dir)
|
||||
|
||||
|
||||
@@ -242,14 +232,16 @@ def _tokenize_chinese_chars(text):
|
||||
# as is Japanese Hiragana and Katakana. Those alphabets are used to write
|
||||
# space-separated words, so they are not treated specially and handled
|
||||
# like the all of the other languages.
|
||||
if ((cp >= 0x4E00 and cp <= 0x9FFF) or #
|
||||
(cp >= 0x3400 and cp <= 0x4DBF) or #
|
||||
(cp >= 0x20000 and cp <= 0x2A6DF) or #
|
||||
(cp >= 0x2A700 and cp <= 0x2B73F) or #
|
||||
(cp >= 0x2B740 and cp <= 0x2B81F) or #
|
||||
(cp >= 0x2B820 and cp <= 0x2CEAF) or
|
||||
(cp >= 0xF900 and cp <= 0xFAFF) or #
|
||||
(cp >= 0x2F800 and cp <= 0x2FA1F)): #
|
||||
if (
|
||||
(cp >= 0x4E00 and cp <= 0x9FFF)
|
||||
or (cp >= 0x3400 and cp <= 0x4DBF) #
|
||||
or (cp >= 0x20000 and cp <= 0x2A6DF) #
|
||||
or (cp >= 0x2A700 and cp <= 0x2B73F) #
|
||||
or (cp >= 0x2B740 and cp <= 0x2B81F) #
|
||||
or (cp >= 0x2B820 and cp <= 0x2CEAF) #
|
||||
or (cp >= 0xF900 and cp <= 0xFAFF)
|
||||
or (cp >= 0x2F800 and cp <= 0x2FA1F) #
|
||||
): #
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -290,9 +282,35 @@ def _normalize(in_str):
|
||||
"""
|
||||
in_str = in_str.lower()
|
||||
sp_char = [
|
||||
u':', u'_', u'`', u',', u'。', u':', u'?', u'!', u'(', u')', u'“', u'”',
|
||||
u';', u'’', u'《', u'》', u'……', u'·', u'、', u',', u'「', u'」', u'(', u')',
|
||||
u'-', u'~', u'『', u'』', '|'
|
||||
":",
|
||||
"_",
|
||||
"`",
|
||||
",",
|
||||
"。",
|
||||
":",
|
||||
"?",
|
||||
"!",
|
||||
"(",
|
||||
")",
|
||||
"“",
|
||||
"”",
|
||||
";",
|
||||
"’",
|
||||
"《",
|
||||
"》",
|
||||
"……",
|
||||
"·",
|
||||
"、",
|
||||
",",
|
||||
"「",
|
||||
"」",
|
||||
"(",
|
||||
")",
|
||||
"-",
|
||||
"~",
|
||||
"『",
|
||||
"』",
|
||||
"|",
|
||||
]
|
||||
out_segs = []
|
||||
for char in in_str:
|
||||
@@ -300,7 +318,7 @@ def _normalize(in_str):
|
||||
continue
|
||||
else:
|
||||
out_segs.append(char)
|
||||
return ''.join(out_segs)
|
||||
return "".join(out_segs)
|
||||
|
||||
|
||||
def calc_f1_score(answer, prediction):
|
||||
@@ -318,38 +336,35 @@ def decode(tokenizer, res):
|
||||
save_f1 = []
|
||||
for i in range(len(res)):
|
||||
input_ids, label_ids, predict_ids, bbox = res[i]
|
||||
remove_pos = len(' '.join(
|
||||
[str(x) for x in input_ids]).split('2 6 ')[0].strip(' ').split(
|
||||
' ')) + 2 # remove the question bbox and sep bbox
|
||||
remove_pos = (
|
||||
len(" ".join([str(x) for x in input_ids]).split("2 6 ")[0].strip(" ").split(" ")) + 2
|
||||
) # remove the question bbox and sep bbox
|
||||
start_pos = input_ids.index(sep_id)
|
||||
query_text = []
|
||||
for idx in range(1, start_pos):
|
||||
input_id = input_ids[idx]
|
||||
query_text.append(tokenizer._convert_id_to_token(int(input_id)))
|
||||
|
||||
#label texts and predict texts
|
||||
# label texts and predict texts
|
||||
text_label, text_predict = [], []
|
||||
label_bbox_index, predict_bbox_index = [], []
|
||||
for idx in range(start_pos + 1, len(input_ids)):
|
||||
input_id, label_id, predict_id = input_ids[idx], label_ids[
|
||||
idx], predict_ids[idx]
|
||||
input_id, label_id, predict_id = input_ids[idx], label_ids[idx], predict_ids[idx]
|
||||
|
||||
if label_id in [1, 2, 3]:
|
||||
text_label.append(tokenizer._convert_id_to_token(int(input_id)))
|
||||
label_bbox_index.append(idx - remove_pos + 1)
|
||||
if predict_id in [1, 2, 3]:
|
||||
text_predict.append(
|
||||
tokenizer._convert_id_to_token(int(input_id)))
|
||||
text_predict.append(tokenizer._convert_id_to_token(int(input_id)))
|
||||
predict_bbox_index.append(idx - remove_pos + 1)
|
||||
text_res.append([
|
||||
''.join(query_text), ''.join(text_label), ''.join(text_predict),
|
||||
label_bbox_index, predict_bbox_index
|
||||
])
|
||||
text_res.append(
|
||||
["".join(query_text), "".join(text_label), "".join(text_predict), label_bbox_index, predict_bbox_index]
|
||||
)
|
||||
|
||||
f1 = calc_f1_score(''.join(text_label), ''.join(text_predict))
|
||||
f1 = calc_f1_score("".join(text_label), "".join(text_predict))
|
||||
save_f1.append(f1)
|
||||
|
||||
if len(''.join(text_label)) > 10:
|
||||
if len("".join(text_label)) > 10:
|
||||
all_f1.append(f1)
|
||||
if len(all_f1) > 0:
|
||||
print("F1: ", sum(all_f1) / len(all_f1))
|
||||
@@ -358,31 +373,17 @@ def decode(tokenizer, res):
|
||||
return text_res
|
||||
|
||||
|
||||
def evaluate(args,
|
||||
model,
|
||||
tokenizer,
|
||||
label2id_map,
|
||||
id2label_map,
|
||||
pad_token_label_id,
|
||||
prefix="",
|
||||
global_step=0):
|
||||
def evaluate(args, model, tokenizer, label2id_map, id2label_map, pad_token_label_id, prefix="", global_step=0):
|
||||
|
||||
eval_dataset = DocVQA(args,
|
||||
tokenizer,
|
||||
label2id_map,
|
||||
max_seq_len=512,
|
||||
max_query_length=20,
|
||||
max_doc_length=512,
|
||||
max_span_num=1)
|
||||
eval_dataset = DocVQA(
|
||||
args, tokenizer, label2id_map, max_seq_len=512, max_query_length=20, max_doc_length=512, max_span_num=1
|
||||
)
|
||||
|
||||
args.eval_batch_size = args.per_gpu_eval_batch_size * max(
|
||||
1, paddle.distributed.get_world_size())
|
||||
args.eval_batch_size = args.per_gpu_eval_batch_size * max(1, paddle.distributed.get_world_size())
|
||||
|
||||
eval_dataloader = paddle.io.DataLoader(eval_dataset,
|
||||
batch_size=args.eval_batch_size,
|
||||
num_workers=0,
|
||||
use_shared_memory=True,
|
||||
collate_fn=None)
|
||||
eval_dataloader = paddle.io.DataLoader(
|
||||
eval_dataset, batch_size=args.eval_batch_size, num_workers=0, use_shared_memory=True, collate_fn=None
|
||||
)
|
||||
|
||||
# Eval!
|
||||
logger.info("***** Running evaluation %s *****", prefix)
|
||||
@@ -396,66 +397,65 @@ def evaluate(args,
|
||||
|
||||
if input_ids.shape[0] != args.eval_batch_size:
|
||||
continue
|
||||
outputs = model(input_ids=input_ids,
|
||||
bbox=bboxes,
|
||||
attention_mask=input_mask,
|
||||
token_type_ids=segment_ids,
|
||||
labels=labels,
|
||||
is_train=False)
|
||||
outputs = model(
|
||||
input_ids=input_ids,
|
||||
bbox=bboxes,
|
||||
attention_mask=input_mask,
|
||||
token_type_ids=segment_ids,
|
||||
labels=labels,
|
||||
is_train=False,
|
||||
)
|
||||
labels = labels.numpy()
|
||||
crf_decode = outputs[1].numpy()
|
||||
bboxes = bboxes.squeeze().numpy()
|
||||
input_ids = input_ids.squeeze(axis=1).numpy()
|
||||
|
||||
for index in range(input_ids.shape[0]):
|
||||
res.append([
|
||||
list(input_ids[index]),
|
||||
list(labels[index]),
|
||||
list(crf_decode[index]), bboxes[index]
|
||||
])
|
||||
res.append([list(input_ids[index]), list(labels[index]), list(crf_decode[index]), bboxes[index]])
|
||||
|
||||
origin_inputs = []
|
||||
with open(args.test_file, 'r', encoding='utf8') as f:
|
||||
with open(args.test_file, "r", encoding="utf8") as f:
|
||||
for line in f:
|
||||
line = json.loads(line.strip())
|
||||
origin_inputs.append({
|
||||
'img_name': line['img_name'],
|
||||
'question': line['question'],
|
||||
'bboxes': line['document_bbox'],
|
||||
'img_id': line['img_id']
|
||||
})
|
||||
origin_inputs.append(
|
||||
{
|
||||
"img_name": line["img_name"],
|
||||
"question": line["question"],
|
||||
"bboxes": line["document_bbox"],
|
||||
"img_id": line["img_id"],
|
||||
}
|
||||
)
|
||||
|
||||
text_res = decode(tokenizer, res)
|
||||
|
||||
with open(args.save_path, 'w', encoding='utf8') as f:
|
||||
for line_res, line_text, line_label in zip(res, text_res,
|
||||
origin_inputs):
|
||||
with open(args.save_path, "w", encoding="utf8") as f:
|
||||
for line_res, line_text, line_label in zip(res, text_res, origin_inputs):
|
||||
line_json = {}
|
||||
line_json['img_name'] = line_label['img_name']
|
||||
line_json['img_id'] = line_label['img_id']
|
||||
line_json['question'] = line_label['question']
|
||||
line_json['label_answer'] = line_text[1]
|
||||
line_json['predict_answer'] = line_text[2]
|
||||
line_json["img_name"] = line_label["img_name"]
|
||||
line_json["img_id"] = line_label["img_id"]
|
||||
line_json["question"] = line_label["question"]
|
||||
line_json["label_answer"] = line_text[1]
|
||||
line_json["predict_answer"] = line_text[2]
|
||||
all_boxes = line_res[3]
|
||||
label_bbox_index, predict_bbox_index = line_text[3], line_text[4]
|
||||
label_bboxes, predict_bboxes = [], []
|
||||
for i in range(len(line_label['bboxes'])):
|
||||
for i in range(len(line_label["bboxes"])):
|
||||
if i in label_bbox_index:
|
||||
label_bboxes.append(line_label['bboxes'][i])
|
||||
label_bboxes.append(line_label["bboxes"][i])
|
||||
if i in predict_bbox_index:
|
||||
predict_bboxes.append(line_label['bboxes'][i])
|
||||
line_json['label_bboxes'] = label_bboxes
|
||||
line_json['predict_bboxes'] = predict_bboxes
|
||||
predict_bboxes.append(line_label["bboxes"][i])
|
||||
line_json["label_bboxes"] = label_bboxes
|
||||
line_json["predict_bboxes"] = predict_bboxes
|
||||
json.dump(line_json, f, ensure_ascii=False)
|
||||
f.write('\n')
|
||||
f.write("\n")
|
||||
|
||||
|
||||
def print_arguments(args):
|
||||
"""print arguments"""
|
||||
print('----------- Configuration Arguments -----------')
|
||||
print("----------- Configuration Arguments -----------")
|
||||
for arg, value in sorted(vars(args).items()):
|
||||
print('%s: %s' % (arg, value))
|
||||
print('------------------------------------------------')
|
||||
print("%s: %s" % (arg, value))
|
||||
print("------------------------------------------------")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -30,12 +30,12 @@ def _highlight_bbox(img, bbox):
|
||||
w = bbox[1] - x
|
||||
y = bbox[2]
|
||||
h = bbox[3] - y
|
||||
sub_img = img[y:y + h, x:x + w]
|
||||
sub_img = img[y : y + h, x : x + w]
|
||||
colored_rect = np.zeros(sub_img.shape, dtype=np.uint8)
|
||||
colored_rect[:, :, 2] = 255
|
||||
colored_rect[:, :, 1] = 255
|
||||
res = cv2.addWeighted(sub_img, 0.5, colored_rect, 0.5, 1.0)
|
||||
img[y:y + h, x:x + w] = res
|
||||
img[y : y + h, x : x + w] = res
|
||||
|
||||
|
||||
def highlight_ans(source_img_path, output_img_path, ans_bbox):
|
||||
@@ -54,14 +54,14 @@ def highlight_img(source_img_path, output_img_path):
|
||||
cv2.imwrite(output_img_path, image)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
res_path = "./data/decode_res.json"
|
||||
result = {}
|
||||
with open(res_path, "r", encoding="utf-8") as f:
|
||||
line = f.readline()
|
||||
result = json.loads(line.strip())
|
||||
|
||||
img_path = '../OCR_process/demo_pics/demo_{}.png'.format(result["img_id"])
|
||||
img_path = "../OCR_process/demo_pics/demo_{}.png".format(result["img_id"])
|
||||
img_save_path = "../answer.png"
|
||||
highlight_ans(img_path, img_save_path, result['predict_bboxes'])
|
||||
highlight_ans(img_path, img_save_path, result["predict_bboxes"])
|
||||
print("extraction result has been saved to answer.png")
|
||||
|
||||
@@ -33,7 +33,7 @@ def get_all_chars(tokenizer):
|
||||
tok_chr = [tc.replace("▁", "") for tc in tok_chr]
|
||||
while "" in tok_chr:
|
||||
tok_chr.remove("")
|
||||
tok_chr = ''.join(tok_chr)
|
||||
tok_chr = "".join(tok_chr)
|
||||
if len(tok_chr) != 1:
|
||||
all_chr.append(i)
|
||||
return all_chr
|
||||
@@ -53,8 +53,7 @@ def merge_bbox(tok_bboxes):
|
||||
height_m += y_max - y_min
|
||||
width_m += x_max - x_min
|
||||
height_m = height_m / len(tok_bboxes)
|
||||
if (height_g -
|
||||
height_m) < 0.5 * height_m and width_g - width_m < 0.1 * width_m:
|
||||
if (height_g - height_m) < 0.5 * height_m and width_g - width_m < 0.1 * width_m:
|
||||
return False, [min_gx, max_gx, min_gy, max_gy]
|
||||
else:
|
||||
return True, tok_bboxes[0]
|
||||
@@ -72,7 +71,7 @@ def xlm_parse(ocr_res, tokenizer):
|
||||
new_token_boxes.extend(item["token_box"])
|
||||
|
||||
# get layoutxlm tokenizer results and get the final results
|
||||
temp_span_text = ''.join(new_tokens)
|
||||
temp_span_text = "".join(new_tokens)
|
||||
temp_span_bbox = new_token_boxes
|
||||
span_text = ""
|
||||
span_bbox = []
|
||||
@@ -138,20 +137,15 @@ def xlm_parse(ocr_res, tokenizer):
|
||||
for j in range(i, len(span_text)):
|
||||
if span_text[j].lower() == span_tokens[tid + 1][0]:
|
||||
break
|
||||
if span_text[j].lower() == "," and span_tokens[
|
||||
tid + 1][0] == ",":
|
||||
if span_text[j].lower() == "," and span_tokens[tid + 1][0] == ",":
|
||||
break
|
||||
if span_text[j].lower() == ";" and span_tokens[
|
||||
tid + 1][0] == ";":
|
||||
if span_text[j].lower() == ";" and span_tokens[tid + 1][0] == ";":
|
||||
break
|
||||
if span_text[j].lower() == ")" and span_tokens[
|
||||
tid + 1][0] == ")":
|
||||
if span_text[j].lower() == ")" and span_tokens[tid + 1][0] == ")":
|
||||
break
|
||||
if span_text[j].lower() == "(" and span_tokens[
|
||||
tid + 1][0] == "(":
|
||||
if span_text[j].lower() == "(" and span_tokens[tid + 1][0] == "(":
|
||||
break
|
||||
if span_text[j].lower() == "¥" and span_tokens[
|
||||
tid + 1][0] == "¥":
|
||||
if span_text[j].lower() == "¥" and span_tokens[tid + 1][0] == "¥":
|
||||
break
|
||||
|
||||
tok_len = j - i
|
||||
@@ -159,7 +153,7 @@ def xlm_parse(ocr_res, tokenizer):
|
||||
else:
|
||||
if "<EFBFBD>" == span_text[i]:
|
||||
tok_len = len(tok) + 1
|
||||
elif tok == "......" and "…" in span_text[i:i + 6]:
|
||||
elif tok == "......" and "…" in span_text[i : i + 6]:
|
||||
tok_len = len(tok) - 2
|
||||
elif "ⅱ" in span_text[i + len(tok) - 1]:
|
||||
if tok == "i":
|
||||
@@ -172,21 +166,21 @@ def xlm_parse(ocr_res, tokenizer):
|
||||
tok_len = len(tok)
|
||||
|
||||
assert i + tok_len <= len(span_bbox)
|
||||
tok_bboxes = span_bbox[i:i + tok_len]
|
||||
tok_bboxes = span_bbox[i : i + tok_len]
|
||||
_, merged_bbox = merge_bbox(tok_bboxes)
|
||||
|
||||
doc_bboxes.append(merged_bbox)
|
||||
i = i + tok_len
|
||||
except:
|
||||
print('Error')
|
||||
span_tokens = ['▁'] * 512
|
||||
print("Error")
|
||||
span_tokens = ["▁"] * 512
|
||||
doc_bboxes = [[0, 0, 0, 0]] * 512
|
||||
|
||||
return span_tokens, doc_bboxes
|
||||
|
||||
|
||||
def tokenize_ocr_res(ocr_reses):
|
||||
'''
|
||||
"""
|
||||
input:
|
||||
ocr_res: the ocr result of the image
|
||||
return:
|
||||
@@ -198,7 +192,7 @@ def tokenize_ocr_res(ocr_reses):
|
||||
"token_box: bounding box of each chars in ocr_res
|
||||
}
|
||||
}
|
||||
'''
|
||||
"""
|
||||
new_reses = []
|
||||
for img_name, ocr_res in ocr_reses:
|
||||
new_res = []
|
||||
@@ -227,16 +221,16 @@ def tokenize_ocr_res(ocr_reses):
|
||||
tok_y_max = y_max
|
||||
|
||||
shift = tok_x_max
|
||||
new_token_boxes.append(
|
||||
[round(tok_x_min),
|
||||
round(tok_x_max), tok_y_min, tok_y_max])
|
||||
new_token_boxes.append([round(tok_x_min), round(tok_x_max), tok_y_min, tok_y_max])
|
||||
new_tokens.append(char)
|
||||
new_res.append({
|
||||
"text": para["text"],
|
||||
"bounding_box": para["bbox"],
|
||||
"tokens": new_tokens,
|
||||
"token_box": new_token_boxes
|
||||
})
|
||||
new_res.append(
|
||||
{
|
||||
"text": para["text"],
|
||||
"bounding_box": para["bbox"],
|
||||
"tokens": new_tokens,
|
||||
"token_box": new_token_boxes,
|
||||
}
|
||||
)
|
||||
new_reses.append((img_name, new_res))
|
||||
return new_reses
|
||||
|
||||
@@ -247,19 +241,15 @@ def process_input(ocr_reses, tokenizer, save_ocr_path):
|
||||
examples = []
|
||||
for img_name, ocr_res in ocr_reses:
|
||||
doc_tokens, doc_bboxes = xlm_parse(ocr_res, tokenizer)
|
||||
doc_tokens.insert(0, '▁')
|
||||
doc_tokens.insert(0, "▁")
|
||||
doc_bboxes.insert(0, doc_bboxes[0])
|
||||
example = {
|
||||
"img_name": img_name,
|
||||
"document": doc_tokens,
|
||||
"document_bbox": doc_bboxes
|
||||
}
|
||||
example = {"img_name": img_name, "document": doc_tokens, "document_bbox": doc_bboxes}
|
||||
examples.append(example)
|
||||
|
||||
with open(save_ocr_path, 'w', encoding='utf8') as f:
|
||||
with open(save_ocr_path, "w", encoding="utf8") as f:
|
||||
for example in examples:
|
||||
json.dump(example, f, ensure_ascii=False)
|
||||
f.write('\n')
|
||||
f.write("\n")
|
||||
|
||||
print(f"ocr parsing results has been save to: {save_ocr_path}")
|
||||
|
||||
@@ -267,8 +257,7 @@ def process_input(ocr_reses, tokenizer, save_ocr_path):
|
||||
def ocr_preprocess(img_dir):
|
||||
ocr = PaddleOCR(use_angle_cls=True, lang="ch", use_gpu=True)
|
||||
ocr_reses = []
|
||||
img_names = sorted(os.listdir(img_dir),
|
||||
key=lambda x: int(x.split("_")[1].split(".")[0]))
|
||||
img_names = sorted(os.listdir(img_dir), key=lambda x: int(x.split("_")[1].split(".")[0]))
|
||||
for img_name in img_names:
|
||||
img_path = os.path.join(img_dir, img_name)
|
||||
parsing_res = ocr.ocr(img_path, cls=True)
|
||||
@@ -280,7 +269,7 @@ def ocr_preprocess(img_dir):
|
||||
return ocr_reses
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
img_dir = "./demo_pics"
|
||||
save_path = "./demo_ocr_res.json"
|
||||
ocr_results = ocr_preprocess(img_dir)
|
||||
|
||||
@@ -17,17 +17,17 @@ import json
|
||||
|
||||
question = sys.argv[1]
|
||||
|
||||
with open('../OCR_process/demo_ocr_res.json', 'r', encoding='utf8') as f:
|
||||
with open("../OCR_process/demo_ocr_res.json", "r", encoding="utf8") as f:
|
||||
paras = []
|
||||
for line in f:
|
||||
line = json.loads(line.strip())
|
||||
document = line['document']
|
||||
document = line["document"]
|
||||
para = []
|
||||
for token in document:
|
||||
token = token.replace('▁', '')
|
||||
token = token.replace("▁", "")
|
||||
para.append(token)
|
||||
paras.append(''.join(para))
|
||||
paras.append("".join(para))
|
||||
|
||||
with open('./data/demo.tsv', 'w', encoding='utf8') as f:
|
||||
with open("./data/demo.tsv", "w", encoding="utf8") as f:
|
||||
for para in paras:
|
||||
f.write('{}\t\t{}\t0\n'.format(question, para))
|
||||
f.write("{}\t\t{}\t0\n".format(question, para))
|
||||
|
||||
@@ -21,13 +21,15 @@ import numpy as np
|
||||
from six.moves import xrange
|
||||
|
||||
|
||||
def pad_batch_data(insts,
|
||||
pad_idx=0,
|
||||
return_pos=False,
|
||||
return_input_mask=False,
|
||||
return_max_len=False,
|
||||
return_num_token=False,
|
||||
return_seq_lens=False):
|
||||
def pad_batch_data(
|
||||
insts,
|
||||
pad_idx=0,
|
||||
return_pos=False,
|
||||
return_input_mask=False,
|
||||
return_max_len=False,
|
||||
return_num_token=False,
|
||||
return_seq_lens=False,
|
||||
):
|
||||
"""
|
||||
Pad the instances to the max sequence length in batch, and generate the
|
||||
corresponding position data and attention bias.
|
||||
@@ -37,23 +39,18 @@ def pad_batch_data(insts,
|
||||
# Any token included in dict can be used to pad, since the paddings' loss
|
||||
# will be masked out by weights and make no effect on parameter gradients.
|
||||
|
||||
inst_data = np.array(
|
||||
[inst + list([pad_idx] * (max_len - len(inst))) for inst in insts])
|
||||
inst_data = np.array([inst + list([pad_idx] * (max_len - len(inst))) for inst in insts])
|
||||
return_list += [inst_data.astype("int64").reshape([-1, max_len, 1])]
|
||||
|
||||
# position data
|
||||
if return_pos:
|
||||
inst_pos = np.array([
|
||||
list(range(0, len(inst))) + [pad_idx] * (max_len - len(inst))
|
||||
for inst in insts
|
||||
])
|
||||
inst_pos = np.array([list(range(0, len(inst))) + [pad_idx] * (max_len - len(inst)) for inst in insts])
|
||||
|
||||
return_list += [inst_pos.astype("int64").reshape([-1, max_len, 1])]
|
||||
|
||||
if return_input_mask:
|
||||
# This is used to avoid attention on paddings.
|
||||
input_mask_data = np.array(
|
||||
[[1] * len(inst) + [0] * (max_len - len(inst)) for inst in insts])
|
||||
input_mask_data = np.array([[1] * len(inst) + [0] * (max_len - len(inst)) for inst in insts])
|
||||
input_mask_data = np.expand_dims(input_mask_data, axis=-1)
|
||||
return_list += [input_mask_data.astype("float32")]
|
||||
|
||||
|
||||
@@ -32,53 +32,48 @@ from model.ernie import ErnieModel
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_model(args,
|
||||
pyreader_name,
|
||||
ernie_config,
|
||||
is_prediction=False,
|
||||
task_name=""):
|
||||
pyreader = fluid.layers.py_reader(capacity=50,
|
||||
shapes=[[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, 1], [-1, 1]],
|
||||
dtypes=[
|
||||
'int64', 'int64', 'int64', 'int64',
|
||||
'float32', 'int64', 'int64'
|
||||
],
|
||||
lod_levels=[0, 0, 0, 0, 0, 0, 0],
|
||||
name=task_name + "_" + pyreader_name,
|
||||
use_double_buffer=True)
|
||||
def create_model(args, pyreader_name, ernie_config, is_prediction=False, task_name=""):
|
||||
pyreader = fluid.layers.py_reader(
|
||||
capacity=50,
|
||||
shapes=[
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, args.max_seq_len, 1],
|
||||
[-1, 1],
|
||||
[-1, 1],
|
||||
],
|
||||
dtypes=["int64", "int64", "int64", "int64", "float32", "int64", "int64"],
|
||||
lod_levels=[0, 0, 0, 0, 0, 0, 0],
|
||||
name=task_name + "_" + pyreader_name,
|
||||
use_double_buffer=True,
|
||||
)
|
||||
|
||||
(src_ids, sent_ids, pos_ids, task_ids, input_mask, labels,
|
||||
qids) = fluid.layers.read_file(pyreader)
|
||||
(src_ids, sent_ids, pos_ids, task_ids, input_mask, labels, qids) = fluid.layers.read_file(pyreader)
|
||||
|
||||
def _model(is_noise=False):
|
||||
ernie = ErnieModel(src_ids=src_ids,
|
||||
position_ids=pos_ids,
|
||||
sentence_ids=sent_ids,
|
||||
task_ids=task_ids,
|
||||
input_mask=input_mask,
|
||||
config=ernie_config,
|
||||
is_noise=is_noise)
|
||||
ernie = ErnieModel(
|
||||
src_ids=src_ids,
|
||||
position_ids=pos_ids,
|
||||
sentence_ids=sent_ids,
|
||||
task_ids=task_ids,
|
||||
input_mask=input_mask,
|
||||
config=ernie_config,
|
||||
is_noise=is_noise,
|
||||
)
|
||||
|
||||
cls_feats = ernie.get_pooled_output()
|
||||
if not is_noise:
|
||||
cls_feats = fluid.layers.dropout(
|
||||
x=cls_feats,
|
||||
dropout_prob=0.1,
|
||||
dropout_implementation="upscale_in_train")
|
||||
cls_feats = fluid.layers.dropout(x=cls_feats, dropout_prob=0.1, dropout_implementation="upscale_in_train")
|
||||
logits = fluid.layers.fc(
|
||||
input=cls_feats,
|
||||
size=args.num_labels,
|
||||
param_attr=fluid.ParamAttr(
|
||||
name=task_name + "_cls_out_w",
|
||||
initializer=fluid.initializer.TruncatedNormal(scale=0.02)),
|
||||
bias_attr=fluid.ParamAttr(
|
||||
name=task_name + "_cls_out_b",
|
||||
initializer=fluid.initializer.Constant(0.)))
|
||||
name=task_name + "_cls_out_w", initializer=fluid.initializer.TruncatedNormal(scale=0.02)
|
||||
),
|
||||
bias_attr=fluid.ParamAttr(name=task_name + "_cls_out_b", initializer=fluid.initializer.Constant(0.0)),
|
||||
)
|
||||
"""
|
||||
if is_prediction:
|
||||
probs = fluid.layers.softmax(logits)
|
||||
@@ -90,37 +85,31 @@ def create_model(args,
|
||||
return pyreader, probs, feed_targets_name
|
||||
"""
|
||||
|
||||
num_seqs = fluid.layers.create_tensor(dtype='int64')
|
||||
num_seqs = fluid.layers.create_tensor(dtype="int64")
|
||||
## add focal loss
|
||||
ce_loss, probs = fluid.layers.softmax_with_cross_entropy(
|
||||
logits=logits, label=labels, return_softmax=True)
|
||||
ce_loss, probs = fluid.layers.softmax_with_cross_entropy(logits=logits, label=labels, return_softmax=True)
|
||||
loss = fluid.layers.mean(x=ce_loss)
|
||||
accuracy = fluid.layers.accuracy(input=probs,
|
||||
label=labels,
|
||||
total=num_seqs)
|
||||
accuracy = fluid.layers.accuracy(input=probs, label=labels, total=num_seqs)
|
||||
graph_vars = {
|
||||
"loss": loss,
|
||||
"probs": probs,
|
||||
"accuracy": accuracy,
|
||||
"labels": labels,
|
||||
"num_seqs": num_seqs,
|
||||
"qids": qids
|
||||
"qids": qids,
|
||||
}
|
||||
return graph_vars
|
||||
|
||||
if not is_prediction:
|
||||
graph_vars = _model(is_noise=True)
|
||||
old_loss = graph_vars["loss"]
|
||||
token_emb = fluid.default_main_program().global_block().var(
|
||||
"word_embedding")
|
||||
token_emb = fluid.default_main_program().global_block().var("word_embedding")
|
||||
# print(token_emb)
|
||||
token_emb.stop_gradient = False
|
||||
token_gradient = fluid.gradients(old_loss, token_emb)[0]
|
||||
token_gradient.stop_gradient = False
|
||||
epsilon = 1e-8
|
||||
norm = (fluid.layers.sqrt(
|
||||
fluid.layers.reduce_sum(fluid.layers.square(token_gradient)) +
|
||||
epsilon))
|
||||
norm = fluid.layers.sqrt(fluid.layers.reduce_sum(fluid.layers.square(token_gradient)) + epsilon)
|
||||
gp = (0.01 * token_gradient) / norm
|
||||
gp.stop_gradient = True
|
||||
fluid.layers.assign(token_emb + gp, token_emb)
|
||||
@@ -153,17 +142,10 @@ def evaluate_mrr(preds):
|
||||
return total_mrr / qnum
|
||||
|
||||
|
||||
def evaluate(exe,
|
||||
test_program,
|
||||
test_pyreader,
|
||||
graph_vars,
|
||||
eval_phase,
|
||||
use_multi_gpu_test=False,
|
||||
metric='simple_accuracy'):
|
||||
train_fetch_list = [
|
||||
graph_vars["loss"].name, graph_vars["accuracy"].name,
|
||||
graph_vars["num_seqs"].name
|
||||
]
|
||||
def evaluate(
|
||||
exe, test_program, test_pyreader, graph_vars, eval_phase, use_multi_gpu_test=False, metric="simple_accuracy"
|
||||
):
|
||||
train_fetch_list = [graph_vars["loss"].name, graph_vars["accuracy"].name, graph_vars["num_seqs"].name]
|
||||
|
||||
if eval_phase == "train":
|
||||
if "learning_rate" in graph_vars:
|
||||
@@ -185,18 +167,21 @@ def evaluate(exe,
|
||||
time_begin = time.time()
|
||||
|
||||
fetch_list = [
|
||||
graph_vars["loss"].name, graph_vars["accuracy"].name,
|
||||
graph_vars["probs"].name, graph_vars["labels"].name,
|
||||
graph_vars["num_seqs"].name, graph_vars["qids"].name
|
||||
graph_vars["loss"].name,
|
||||
graph_vars["accuracy"].name,
|
||||
graph_vars["probs"].name,
|
||||
graph_vars["labels"].name,
|
||||
graph_vars["num_seqs"].name,
|
||||
graph_vars["qids"].name,
|
||||
]
|
||||
while True:
|
||||
try:
|
||||
if use_multi_gpu_test:
|
||||
np_loss, np_acc, np_probs, np_labels, np_num_seqs, np_qids = exe.run(
|
||||
fetch_list=fetch_list)
|
||||
np_loss, np_acc, np_probs, np_labels, np_num_seqs, np_qids = exe.run(fetch_list=fetch_list)
|
||||
else:
|
||||
np_loss, np_acc, np_probs, np_labels, np_num_seqs, np_qids = exe.run(
|
||||
program=test_program, fetch_list=fetch_list)
|
||||
program=test_program, fetch_list=fetch_list
|
||||
)
|
||||
total_cost += np.sum(np_loss * np_num_seqs)
|
||||
total_acc += np.sum(np_acc * np_num_seqs)
|
||||
total_num_seqs += np.sum(np_num_seqs)
|
||||
@@ -218,31 +203,55 @@ def evaluate(exe,
|
||||
elapsed_time = time_end - time_begin
|
||||
|
||||
evaluate_info = ""
|
||||
if metric == 'acc_and_f1':
|
||||
if metric == "acc_and_f1":
|
||||
ret = acc_and_f1(preds, labels)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, ave_acc: %f, f1: %f, data_num: %d, elapsed time: %f s" \
|
||||
% (eval_phase, cost, ret['acc'], ret['f1'], total_num_seqs, elapsed_time)
|
||||
elif metric == 'matthews_corrcoef':
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, ave_acc: %f, f1: %f, data_num: %d, elapsed time: %f s" % (
|
||||
eval_phase,
|
||||
cost,
|
||||
ret["acc"],
|
||||
ret["f1"],
|
||||
total_num_seqs,
|
||||
elapsed_time,
|
||||
)
|
||||
elif metric == "matthews_corrcoef":
|
||||
ret = matthews_corrcoef(preds, labels)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, matthews_corrcoef: %f, data_num: %d, elapsed time: %f s" \
|
||||
% (eval_phase, cost, ret, total_num_seqs, elapsed_time)
|
||||
elif metric == 'pearson_and_spearman':
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, matthews_corrcoef: %f, data_num: %d, elapsed time: %f s" % (
|
||||
eval_phase,
|
||||
cost,
|
||||
ret,
|
||||
total_num_seqs,
|
||||
elapsed_time,
|
||||
)
|
||||
elif metric == "pearson_and_spearman":
|
||||
ret = pearson_and_spearman(scores, labels)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, pearson:%f, spearman:%f, corr:%f, data_num: %d, elapsed time: %f s" \
|
||||
% (eval_phase, cost, ret['pearson'], ret['spearman'], ret['corr'], total_num_seqs, elapsed_time)
|
||||
elif metric == 'simple_accuracy':
|
||||
evaluate_info = (
|
||||
"[%s evaluation] ave loss: %f, pearson:%f, spearman:%f, corr:%f, data_num: %d, elapsed time: %f s"
|
||||
% (eval_phase, cost, ret["pearson"], ret["spearman"], ret["corr"], total_num_seqs, elapsed_time)
|
||||
)
|
||||
elif metric == "simple_accuracy":
|
||||
ret = simple_accuracy(preds, labels)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, acc:%f, data_num: %d, elapsed time: %f s" \
|
||||
% (eval_phase, cost, ret, total_num_seqs, elapsed_time)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, acc:%f, data_num: %d, elapsed time: %f s" % (
|
||||
eval_phase,
|
||||
cost,
|
||||
ret,
|
||||
total_num_seqs,
|
||||
elapsed_time,
|
||||
)
|
||||
elif metric == "acc_and_f1_and_mrr":
|
||||
ret_a = acc_and_f1(preds, labels)
|
||||
preds = sorted(zip(qids, scores, labels),
|
||||
key=lambda elem: (elem[0], -elem[1]))
|
||||
preds = sorted(zip(qids, scores, labels), key=lambda elem: (elem[0], -elem[1]))
|
||||
ret_b = evaluate_mrr(preds)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, acc: %f, f1: %f, mrr: %f, data_num: %d, elapsed time: %f s" \
|
||||
% (eval_phase, cost, ret_a['acc'], ret_a['f1'], ret_b, total_num_seqs, elapsed_time)
|
||||
evaluate_info = "[%s evaluation] ave loss: %f, acc: %f, f1: %f, mrr: %f, data_num: %d, elapsed time: %f s" % (
|
||||
eval_phase,
|
||||
cost,
|
||||
ret_a["acc"],
|
||||
ret_a["f1"],
|
||||
ret_b,
|
||||
total_num_seqs,
|
||||
elapsed_time,
|
||||
)
|
||||
else:
|
||||
raise ValueError('unsupported metric {}'.format(metric))
|
||||
raise ValueError("unsupported metric {}".format(metric))
|
||||
return evaluate_info
|
||||
|
||||
|
||||
@@ -254,8 +263,7 @@ def matthews_corrcoef(preds, labels):
|
||||
fp = np.sum((labels == 0) & (preds == 1))
|
||||
fn = np.sum((labels == 1) & (preds == 0))
|
||||
|
||||
mcc = ((tp * tn) - (fp * fn)) / np.sqrt(
|
||||
(tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))
|
||||
mcc = ((tp * tn) - (fp * fn)) / np.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))
|
||||
return mcc
|
||||
|
||||
|
||||
@@ -315,8 +323,7 @@ def predict(exe, test_program, test_pyreader, graph_vars, dev_count=1):
|
||||
while True:
|
||||
try:
|
||||
if dev_count == 1:
|
||||
np_probs, np_qids = exe.run(program=test_program,
|
||||
fetch_list=fetch_list)
|
||||
np_probs, np_qids = exe.run(program=test_program, fetch_list=fetch_list)
|
||||
else:
|
||||
np_probs, np_qids = exe.run(fetch_list=fetch_list)
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@ import numpy as np
|
||||
|
||||
|
||||
def read_embed(file_name, dim=768, bs=3000):
|
||||
if file_name.endswith('npy'):
|
||||
if file_name.endswith("npy"):
|
||||
i = 0
|
||||
emb_np = np.load(file_name)
|
||||
while (i < len(emb_np)):
|
||||
vec_list = emb_np[i:i + bs]
|
||||
while i < len(emb_np):
|
||||
vec_list = emb_np[i : i + bs]
|
||||
i += bs
|
||||
yield vec_list
|
||||
else:
|
||||
@@ -32,7 +32,7 @@ def read_embed(file_name, dim=768, bs=3000):
|
||||
with open(file_name) as inp:
|
||||
for line in inp:
|
||||
data = line.strip()
|
||||
vector = [float(item) for item in data.split(' ')]
|
||||
vector = [float(item) for item in data.split(" ")]
|
||||
assert len(vector) == dim
|
||||
vec_list.append(vector)
|
||||
if len(vec_list) == bs:
|
||||
@@ -47,24 +47,23 @@ def load_qid(file_name):
|
||||
with open(file_name) as inp:
|
||||
for line in inp:
|
||||
line = line.strip()
|
||||
qid = line.split('\t')[0]
|
||||
qid = line.split("\t")[0]
|
||||
qid_list.append(qid)
|
||||
return qid_list
|
||||
|
||||
|
||||
def search(index, emb_file, qid_list, outfile, top_k):
|
||||
q_idx = 0
|
||||
with open(outfile, 'w') as out:
|
||||
with open(outfile, "w") as out:
|
||||
for batch_vec in read_embed(emb_file):
|
||||
q_emb_matrix = np.array(batch_vec)
|
||||
res_dist, res_p_id = index.search(q_emb_matrix.astype('float32'),
|
||||
top_k)
|
||||
res_dist, res_p_id = index.search(q_emb_matrix.astype("float32"), top_k)
|
||||
for i in range(len(q_emb_matrix)):
|
||||
qid = qid_list[q_idx]
|
||||
for j in range(top_k):
|
||||
pid = res_p_id[i][j]
|
||||
score = res_dist[i][j]
|
||||
out.write('%s\t%s\t%s\t%s\n' % (qid, pid, j + 1, score))
|
||||
out.write("%s\t%s\t%s\t%s\n" % (qid, pid, j + 1, score))
|
||||
q_idx += 1
|
||||
|
||||
|
||||
@@ -72,12 +71,12 @@ def main():
|
||||
part = sys.argv[1]
|
||||
topk = int(sys.argv[2])
|
||||
q_text_file = sys.argv[3]
|
||||
outfile = 'output/res.top%s-part%s' % (topk, part)
|
||||
outfile = "output/res.top%s-part%s" % (topk, part)
|
||||
|
||||
qid_list = load_qid(q_text_file)
|
||||
|
||||
engine = faiss.read_index("output/para.index.part%s" % part)
|
||||
emb_file = 'output/query.emb.npy'
|
||||
emb_file = "output/query.emb.npy"
|
||||
search(engine, emb_file, qid_list, outfile, topk)
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ total_part = int(sys.argv[3])
|
||||
|
||||
f_list = []
|
||||
for part in range(total_part):
|
||||
f0 = open('output/res.top%s-part%s' % (top, part))
|
||||
f0 = open("output/res.top%s-part%s" % (top, part))
|
||||
f_list.append(f0)
|
||||
|
||||
line_list = []
|
||||
@@ -28,22 +28,21 @@ for part in range(total_part):
|
||||
line = f_list[part].readline()
|
||||
line_list.append(line)
|
||||
|
||||
out = open('output/dev.res.top%s' % top, 'w')
|
||||
last_q = ''
|
||||
out = open("output/dev.res.top%s" % top, "w")
|
||||
last_q = ""
|
||||
ans_list = {}
|
||||
while line_list[-1]:
|
||||
cur_list = []
|
||||
for line in line_list:
|
||||
sub = line.strip().split('\t')
|
||||
sub = line.strip().split("\t")
|
||||
cur_list.append(sub)
|
||||
|
||||
if last_q == '':
|
||||
if last_q == "":
|
||||
last_q = cur_list[0][0]
|
||||
if cur_list[0][0] != last_q:
|
||||
rank = sorted(ans_list.items(), key=lambda a: a[1], reverse=True)
|
||||
for i in range(top):
|
||||
out.write("%s\t%s\t%s\t%s\n" %
|
||||
(last_q, rank[i][0], i + 1, rank[i][1]))
|
||||
out.write("%s\t%s\t%s\t%s\n" % (last_q, rank[i][0], i + 1, rank[i][1]))
|
||||
ans_list = {}
|
||||
for i, sub in enumerate(cur_list):
|
||||
ans_list[int(sub[1]) + shift * i] = float(sub[-1])
|
||||
@@ -59,4 +58,4 @@ for i in range(top):
|
||||
out.write("%s\t%s\t%s\t%s\n" % (last_q, rank[i][0], i + 1, rank[i][1]))
|
||||
out.close()
|
||||
|
||||
print('output/dev.res.top%s' % top)
|
||||
print("output/dev.res.top%s" % top)
|
||||
|
||||
@@ -32,17 +32,15 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ErnieConfig(object):
|
||||
|
||||
def __init__(self, config_path):
|
||||
self._config_dict = self._parse(config_path)
|
||||
|
||||
def _parse(self, config_path):
|
||||
try:
|
||||
with open(config_path, 'r', encoding='utf8') as json_file:
|
||||
with open(config_path, "r", encoding="utf8") as json_file:
|
||||
config_dict = json.load(json_file)
|
||||
except Exception:
|
||||
raise IOError("Error in parsing Ernie model config file '%s'" %
|
||||
config_path)
|
||||
raise IOError("Error in parsing Ernie model config file '%s'" % config_path)
|
||||
else:
|
||||
return config_dict
|
||||
|
||||
@@ -51,39 +49,40 @@ class ErnieConfig(object):
|
||||
|
||||
def print_config(self):
|
||||
for arg, value in sorted(six.iteritems(self._config_dict)):
|
||||
log.info('%s: %s' % (arg, value))
|
||||
log.info('------------------------------------------------')
|
||||
log.info("%s: %s" % (arg, value))
|
||||
log.info("------------------------------------------------")
|
||||
|
||||
|
||||
class ErnieModel(object):
|
||||
def __init__(
|
||||
self,
|
||||
src_ids,
|
||||
position_ids,
|
||||
sentence_ids,
|
||||
task_ids,
|
||||
input_mask,
|
||||
config,
|
||||
weight_sharing=True,
|
||||
model_name="",
|
||||
is_noise=False,
|
||||
):
|
||||
|
||||
def __init__(self,
|
||||
src_ids,
|
||||
position_ids,
|
||||
sentence_ids,
|
||||
task_ids,
|
||||
input_mask,
|
||||
config,
|
||||
weight_sharing=True,
|
||||
model_name='',
|
||||
is_noise=False):
|
||||
|
||||
self._emb_size = config['hidden_size']
|
||||
self._n_layer = config['num_hidden_layers']
|
||||
self._n_head = config['num_attention_heads']
|
||||
self._voc_size = config['vocab_size']
|
||||
self._max_position_seq_len = config['max_position_embeddings']
|
||||
if config['sent_type_vocab_size']:
|
||||
self._sent_types = config['sent_type_vocab_size']
|
||||
self._emb_size = config["hidden_size"]
|
||||
self._n_layer = config["num_hidden_layers"]
|
||||
self._n_head = config["num_attention_heads"]
|
||||
self._voc_size = config["vocab_size"]
|
||||
self._max_position_seq_len = config["max_position_embeddings"]
|
||||
if config["sent_type_vocab_size"]:
|
||||
self._sent_types = config["sent_type_vocab_size"]
|
||||
else:
|
||||
self._sent_types = config['type_vocab_size']
|
||||
self._sent_types = config["type_vocab_size"]
|
||||
|
||||
self._use_task_id = config['use_task_id']
|
||||
self._use_task_id = config["use_task_id"]
|
||||
if self._use_task_id:
|
||||
self._task_types = config['task_type_vocab_size']
|
||||
self._hidden_act = config['hidden_act']
|
||||
self._prepostprocess_dropout = config['hidden_dropout_prob']
|
||||
self._attention_dropout = config['attention_probs_dropout_prob']
|
||||
self._task_types = config["task_type_vocab_size"]
|
||||
self._hidden_act = config["hidden_act"]
|
||||
self._prepostprocess_dropout = config["hidden_dropout_prob"]
|
||||
self._attention_dropout = config["attention_probs_dropout_prob"]
|
||||
if is_noise:
|
||||
self._prepostprocess_dropout = 0
|
||||
self._attention_dropout = 0
|
||||
@@ -98,36 +97,33 @@ class ErnieModel(object):
|
||||
|
||||
# Initialize all weigths by truncated normal initializer, and all biases
|
||||
# will be initialized by constant zero by default.
|
||||
self._param_initializer = fluid.initializer.TruncatedNormal(
|
||||
scale=config['initializer_range'])
|
||||
self._param_initializer = fluid.initializer.TruncatedNormal(scale=config["initializer_range"])
|
||||
|
||||
self._build_model(model_name, src_ids, position_ids, sentence_ids,
|
||||
task_ids, input_mask)
|
||||
self._build_model(model_name, src_ids, position_ids, sentence_ids, task_ids, input_mask)
|
||||
|
||||
def _build_model(self, model_name, src_ids, position_ids, sentence_ids,
|
||||
task_ids, input_mask):
|
||||
def _build_model(self, model_name, src_ids, position_ids, sentence_ids, task_ids, input_mask):
|
||||
# padding id in vocabulary must be set to 0
|
||||
emb_out = fluid.layers.embedding(
|
||||
input=src_ids,
|
||||
size=[self._voc_size, self._emb_size],
|
||||
dtype=self._emb_dtype,
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._word_emb_name,
|
||||
initializer=self._param_initializer),
|
||||
is_sparse=False)
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._word_emb_name, initializer=self._param_initializer),
|
||||
is_sparse=False,
|
||||
)
|
||||
|
||||
position_emb_out = fluid.layers.embedding(
|
||||
input=position_ids,
|
||||
size=[self._max_position_seq_len, self._emb_size],
|
||||
dtype=self._emb_dtype,
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._pos_emb_name,
|
||||
initializer=self._param_initializer))
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._pos_emb_name, initializer=self._param_initializer),
|
||||
)
|
||||
|
||||
sent_emb_out = fluid.layers.embedding(
|
||||
sentence_ids,
|
||||
size=[self._sent_types, self._emb_size],
|
||||
dtype=self._emb_dtype,
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._sent_emb_name,
|
||||
initializer=self._param_initializer))
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._sent_emb_name, initializer=self._param_initializer),
|
||||
)
|
||||
|
||||
emb_out = emb_out + position_emb_out
|
||||
emb_out = emb_out + sent_emb_out
|
||||
@@ -137,28 +133,17 @@ class ErnieModel(object):
|
||||
task_ids,
|
||||
size=[self._task_types, self._emb_size],
|
||||
dtype=self._emb_dtype,
|
||||
param_attr=fluid.ParamAttr(name=model_name +
|
||||
self._task_emb_name,
|
||||
initializer=self._param_initializer))
|
||||
param_attr=fluid.ParamAttr(name=model_name + self._task_emb_name, initializer=self._param_initializer),
|
||||
)
|
||||
|
||||
emb_out = emb_out + task_emb_out
|
||||
|
||||
emb_out = pre_process_layer(emb_out,
|
||||
'nd',
|
||||
self._prepostprocess_dropout,
|
||||
name=model_name + 'pre_encoder')
|
||||
emb_out = pre_process_layer(emb_out, "nd", self._prepostprocess_dropout, name=model_name + "pre_encoder")
|
||||
|
||||
self_attn_mask = fluid.layers.matmul(x=input_mask,
|
||||
y=input_mask,
|
||||
transpose_y=True)
|
||||
self_attn_mask = fluid.layers.matmul(x=input_mask, y=input_mask, transpose_y=True)
|
||||
|
||||
self_attn_mask = fluid.layers.scale(x=self_attn_mask,
|
||||
scale=10000.0,
|
||||
bias=-1.0,
|
||||
bias_after_scale=False)
|
||||
n_head_self_attn_mask = fluid.layers.stack(x=[self_attn_mask] *
|
||||
self._n_head,
|
||||
axis=1)
|
||||
self_attn_mask = fluid.layers.scale(x=self_attn_mask, scale=10000.0, bias=-1.0, bias_after_scale=False)
|
||||
n_head_self_attn_mask = fluid.layers.stack(x=[self_attn_mask] * self._n_head, axis=1)
|
||||
n_head_self_attn_mask.stop_gradient = True
|
||||
|
||||
self._enc_out, self.checkpoints = encoder(
|
||||
@@ -178,44 +163,38 @@ class ErnieModel(object):
|
||||
postprocess_cmd="dan",
|
||||
param_initializer=self._param_initializer,
|
||||
model_name=model_name,
|
||||
name=model_name + 'encoder')
|
||||
name=model_name + "encoder",
|
||||
)
|
||||
|
||||
def get_sequence_output(self):
|
||||
return self._enc_out
|
||||
|
||||
def get_cls_output(self):
|
||||
"""Get the first feature of each sequence for classification"""
|
||||
cls_output = fluid.layers.slice(input=self._enc_out,
|
||||
axes=[1],
|
||||
starts=[0],
|
||||
ends=[1])
|
||||
cls_output = fluid.layers.slice(input=self._enc_out, axes=[1], starts=[0], ends=[1])
|
||||
cls_output = fluid.layers.squeeze(cls_output, axes=[1])
|
||||
return cls_output
|
||||
|
||||
def get_pooled_output(self):
|
||||
"""Get the first feature of each sequence for classification"""
|
||||
next_sent_feat = fluid.layers.slice(input=self._enc_out,
|
||||
axes=[1],
|
||||
starts=[0],
|
||||
ends=[1])
|
||||
next_sent_feat = fluid.layers.slice(input=self._enc_out, axes=[1], starts=[0], ends=[1])
|
||||
next_sent_feat = fluid.layers.fc(
|
||||
input=next_sent_feat,
|
||||
size=self._emb_size,
|
||||
act="tanh",
|
||||
param_attr=fluid.ParamAttr(name="pooled_fc.w_0",
|
||||
initializer=self._param_initializer),
|
||||
bias_attr="pooled_fc.b_0")
|
||||
param_attr=fluid.ParamAttr(name="pooled_fc.w_0", initializer=self._param_initializer),
|
||||
bias_attr="pooled_fc.b_0",
|
||||
)
|
||||
return next_sent_feat
|
||||
|
||||
def get_lm_output(self, mask_label, mask_pos):
|
||||
"""Get the loss & accuracy for pretraining"""
|
||||
|
||||
mask_pos = fluid.layers.cast(x=mask_pos, dtype='int32')
|
||||
mask_pos = fluid.layers.cast(x=mask_pos, dtype="int32")
|
||||
|
||||
# extract the first token feature in each sentence
|
||||
self.next_sent_feat = self.get_pooled_output()
|
||||
reshaped_emb_out = fluid.layers.reshape(x=self._enc_out,
|
||||
shape=[-1, self._emb_size])
|
||||
reshaped_emb_out = fluid.layers.reshape(x=self._enc_out, shape=[-1, self._emb_size])
|
||||
# extract masked tokens' feature
|
||||
mask_feat = fluid.layers.gather(input=reshaped_emb_out, index=mask_pos)
|
||||
|
||||
@@ -224,61 +203,61 @@ class ErnieModel(object):
|
||||
input=mask_feat,
|
||||
size=self._emb_size,
|
||||
act=self._hidden_act,
|
||||
param_attr=fluid.ParamAttr(name='mask_lm_trans_fc.w_0',
|
||||
initializer=self._param_initializer),
|
||||
bias_attr=fluid.ParamAttr(name='mask_lm_trans_fc.b_0'))
|
||||
param_attr=fluid.ParamAttr(name="mask_lm_trans_fc.w_0", initializer=self._param_initializer),
|
||||
bias_attr=fluid.ParamAttr(name="mask_lm_trans_fc.b_0"),
|
||||
)
|
||||
|
||||
# transform: layer norm
|
||||
mask_trans_feat = fluid.layers.layer_norm(
|
||||
mask_trans_feat,
|
||||
begin_norm_axis=len(mask_trans_feat.shape) - 1,
|
||||
param_attr=fluid.ParamAttr(
|
||||
name='mask_lm_trans_layer_norm_scale',
|
||||
initializer=fluid.initializer.Constant(1.)),
|
||||
name="mask_lm_trans_layer_norm_scale", initializer=fluid.initializer.Constant(1.0)
|
||||
),
|
||||
bias_attr=fluid.ParamAttr(
|
||||
name='mask_lm_trans_layer_norm_bias',
|
||||
initializer=fluid.initializer.Constant(1.)))
|
||||
name="mask_lm_trans_layer_norm_bias", initializer=fluid.initializer.Constant(1.0)
|
||||
),
|
||||
)
|
||||
# transform: layer norm
|
||||
#mask_trans_feat = pre_process_layer(
|
||||
# mask_trans_feat = pre_process_layer(
|
||||
# mask_trans_feat, 'n', name='mask_lm_trans')
|
||||
|
||||
mask_lm_out_bias_attr = fluid.ParamAttr(
|
||||
name="mask_lm_out_fc.b_0",
|
||||
initializer=fluid.initializer.Constant(value=0.0))
|
||||
name="mask_lm_out_fc.b_0", initializer=fluid.initializer.Constant(value=0.0)
|
||||
)
|
||||
if self._weight_sharing:
|
||||
fc_out = fluid.layers.matmul(
|
||||
x=mask_trans_feat,
|
||||
y=fluid.default_main_program().global_block().var(
|
||||
self._word_emb_name),
|
||||
transpose_y=True)
|
||||
fc_out += fluid.layers.create_parameter(shape=[self._voc_size],
|
||||
dtype=self._emb_dtype,
|
||||
attr=mask_lm_out_bias_attr,
|
||||
is_bias=True)
|
||||
y=fluid.default_main_program().global_block().var(self._word_emb_name),
|
||||
transpose_y=True,
|
||||
)
|
||||
fc_out += fluid.layers.create_parameter(
|
||||
shape=[self._voc_size], dtype=self._emb_dtype, attr=mask_lm_out_bias_attr, is_bias=True
|
||||
)
|
||||
|
||||
else:
|
||||
fc_out = fluid.layers.fc(input=mask_trans_feat,
|
||||
size=self._voc_size,
|
||||
param_attr=fluid.ParamAttr(
|
||||
name="mask_lm_out_fc.w_0",
|
||||
initializer=self._param_initializer),
|
||||
bias_attr=mask_lm_out_bias_attr)
|
||||
fc_out = fluid.layers.fc(
|
||||
input=mask_trans_feat,
|
||||
size=self._voc_size,
|
||||
param_attr=fluid.ParamAttr(name="mask_lm_out_fc.w_0", initializer=self._param_initializer),
|
||||
bias_attr=mask_lm_out_bias_attr,
|
||||
)
|
||||
|
||||
mask_lm_loss = fluid.layers.softmax_with_cross_entropy(logits=fc_out,
|
||||
label=mask_label)
|
||||
mask_lm_loss = fluid.layers.softmax_with_cross_entropy(logits=fc_out, label=mask_label)
|
||||
mean_mask_lm_loss = fluid.layers.mean(mask_lm_loss)
|
||||
|
||||
return mean_mask_lm_loss
|
||||
|
||||
def get_task_output(self, task, task_labels):
|
||||
task_fc_out = fluid.layers.fc(input=self.next_sent_feat,
|
||||
size=task["num_labels"],
|
||||
param_attr=fluid.ParamAttr(
|
||||
name=task["task_name"] + "_fc.w_0",
|
||||
initializer=self._param_initializer),
|
||||
bias_attr=task["task_name"] + "_fc.b_0")
|
||||
task_fc_out = fluid.layers.fc(
|
||||
input=self.next_sent_feat,
|
||||
size=task["num_labels"],
|
||||
param_attr=fluid.ParamAttr(name=task["task_name"] + "_fc.w_0", initializer=self._param_initializer),
|
||||
bias_attr=task["task_name"] + "_fc.b_0",
|
||||
)
|
||||
task_loss, task_softmax = fluid.layers.softmax_with_cross_entropy(
|
||||
logits=task_fc_out, label=task_labels, return_softmax=True)
|
||||
logits=task_fc_out, label=task_labels, return_softmax=True
|
||||
)
|
||||
task_acc = fluid.layers.accuracy(input=task_softmax, label=task_labels)
|
||||
mean_task_loss = fluid.layers.mean(task_loss)
|
||||
return mean_task_loss, task_acc
|
||||
|
||||
@@ -23,18 +23,20 @@ import paddle.fluid as fluid
|
||||
import paddle.fluid.layers as layers
|
||||
|
||||
|
||||
def multi_head_attention(queries,
|
||||
keys,
|
||||
values,
|
||||
attn_bias,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
n_head=1,
|
||||
dropout_rate=0.,
|
||||
cache=None,
|
||||
param_initializer=None,
|
||||
name='multi_head_att'):
|
||||
def multi_head_attention(
|
||||
queries,
|
||||
keys,
|
||||
values,
|
||||
attn_bias,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
n_head=1,
|
||||
dropout_rate=0.0,
|
||||
cache=None,
|
||||
param_initializer=None,
|
||||
name="multi_head_att",
|
||||
):
|
||||
"""
|
||||
Multi-Head Attention. Note that attn_bias is added to the logit before
|
||||
computing softmax activiation to mask certain selected positions so that
|
||||
@@ -44,31 +46,33 @@ def multi_head_attention(queries,
|
||||
values = keys if values is None else values
|
||||
|
||||
if not (len(queries.shape) == len(keys.shape) == len(values.shape) == 3):
|
||||
raise ValueError(
|
||||
"Inputs: quries, keys and values should all be 3-D tensors.")
|
||||
raise ValueError("Inputs: quries, keys and values should all be 3-D tensors.")
|
||||
|
||||
def __compute_qkv(queries, keys, values, n_head, d_key, d_value):
|
||||
"""
|
||||
Add linear projection to queries, keys, and values.
|
||||
"""
|
||||
q = layers.fc(input=queries,
|
||||
size=d_key * n_head,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + '_query_fc.w_0',
|
||||
initializer=param_initializer),
|
||||
bias_attr=name + '_query_fc.b_0')
|
||||
k = layers.fc(input=keys,
|
||||
size=d_key * n_head,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + '_key_fc.w_0',
|
||||
initializer=param_initializer),
|
||||
bias_attr=name + '_key_fc.b_0')
|
||||
v = layers.fc(input=values,
|
||||
size=d_value * n_head,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + '_value_fc.w_0',
|
||||
initializer=param_initializer),
|
||||
bias_attr=name + '_value_fc.b_0')
|
||||
q = layers.fc(
|
||||
input=queries,
|
||||
size=d_key * n_head,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + "_query_fc.w_0", initializer=param_initializer),
|
||||
bias_attr=name + "_query_fc.b_0",
|
||||
)
|
||||
k = layers.fc(
|
||||
input=keys,
|
||||
size=d_key * n_head,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + "_key_fc.w_0", initializer=param_initializer),
|
||||
bias_attr=name + "_key_fc.b_0",
|
||||
)
|
||||
v = layers.fc(
|
||||
input=values,
|
||||
size=d_value * n_head,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + "_value_fc.w_0", initializer=param_initializer),
|
||||
bias_attr=name + "_value_fc.b_0",
|
||||
)
|
||||
return q, k, v
|
||||
|
||||
def __split_heads(x, n_head):
|
||||
@@ -81,9 +85,7 @@ def multi_head_attention(queries,
|
||||
hidden_size = x.shape[-1]
|
||||
# The value 0 in shape attr means copying the corresponding dimension
|
||||
# size of the input as the output dimension size.
|
||||
reshaped = layers.reshape(x=x,
|
||||
shape=[0, 0, n_head, hidden_size // n_head],
|
||||
inplace=True)
|
||||
reshaped = layers.reshape(x=x, shape=[0, 0, n_head, hidden_size // n_head], inplace=True)
|
||||
|
||||
# permuate the dimensions into:
|
||||
# [batch_size, n_head, max_sequence_len, hidden_size_per_head]
|
||||
@@ -94,16 +96,15 @@ def multi_head_attention(queries,
|
||||
Transpose and then reshape the last two dimensions of inpunt tensor x
|
||||
so that it becomes one dimension, which is reverse to __split_heads.
|
||||
"""
|
||||
if len(x.shape) == 3: return x
|
||||
if len(x.shape) == 3:
|
||||
return x
|
||||
if len(x.shape) != 4:
|
||||
raise ValueError("Input(x) should be a 4-D Tensor.")
|
||||
|
||||
trans_x = layers.transpose(x, perm=[0, 2, 1, 3])
|
||||
# The value 0 in shape attr means copying the corresponding dimension
|
||||
# size of the input as the output dimension size.
|
||||
return layers.reshape(x=trans_x,
|
||||
shape=[0, 0, trans_x.shape[2] * trans_x.shape[3]],
|
||||
inplace=True)
|
||||
return layers.reshape(x=trans_x, shape=[0, 0, trans_x.shape[2] * trans_x.shape[3]], inplace=True)
|
||||
|
||||
def scaled_dot_product_attention(q, k, v, attn_bias, d_key, dropout_rate):
|
||||
"""
|
||||
@@ -115,10 +116,9 @@ def multi_head_attention(queries,
|
||||
product += attn_bias
|
||||
weights = layers.softmax(product)
|
||||
if dropout_rate:
|
||||
weights = layers.dropout(weights,
|
||||
dropout_prob=dropout_rate,
|
||||
dropout_implementation="upscale_in_train",
|
||||
is_test=False)
|
||||
weights = layers.dropout(
|
||||
weights, dropout_prob=dropout_rate, dropout_implementation="upscale_in_train", is_test=False
|
||||
)
|
||||
out = layers.matmul(weights, v)
|
||||
return out
|
||||
|
||||
@@ -128,70 +128,57 @@ def multi_head_attention(queries,
|
||||
# Since the inplace reshape in __split_heads changes the shape of k and
|
||||
# v, which is the cache input for next time step, reshape the cache
|
||||
# input from the previous time step first.
|
||||
k = cache["k"] = layers.concat(
|
||||
[layers.reshape(cache["k"], shape=[0, 0, d_model]), k], axis=1)
|
||||
v = cache["v"] = layers.concat(
|
||||
[layers.reshape(cache["v"], shape=[0, 0, d_model]), v], axis=1)
|
||||
k = cache["k"] = layers.concat([layers.reshape(cache["k"], shape=[0, 0, d_model]), k], axis=1)
|
||||
v = cache["v"] = layers.concat([layers.reshape(cache["v"], shape=[0, 0, d_model]), v], axis=1)
|
||||
|
||||
q = __split_heads(q, n_head)
|
||||
k = __split_heads(k, n_head)
|
||||
v = __split_heads(v, n_head)
|
||||
|
||||
ctx_multiheads = scaled_dot_product_attention(q, k, v, attn_bias, d_key,
|
||||
dropout_rate)
|
||||
ctx_multiheads = scaled_dot_product_attention(q, k, v, attn_bias, d_key, dropout_rate)
|
||||
|
||||
out = __combine_heads(ctx_multiheads)
|
||||
|
||||
# Project back to the model size.
|
||||
proj_out = layers.fc(input=out,
|
||||
size=d_model,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(
|
||||
name=name + '_output_fc.w_0',
|
||||
initializer=param_initializer),
|
||||
bias_attr=name + '_output_fc.b_0')
|
||||
proj_out = layers.fc(
|
||||
input=out,
|
||||
size=d_model,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + "_output_fc.w_0", initializer=param_initializer),
|
||||
bias_attr=name + "_output_fc.b_0",
|
||||
)
|
||||
return proj_out
|
||||
|
||||
|
||||
def positionwise_feed_forward(x,
|
||||
d_inner_hid,
|
||||
d_hid,
|
||||
dropout_rate,
|
||||
hidden_act,
|
||||
param_initializer=None,
|
||||
name='ffn'):
|
||||
def positionwise_feed_forward(x, d_inner_hid, d_hid, dropout_rate, hidden_act, param_initializer=None, name="ffn"):
|
||||
"""
|
||||
Position-wise Feed-Forward Networks.
|
||||
This module consists of two linear transformations with a ReLU activation
|
||||
in between, which is applied to each position separately and identically.
|
||||
"""
|
||||
hidden = layers.fc(input=x,
|
||||
size=d_inner_hid,
|
||||
num_flatten_dims=2,
|
||||
act=hidden_act,
|
||||
param_attr=fluid.ParamAttr(
|
||||
name=name + '_fc_0.w_0',
|
||||
initializer=param_initializer),
|
||||
bias_attr=name + '_fc_0.b_0')
|
||||
hidden = layers.fc(
|
||||
input=x,
|
||||
size=d_inner_hid,
|
||||
num_flatten_dims=2,
|
||||
act=hidden_act,
|
||||
param_attr=fluid.ParamAttr(name=name + "_fc_0.w_0", initializer=param_initializer),
|
||||
bias_attr=name + "_fc_0.b_0",
|
||||
)
|
||||
if dropout_rate:
|
||||
hidden = layers.dropout(hidden,
|
||||
dropout_prob=dropout_rate,
|
||||
dropout_implementation="upscale_in_train",
|
||||
is_test=False)
|
||||
out = layers.fc(input=hidden,
|
||||
size=d_hid,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + '_fc_1.w_0',
|
||||
initializer=param_initializer),
|
||||
bias_attr=name + '_fc_1.b_0')
|
||||
hidden = layers.dropout(
|
||||
hidden, dropout_prob=dropout_rate, dropout_implementation="upscale_in_train", is_test=False
|
||||
)
|
||||
out = layers.fc(
|
||||
input=hidden,
|
||||
size=d_hid,
|
||||
num_flatten_dims=2,
|
||||
param_attr=fluid.ParamAttr(name=name + "_fc_1.w_0", initializer=param_initializer),
|
||||
bias_attr=name + "_fc_1.b_0",
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def pre_post_process_layer(prev_out,
|
||||
out,
|
||||
process_cmd,
|
||||
dropout_rate=0.,
|
||||
name=''):
|
||||
def pre_post_process_layer(prev_out, out, process_cmd, dropout_rate=0.0, name=""):
|
||||
"""
|
||||
Add residual connection, layer normalization and droput to the out tensor
|
||||
optionally according to the value of process_cmd.
|
||||
@@ -209,19 +196,17 @@ def pre_post_process_layer(prev_out,
|
||||
out,
|
||||
begin_norm_axis=len(out.shape) - 1,
|
||||
param_attr=fluid.ParamAttr(
|
||||
name=name + '_layer_norm_scale',
|
||||
initializer=fluid.initializer.Constant(1.)),
|
||||
bias_attr=fluid.ParamAttr(
|
||||
name=name + '_layer_norm_bias',
|
||||
initializer=fluid.initializer.Constant(0.)))
|
||||
name=name + "_layer_norm_scale", initializer=fluid.initializer.Constant(1.0)
|
||||
),
|
||||
bias_attr=fluid.ParamAttr(name=name + "_layer_norm_bias", initializer=fluid.initializer.Constant(0.0)),
|
||||
)
|
||||
if out_dtype == fluid.core.VarDesc.VarType.FP16:
|
||||
out = layers.cast(x=out, dtype="float16")
|
||||
elif cmd == "d": # add dropout
|
||||
if dropout_rate:
|
||||
out = layers.dropout(out,
|
||||
dropout_prob=dropout_rate,
|
||||
dropout_implementation="upscale_in_train",
|
||||
is_test=False)
|
||||
out = layers.dropout(
|
||||
out, dropout_prob=dropout_rate, dropout_implementation="upscale_in_train", is_test=False
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
@@ -229,68 +214,88 @@ pre_process_layer = partial(pre_post_process_layer, None)
|
||||
post_process_layer = pre_post_process_layer
|
||||
|
||||
|
||||
def encoder_layer(enc_input,
|
||||
attn_bias,
|
||||
n_head,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
d_inner_hid,
|
||||
prepostprocess_dropout,
|
||||
attention_dropout,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
preprocess_cmd="n",
|
||||
postprocess_cmd="da",
|
||||
param_initializer=None,
|
||||
name=''):
|
||||
def encoder_layer(
|
||||
enc_input,
|
||||
attn_bias,
|
||||
n_head,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
d_inner_hid,
|
||||
prepostprocess_dropout,
|
||||
attention_dropout,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
preprocess_cmd="n",
|
||||
postprocess_cmd="da",
|
||||
param_initializer=None,
|
||||
name="",
|
||||
):
|
||||
"""The encoder layers that can be stacked to form a deep encoder.
|
||||
This module consits of a multi-head (self) attention followed by
|
||||
position-wise feed-forward networks and both the two components companied
|
||||
with the post_process_layer to add residual connection, layer normalization
|
||||
and droput.
|
||||
"""
|
||||
attn_output = multi_head_attention(pre_process_layer(enc_input,
|
||||
preprocess_cmd,
|
||||
prepostprocess_dropout,
|
||||
name=name +
|
||||
'_pre_att'),
|
||||
None,
|
||||
None,
|
||||
attn_bias,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
n_head,
|
||||
attention_dropout,
|
||||
param_initializer=param_initializer,
|
||||
name=name + '_multi_head_att')
|
||||
attn_output = post_process_layer(enc_input,
|
||||
attn_output,
|
||||
postprocess_cmd,
|
||||
prepostprocess_dropout,
|
||||
name=name + '_post_att')
|
||||
ffd_output = positionwise_feed_forward(pre_process_layer(
|
||||
attn_output,
|
||||
preprocess_cmd,
|
||||
prepostprocess_dropout,
|
||||
name=name + '_pre_ffn'),
|
||||
d_inner_hid,
|
||||
d_model,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
param_initializer=param_initializer,
|
||||
name=name + '_ffn')
|
||||
return post_process_layer(attn_output,
|
||||
ffd_output,
|
||||
postprocess_cmd,
|
||||
prepostprocess_dropout,
|
||||
name=name + '_post_ffn'), ffd_output
|
||||
attn_output = multi_head_attention(
|
||||
pre_process_layer(enc_input, preprocess_cmd, prepostprocess_dropout, name=name + "_pre_att"),
|
||||
None,
|
||||
None,
|
||||
attn_bias,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
n_head,
|
||||
attention_dropout,
|
||||
param_initializer=param_initializer,
|
||||
name=name + "_multi_head_att",
|
||||
)
|
||||
attn_output = post_process_layer(
|
||||
enc_input, attn_output, postprocess_cmd, prepostprocess_dropout, name=name + "_post_att"
|
||||
)
|
||||
ffd_output = positionwise_feed_forward(
|
||||
pre_process_layer(attn_output, preprocess_cmd, prepostprocess_dropout, name=name + "_pre_ffn"),
|
||||
d_inner_hid,
|
||||
d_model,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
param_initializer=param_initializer,
|
||||
name=name + "_ffn",
|
||||
)
|
||||
return (
|
||||
post_process_layer(attn_output, ffd_output, postprocess_cmd, prepostprocess_dropout, name=name + "_post_ffn"),
|
||||
ffd_output,
|
||||
)
|
||||
|
||||
|
||||
def encoder(enc_input,
|
||||
def encoder(
|
||||
enc_input,
|
||||
attn_bias,
|
||||
n_layer,
|
||||
n_head,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
d_inner_hid,
|
||||
prepostprocess_dropout,
|
||||
attention_dropout,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
preprocess_cmd="n",
|
||||
postprocess_cmd="da",
|
||||
param_initializer=None,
|
||||
model_name="",
|
||||
name="",
|
||||
):
|
||||
"""
|
||||
The encoder is composed of a stack of identical layers returned by calling
|
||||
encoder_layer.
|
||||
"""
|
||||
checkpoints = []
|
||||
for i in range(n_layer):
|
||||
enc_output, cp = encoder_layer(
|
||||
enc_input,
|
||||
attn_bias,
|
||||
n_layer,
|
||||
n_head,
|
||||
d_key,
|
||||
d_value,
|
||||
@@ -300,37 +305,15 @@ def encoder(enc_input,
|
||||
attention_dropout,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
preprocess_cmd="n",
|
||||
postprocess_cmd="da",
|
||||
param_initializer=None,
|
||||
model_name='',
|
||||
name=''):
|
||||
"""
|
||||
The encoder is composed of a stack of identical layers returned by calling
|
||||
encoder_layer.
|
||||
"""
|
||||
checkpoints = []
|
||||
for i in range(n_layer):
|
||||
enc_output, cp = encoder_layer(enc_input,
|
||||
attn_bias,
|
||||
n_head,
|
||||
d_key,
|
||||
d_value,
|
||||
d_model,
|
||||
d_inner_hid,
|
||||
prepostprocess_dropout,
|
||||
attention_dropout,
|
||||
relu_dropout,
|
||||
hidden_act,
|
||||
preprocess_cmd,
|
||||
postprocess_cmd,
|
||||
param_initializer=param_initializer,
|
||||
name=name + '_layer_' + str(i))
|
||||
preprocess_cmd,
|
||||
postprocess_cmd,
|
||||
param_initializer=param_initializer,
|
||||
name=name + "_layer_" + str(i),
|
||||
)
|
||||
checkpoints.append(cp)
|
||||
enc_input = enc_output
|
||||
enc_output = pre_process_layer(enc_output,
|
||||
preprocess_cmd,
|
||||
prepostprocess_dropout,
|
||||
name=model_name + "post_encoder")
|
||||
enc_output = pre_process_layer(
|
||||
enc_output, preprocess_cmd, prepostprocess_dropout, name=model_name + "post_encoder"
|
||||
)
|
||||
|
||||
return enc_output, checkpoints
|
||||
|
||||
@@ -26,14 +26,11 @@ from paddle.fluid.incubate.fleet.collective import fleet, DistributedStrategy
|
||||
|
||||
|
||||
def linear_warmup_decay(learning_rate, warmup_steps, num_train_steps):
|
||||
""" Applies linear warmup of learning rate from 0 and decay to 0."""
|
||||
"""Applies linear warmup of learning rate from 0 and decay to 0."""
|
||||
with fluid.default_main_program()._lr_schedule_guard():
|
||||
lr = fluid.layers.tensor.create_global_var(
|
||||
shape=[1],
|
||||
value=0.0,
|
||||
dtype='float32',
|
||||
persistable=True,
|
||||
name="scheduled_learning_rate")
|
||||
shape=[1], value=0.0, dtype="float32", persistable=True, name="scheduled_learning_rate"
|
||||
)
|
||||
|
||||
global_step = fluid.layers.learning_rate_scheduler._decay_step_counter()
|
||||
|
||||
@@ -47,41 +44,41 @@ def linear_warmup_decay(learning_rate, warmup_steps, num_train_steps):
|
||||
decay_steps=num_train_steps,
|
||||
end_learning_rate=0.0,
|
||||
power=1.0,
|
||||
cycle=False)
|
||||
cycle=False,
|
||||
)
|
||||
fluid.layers.tensor.assign(decayed_lr, lr)
|
||||
|
||||
return lr
|
||||
|
||||
|
||||
def optimization(loss,
|
||||
warmup_steps,
|
||||
num_train_steps,
|
||||
learning_rate,
|
||||
train_program,
|
||||
startup_prog,
|
||||
weight_decay,
|
||||
scheduler='linear_warmup_decay',
|
||||
use_dynamic_loss_scaling=False,
|
||||
incr_every_n_steps=1000,
|
||||
decr_every_n_nan_or_inf=2,
|
||||
incr_ratio=2.0,
|
||||
decr_ratio=0.8,
|
||||
dist_strategy=None,
|
||||
use_lamb=False):
|
||||
def optimization(
|
||||
loss,
|
||||
warmup_steps,
|
||||
num_train_steps,
|
||||
learning_rate,
|
||||
train_program,
|
||||
startup_prog,
|
||||
weight_decay,
|
||||
scheduler="linear_warmup_decay",
|
||||
use_dynamic_loss_scaling=False,
|
||||
incr_every_n_steps=1000,
|
||||
decr_every_n_nan_or_inf=2,
|
||||
incr_ratio=2.0,
|
||||
decr_ratio=0.8,
|
||||
dist_strategy=None,
|
||||
use_lamb=False,
|
||||
):
|
||||
if warmup_steps > 0:
|
||||
if scheduler == 'noam_decay':
|
||||
scheduled_lr = fluid.layers.learning_rate_scheduler\
|
||||
.noam_decay(1/(warmup_steps *(learning_rate ** 2)),
|
||||
warmup_steps)
|
||||
elif scheduler == 'linear_warmup_decay':
|
||||
scheduled_lr = linear_warmup_decay(learning_rate, warmup_steps,
|
||||
num_train_steps)
|
||||
if scheduler == "noam_decay":
|
||||
scheduled_lr = fluid.layers.learning_rate_scheduler.noam_decay(
|
||||
1 / (warmup_steps * (learning_rate**2)), warmup_steps
|
||||
)
|
||||
elif scheduler == "linear_warmup_decay":
|
||||
scheduled_lr = linear_warmup_decay(learning_rate, warmup_steps, num_train_steps)
|
||||
else:
|
||||
raise ValueError("Unkown learning rate scheduler, should be "
|
||||
"'noam_decay' or 'linear_warmup_decay'")
|
||||
raise ValueError("Unkown learning rate scheduler, should be " "'noam_decay' or 'linear_warmup_decay'")
|
||||
if use_lamb:
|
||||
optimizer = fluid.optimizer.LambOptimizer(
|
||||
learning_rate=scheduled_lr)
|
||||
optimizer = fluid.optimizer.LambOptimizer(learning_rate=scheduled_lr)
|
||||
else:
|
||||
optimizer = fluid.optimizer.Adam(learning_rate=scheduled_lr)
|
||||
else:
|
||||
@@ -89,18 +86,16 @@ def optimization(loss,
|
||||
name=fluid.unique_name.generate("learning_rate"),
|
||||
shape=[1],
|
||||
value=learning_rate,
|
||||
dtype='float32',
|
||||
persistable=True)
|
||||
dtype="float32",
|
||||
persistable=True,
|
||||
)
|
||||
if use_lamb:
|
||||
optimizer = fluid.optimizer.LambOptimizer(
|
||||
learning_rate=scheduled_lr)
|
||||
optimizer = fluid.optimizer.LambOptimizer(learning_rate=scheduled_lr)
|
||||
else:
|
||||
optimizer = fluid.optimizer.Adam(learning_rate=scheduled_lr)
|
||||
optimizer._learning_rate_map[
|
||||
fluid.default_main_program()] = scheduled_lr
|
||||
optimizer._learning_rate_map[fluid.default_main_program()] = scheduled_lr
|
||||
|
||||
fluid.clip.set_gradient_clip(clip=fluid.clip.GradientClipByGlobalNorm(
|
||||
clip_norm=1.0))
|
||||
fluid.clip.set_gradient_clip(clip=fluid.clip.GradientClipByGlobalNorm(clip_norm=1.0))
|
||||
|
||||
def exclude_from_weight_decay(name):
|
||||
if name.find("layer_norm") > -1:
|
||||
@@ -119,8 +114,7 @@ def optimization(loss,
|
||||
|
||||
if dist_strategy is not None:
|
||||
# use fleet api
|
||||
optimizer = fleet.distributed_optimizer(optimizer,
|
||||
strategy=dist_strategy)
|
||||
optimizer = fleet.distributed_optimizer(optimizer, strategy=dist_strategy)
|
||||
|
||||
_, param_grads = optimizer.minimize(loss)
|
||||
|
||||
@@ -128,10 +122,8 @@ def optimization(loss,
|
||||
for param, grad in param_grads:
|
||||
if exclude_from_weight_decay(param.name):
|
||||
continue
|
||||
with param.block.program._optimized_guard(
|
||||
[param, grad]), fluid.framework.name_scope("weight_decay"):
|
||||
updated_param = param - param_list[
|
||||
param.name] * weight_decay * scheduled_lr
|
||||
with param.block.program._optimized_guard([param, grad]), fluid.framework.name_scope("weight_decay"):
|
||||
updated_param = param - param_list[param.name] * weight_decay * scheduled_lr
|
||||
fluid.layers.assign(output=param, input=updated_param)
|
||||
|
||||
return scheduled_lr
|
||||
|
||||
@@ -34,16 +34,16 @@ log = logging.getLogger(__name__)
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
|
||||
|
||||
|
||||
def csv_reader(fd, delimiter='\t', trainer_id=0, trainer_num=1):
|
||||
|
||||
def csv_reader(fd, delimiter="\t", trainer_id=0, trainer_num=1):
|
||||
def gen():
|
||||
for i, line in enumerate(fd):
|
||||
if i % trainer_num == trainer_id:
|
||||
slots = line.rstrip('\n').split(delimiter)
|
||||
slots = line.rstrip("\n").split(delimiter)
|
||||
if len(slots) == 1:
|
||||
yield slots,
|
||||
else:
|
||||
@@ -53,22 +53,22 @@ def csv_reader(fd, delimiter='\t', trainer_id=0, trainer_num=1):
|
||||
|
||||
|
||||
class BaseReader(object):
|
||||
|
||||
def __init__(self,
|
||||
vocab_path,
|
||||
label_map_config=None,
|
||||
max_seq_len=512,
|
||||
total_num=0,
|
||||
do_lower_case=True,
|
||||
in_tokens=False,
|
||||
is_inference=False,
|
||||
random_seed=None,
|
||||
tokenizer="FullTokenizer",
|
||||
for_cn=True,
|
||||
task_id=0):
|
||||
def __init__(
|
||||
self,
|
||||
vocab_path,
|
||||
label_map_config=None,
|
||||
max_seq_len=512,
|
||||
total_num=0,
|
||||
do_lower_case=True,
|
||||
in_tokens=False,
|
||||
is_inference=False,
|
||||
random_seed=None,
|
||||
tokenizer="FullTokenizer",
|
||||
for_cn=True,
|
||||
task_id=0,
|
||||
):
|
||||
self.max_seq_len = max_seq_len
|
||||
self.tokenizer = tokenization.FullTokenizer(vocab_file=vocab_path,
|
||||
do_lower_case=do_lower_case)
|
||||
self.tokenizer = tokenization.FullTokenizer(vocab_file=vocab_path, do_lower_case=do_lower_case)
|
||||
self.vocab = self.tokenizer.vocab
|
||||
self.pad_id = self.vocab["[PAD]"]
|
||||
self.cls_id = self.vocab["[CLS]"]
|
||||
@@ -86,7 +86,7 @@ class BaseReader(object):
|
||||
self.total_num = total_num
|
||||
|
||||
if label_map_config:
|
||||
with open(label_map_config, encoding='utf8') as f:
|
||||
with open(label_map_config, encoding="utf8") as f:
|
||||
self.label_map = json.load(f)
|
||||
else:
|
||||
self.label_map = None
|
||||
@@ -97,10 +97,10 @@ class BaseReader(object):
|
||||
|
||||
def _read_tsv(self, input_file, quotechar=None):
|
||||
"""Reads a tab separated value file."""
|
||||
with open(input_file, 'r', encoding='utf8') as f:
|
||||
with open(input_file, "r", encoding="utf8") as f:
|
||||
reader = csv_reader(f)
|
||||
headers = next(reader)
|
||||
Example = namedtuple('Example', headers)
|
||||
Example = namedtuple("Example", headers)
|
||||
|
||||
examples = []
|
||||
for line in reader:
|
||||
@@ -180,30 +180,23 @@ class BaseReader(object):
|
||||
position_ids = list(range(len(token_ids)))
|
||||
|
||||
if self.is_inference:
|
||||
Record = namedtuple('Record',
|
||||
['token_ids', 'text_type_ids', 'position_ids'])
|
||||
record = Record(token_ids=token_ids,
|
||||
text_type_ids=text_type_ids,
|
||||
position_ids=position_ids)
|
||||
Record = namedtuple("Record", ["token_ids", "text_type_ids", "position_ids"])
|
||||
record = Record(token_ids=token_ids, text_type_ids=text_type_ids, position_ids=position_ids)
|
||||
else:
|
||||
if self.label_map:
|
||||
label_id = self.label_map[example.label]
|
||||
else:
|
||||
label_id = example.label
|
||||
|
||||
Record = namedtuple('Record', [
|
||||
'token_ids', 'text_type_ids', 'position_ids', 'label_id', 'qid'
|
||||
])
|
||||
Record = namedtuple("Record", ["token_ids", "text_type_ids", "position_ids", "label_id", "qid"])
|
||||
|
||||
qid = None
|
||||
if "qid" in example._fields:
|
||||
qid = example.qid
|
||||
|
||||
record = Record(token_ids=token_ids,
|
||||
text_type_ids=text_type_ids,
|
||||
position_ids=position_ids,
|
||||
label_id=label_id,
|
||||
qid=qid)
|
||||
record = Record(
|
||||
token_ids=token_ids, text_type_ids=text_type_ids, position_ids=position_ids, label_id=label_id, qid=qid
|
||||
)
|
||||
return record
|
||||
|
||||
def _prepare_batch_data(self, examples, batch_size, phase=None):
|
||||
@@ -212,8 +205,7 @@ class BaseReader(object):
|
||||
for index, example in enumerate(examples):
|
||||
if phase == "train":
|
||||
self.current_example = index
|
||||
record = self._convert_example_to_record(example, self.max_seq_len,
|
||||
self.tokenizer)
|
||||
record = self._convert_example_to_record(example, self.max_seq_len, self.tokenizer)
|
||||
max_len = max(max_len, len(record.token_ids))
|
||||
if self.in_tokens:
|
||||
to_append = (len(batch_records) + 1) * max_len <= batch_size
|
||||
@@ -233,25 +225,18 @@ class BaseReader(object):
|
||||
# return len(examples)
|
||||
return self.num_examples
|
||||
|
||||
def data_generator(self,
|
||||
input_file,
|
||||
batch_size,
|
||||
epoch,
|
||||
dev_count=1,
|
||||
trainer_id=0,
|
||||
trainer_num=1,
|
||||
shuffle=True,
|
||||
phase=None):
|
||||
def data_generator(
|
||||
self, input_file, batch_size, epoch, dev_count=1, trainer_id=0, trainer_num=1, shuffle=True, phase=None
|
||||
):
|
||||
|
||||
if phase == 'train':
|
||||
if phase == "train":
|
||||
# examples = examples[trainer_id: (len(examples) //trainer_num) * trainer_num : trainer_num]
|
||||
self.num_examples_per_node = self.total_num // trainer_num
|
||||
self.num_examples = self.num_examples_per_node * trainer_num
|
||||
examples = self._read_tsv(input_file,
|
||||
trainer_id=trainer_id,
|
||||
trainer_num=trainer_num,
|
||||
num_examples=self.num_examples_per_node)
|
||||
log.info('apply sharding %d/%d' % (trainer_id, trainer_num))
|
||||
examples = self._read_tsv(
|
||||
input_file, trainer_id=trainer_id, trainer_num=trainer_num, num_examples=self.num_examples_per_node
|
||||
)
|
||||
log.info("apply sharding %d/%d" % (trainer_id, trainer_num))
|
||||
else:
|
||||
examples = self._read_tsv(input_file)
|
||||
|
||||
@@ -264,9 +249,7 @@ class BaseReader(object):
|
||||
if shuffle:
|
||||
np.random.shuffle(examples)
|
||||
|
||||
for batch_data in self._prepare_batch_data(examples,
|
||||
batch_size,
|
||||
phase=phase):
|
||||
for batch_data in self._prepare_batch_data(examples, batch_size, phase=phase):
|
||||
if len(all_dev_batches) < dev_count:
|
||||
all_dev_batches.append(batch_data)
|
||||
if len(all_dev_batches) == dev_count:
|
||||
@@ -280,30 +263,21 @@ class BaseReader(object):
|
||||
yield i
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
|
||||
return f
|
||||
|
||||
|
||||
class ClassifyReader(BaseReader):
|
||||
|
||||
def _read_tsv(self,
|
||||
input_file,
|
||||
quotechar=None,
|
||||
trainer_id=0,
|
||||
trainer_num=1,
|
||||
num_examples=0):
|
||||
def _read_tsv(self, input_file, quotechar=None, trainer_id=0, trainer_num=1, num_examples=0):
|
||||
"""Reads a tab separated value file."""
|
||||
with open(input_file, 'r', encoding='utf8') as f:
|
||||
reader = csv_reader(f,
|
||||
trainer_id=trainer_id,
|
||||
trainer_num=trainer_num)
|
||||
with open(input_file, "r", encoding="utf8") as f:
|
||||
reader = csv_reader(f, trainer_id=trainer_id, trainer_num=trainer_num)
|
||||
# headers = next(reader)
|
||||
headers = 'query\ttitle\tpara\tlabel'.split('\t')
|
||||
text_indices = [
|
||||
index for index, h in enumerate(headers) if h != "label"
|
||||
]
|
||||
Example = namedtuple('Example', headers)
|
||||
headers = "query\ttitle\tpara\tlabel".split("\t")
|
||||
text_indices = [index for index, h in enumerate(headers) if h != "label"]
|
||||
Example = namedtuple("Example", headers)
|
||||
|
||||
examples = []
|
||||
for cnt, line in enumerate(reader):
|
||||
@@ -312,7 +286,7 @@ class ClassifyReader(BaseReader):
|
||||
for index, text in enumerate(line):
|
||||
if index in text_indices:
|
||||
if self.for_cn:
|
||||
line[index] = text.replace(' ', '')
|
||||
line[index] = text.replace(" ", "")
|
||||
else:
|
||||
line[index] = text
|
||||
example = Example(*line)
|
||||
@@ -326,31 +300,21 @@ class ClassifyReader(BaseReader):
|
||||
|
||||
if not self.is_inference:
|
||||
batch_labels = [record.label_id for record in batch_records]
|
||||
batch_labels = np.array(batch_labels).astype("int64").reshape(
|
||||
[-1, 1])
|
||||
batch_labels = np.array(batch_labels).astype("int64").reshape([-1, 1])
|
||||
|
||||
if batch_records[0].qid:
|
||||
batch_qids = [record.qid for record in batch_records]
|
||||
batch_qids = np.array(batch_qids).astype("int64").reshape(
|
||||
[-1, 1])
|
||||
batch_qids = np.array(batch_qids).astype("int64").reshape([-1, 1])
|
||||
else:
|
||||
batch_qids = np.array([]).astype("int64").reshape([-1, 1])
|
||||
|
||||
# padding
|
||||
padded_token_ids, input_mask = pad_batch_data(batch_token_ids,
|
||||
pad_idx=self.pad_id,
|
||||
return_input_mask=True)
|
||||
padded_text_type_ids = pad_batch_data(batch_text_type_ids,
|
||||
pad_idx=self.pad_id)
|
||||
padded_position_ids = pad_batch_data(batch_position_ids,
|
||||
pad_idx=self.pad_id)
|
||||
padded_task_ids = np.ones_like(padded_token_ids,
|
||||
dtype="int64") * self.task_id
|
||||
padded_token_ids, input_mask = pad_batch_data(batch_token_ids, pad_idx=self.pad_id, return_input_mask=True)
|
||||
padded_text_type_ids = pad_batch_data(batch_text_type_ids, pad_idx=self.pad_id)
|
||||
padded_position_ids = pad_batch_data(batch_position_ids, pad_idx=self.pad_id)
|
||||
padded_task_ids = np.ones_like(padded_token_ids, dtype="int64") * self.task_id
|
||||
|
||||
return_list = [
|
||||
padded_token_ids, padded_text_type_ids, padded_position_ids,
|
||||
padded_task_ids, input_mask
|
||||
]
|
||||
return_list = [padded_token_ids, padded_text_type_ids, padded_position_ids, padded_task_ids, input_mask]
|
||||
if not self.is_inference:
|
||||
return_list += [batch_labels, batch_qids]
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ def printable_text(text):
|
||||
def load_vocab(vocab_file):
|
||||
"""Loads a vocabulary file into a dictionary."""
|
||||
vocab = collections.OrderedDict()
|
||||
with open(vocab_file, encoding='utf8') as fin:
|
||||
with open(vocab_file, encoding="utf8") as fin:
|
||||
for num, line in enumerate(fin):
|
||||
items = convert_to_unicode(line.strip()).split("\t")
|
||||
if len(items) > 2:
|
||||
@@ -245,14 +245,16 @@ class BasicTokenizer(object):
|
||||
# as is Japanese Hiragana and Katakana. Those alphabets are used to write
|
||||
# space-separated words, so they are not treated specially and handled
|
||||
# like the all of the other languages.
|
||||
if ((cp >= 0x4E00 and cp <= 0x9FFF) or #
|
||||
(cp >= 0x3400 and cp <= 0x4DBF) or #
|
||||
(cp >= 0x20000 and cp <= 0x2A6DF) or #
|
||||
(cp >= 0x2A700 and cp <= 0x2B73F) or #
|
||||
(cp >= 0x2B740 and cp <= 0x2B81F) or #
|
||||
(cp >= 0x2B820 and cp <= 0x2CEAF) or
|
||||
(cp >= 0xF900 and cp <= 0xFAFF) or #
|
||||
(cp >= 0x2F800 and cp <= 0x2FA1F)): #
|
||||
if (
|
||||
(cp >= 0x4E00 and cp <= 0x9FFF)
|
||||
or (cp >= 0x3400 and cp <= 0x4DBF) #
|
||||
or (cp >= 0x20000 and cp <= 0x2A6DF) #
|
||||
or (cp >= 0x2A700 and cp <= 0x2B73F) #
|
||||
or (cp >= 0x2B740 and cp <= 0x2B81F) #
|
||||
or (cp >= 0x2B820 and cp <= 0x2CEAF) #
|
||||
or (cp >= 0xF900 and cp <= 0xFAFF)
|
||||
or (cp >= 0x2F800 and cp <= 0x2FA1F) #
|
||||
): #
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -262,7 +264,7 @@ class BasicTokenizer(object):
|
||||
output = []
|
||||
for char in text:
|
||||
cp = ord(char)
|
||||
if cp == 0 or cp == 0xfffd or _is_control(char):
|
||||
if cp == 0 or cp == 0xFFFD or _is_control(char):
|
||||
continue
|
||||
if _is_whitespace(char):
|
||||
output.append(" ")
|
||||
@@ -364,8 +366,7 @@ def _is_punctuation(char):
|
||||
# Characters such as "^", "$", and "`" are not in the Unicode
|
||||
# Punctuation class but we treat them as punctuation anyways, for
|
||||
# consistency.
|
||||
if ((cp >= 33 and cp <= 47) or (cp >= 58 and cp <= 64)
|
||||
or (cp >= 91 and cp <= 96) or (cp >= 123 and cp <= 126)):
|
||||
if (cp >= 33 and cp <= 47) or (cp >= 58 and cp <= 64) or (cp >= 91 and cp <= 96) or (cp >= 123 and cp <= 126):
|
||||
return True
|
||||
cat = unicodedata.category(char)
|
||||
if cat.startswith("P"):
|
||||
@@ -386,14 +387,16 @@ def tokenize_chinese_chars(text):
|
||||
# as is Japanese Hiragana and Katakana. Those alphabets are used to write
|
||||
# space-separated words, so they are not treated specially and handled
|
||||
# like the all of the other languages.
|
||||
if ((cp >= 0x4E00 and cp <= 0x9FFF) or #
|
||||
(cp >= 0x3400 and cp <= 0x4DBF) or #
|
||||
(cp >= 0x20000 and cp <= 0x2A6DF) or #
|
||||
(cp >= 0x2A700 and cp <= 0x2B73F) or #
|
||||
(cp >= 0x2B740 and cp <= 0x2B81F) or #
|
||||
(cp >= 0x2B820 and cp <= 0x2CEAF) or
|
||||
(cp >= 0xF900 and cp <= 0xFAFF) or #
|
||||
(cp >= 0x2F800 and cp <= 0x2FA1F)): #
|
||||
if (
|
||||
(cp >= 0x4E00 and cp <= 0x9FFF)
|
||||
or (cp >= 0x3400 and cp <= 0x4DBF) #
|
||||
or (cp >= 0x20000 and cp <= 0x2A6DF) #
|
||||
or (cp >= 0x2A700 and cp <= 0x2B73F) #
|
||||
or (cp >= 0x2B740 and cp <= 0x2B81F) #
|
||||
or (cp >= 0x2B820 and cp <= 0x2CEAF) #
|
||||
or (cp >= 0xF900 and cp <= 0xFAFF)
|
||||
or (cp >= 0x2F800 and cp <= 0x2FA1F) #
|
||||
): #
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -28,11 +28,12 @@ import multiprocessing
|
||||
# NOTE(paddle-dev): All of these flags should be
|
||||
# set before `import paddle`. Otherwise, it would
|
||||
# not take any effect.
|
||||
os.environ['FLAGS_eager_delete_tensor_gb'] = '0' # enable gc
|
||||
os.environ["FLAGS_eager_delete_tensor_gb"] = "0" # enable gc
|
||||
|
||||
import paddle
|
||||
import paddle.fluid as fluid
|
||||
if hasattr(paddle, 'enable_static'):
|
||||
|
||||
if hasattr(paddle, "enable_static"):
|
||||
paddle.enable_static()
|
||||
from paddle.fluid.incubate.fleet.collective import fleet, DistributedStrategy
|
||||
import paddle.fluid.incubate.fleet.base.role_maker as role_maker
|
||||
@@ -60,23 +61,24 @@ def main(args):
|
||||
dev_count = len(dev_list)
|
||||
else:
|
||||
place = fluid.CPUPlace()
|
||||
dev_count = int(os.environ.get('CPU_NUM', multiprocessing.cpu_count()))
|
||||
dev_count = int(os.environ.get("CPU_NUM", multiprocessing.cpu_count()))
|
||||
exe = fluid.Executor(place)
|
||||
|
||||
reader = reader_ce.ClassifyReader(vocab_path=args.vocab_path,
|
||||
label_map_config=args.label_map_config,
|
||||
max_seq_len=args.max_seq_len,
|
||||
total_num=args.train_data_size,
|
||||
do_lower_case=args.do_lower_case,
|
||||
in_tokens=args.in_tokens,
|
||||
random_seed=args.random_seed,
|
||||
tokenizer=args.tokenizer,
|
||||
for_cn=args.for_cn,
|
||||
task_id=args.task_id)
|
||||
reader = reader_ce.ClassifyReader(
|
||||
vocab_path=args.vocab_path,
|
||||
label_map_config=args.label_map_config,
|
||||
max_seq_len=args.max_seq_len,
|
||||
total_num=args.train_data_size,
|
||||
do_lower_case=args.do_lower_case,
|
||||
in_tokens=args.in_tokens,
|
||||
random_seed=args.random_seed,
|
||||
tokenizer=args.tokenizer,
|
||||
for_cn=args.for_cn,
|
||||
task_id=args.task_id,
|
||||
)
|
||||
|
||||
if not (args.do_train or args.do_val or args.do_test):
|
||||
raise ValueError("For args `do_train`, `do_val` and `do_test`, at "
|
||||
"least one of them must be True.")
|
||||
raise ValueError("For args `do_train`, `do_val` and `do_test`, at " "least one of them must be True.")
|
||||
|
||||
if args.do_test:
|
||||
assert args.test_save is not None
|
||||
@@ -100,13 +102,13 @@ def main(args):
|
||||
trainer_id=fleet.worker_index(),
|
||||
trainer_num=fleet.worker_num(),
|
||||
shuffle=True,
|
||||
phase="train")
|
||||
phase="train",
|
||||
)
|
||||
|
||||
num_train_examples = reader.get_num_examples(args.train_set)
|
||||
|
||||
if args.in_tokens:
|
||||
max_train_steps = args.epoch * num_train_examples // (
|
||||
args.batch_size // args.max_seq_len) // dev_count
|
||||
max_train_steps = args.epoch * num_train_examples // (args.batch_size // args.max_seq_len) // dev_count
|
||||
else:
|
||||
max_train_steps = args.epoch * num_train_examples // args.batch_size // dev_count
|
||||
|
||||
@@ -141,9 +143,8 @@ def main(args):
|
||||
with fluid.program_guard(train_program, startup_prog):
|
||||
with fluid.unique_name.guard():
|
||||
train_pyreader, graph_vars = create_model(
|
||||
args,
|
||||
pyreader_name='train_reader',
|
||||
ernie_config=ernie_config)
|
||||
args, pyreader_name="train_reader", ernie_config=ernie_config
|
||||
)
|
||||
scheduled_lr = optimization(
|
||||
loss=graph_vars["loss"],
|
||||
warmup_steps=warmup_steps,
|
||||
@@ -158,28 +159,27 @@ def main(args):
|
||||
decr_every_n_nan_or_inf=args.decr_every_n_nan_or_inf,
|
||||
incr_ratio=args.incr_ratio,
|
||||
decr_ratio=args.decr_ratio,
|
||||
dist_strategy=dist_strategy)
|
||||
dist_strategy=dist_strategy,
|
||||
)
|
||||
|
||||
if args.verbose:
|
||||
if args.in_tokens:
|
||||
lower_mem, upper_mem, unit = fluid.contrib.memory_usage(
|
||||
program=train_program,
|
||||
batch_size=args.batch_size // args.max_seq_len)
|
||||
program=train_program, batch_size=args.batch_size // args.max_seq_len
|
||||
)
|
||||
else:
|
||||
lower_mem, upper_mem, unit = fluid.contrib.memory_usage(
|
||||
program=train_program, batch_size=args.batch_size)
|
||||
log.info("Theoretical memory usage in training: %.3f - %.3f %s" %
|
||||
(lower_mem, upper_mem, unit))
|
||||
program=train_program, batch_size=args.batch_size
|
||||
)
|
||||
log.info("Theoretical memory usage in training: %.3f - %.3f %s" % (lower_mem, upper_mem, unit))
|
||||
|
||||
if args.do_val or args.do_test:
|
||||
test_prog = fluid.Program()
|
||||
with fluid.program_guard(test_prog, startup_prog):
|
||||
with fluid.unique_name.guard():
|
||||
test_pyreader, graph_vars = create_model(
|
||||
args,
|
||||
pyreader_name='test_reader',
|
||||
ernie_config=ernie_config,
|
||||
is_prediction=True)
|
||||
args, pyreader_name="test_reader", ernie_config=ernie_config, is_prediction=True
|
||||
)
|
||||
|
||||
test_prog = test_prog.clone(for_test=True)
|
||||
|
||||
@@ -192,19 +192,15 @@ def main(args):
|
||||
if args.init_checkpoint and args.init_pretraining_params:
|
||||
log.warning(
|
||||
"WARNING: args 'init_checkpoint' and 'init_pretraining_params' "
|
||||
"both are set! Only arg 'init_checkpoint' is made valid.")
|
||||
"both are set! Only arg 'init_checkpoint' is made valid."
|
||||
)
|
||||
if args.init_checkpoint:
|
||||
init_checkpoint(exe,
|
||||
args.init_checkpoint,
|
||||
main_program=startup_prog)
|
||||
init_checkpoint(exe, args.init_checkpoint, main_program=startup_prog)
|
||||
elif args.init_pretraining_params:
|
||||
init_pretraining_params(exe,
|
||||
args.init_pretraining_params,
|
||||
main_program=startup_prog)
|
||||
init_pretraining_params(exe, args.init_pretraining_params, main_program=startup_prog)
|
||||
elif args.do_val or args.do_test:
|
||||
if not args.init_checkpoint:
|
||||
raise ValueError("args 'init_checkpoint' should be set if"
|
||||
"only doing validation or testing!")
|
||||
raise ValueError("args 'init_checkpoint' should be set if" "only doing validation or testing!")
|
||||
init_checkpoint(exe, args.init_checkpoint, main_program=startup_prog)
|
||||
|
||||
if args.do_train:
|
||||
@@ -237,19 +233,15 @@ def main(args):
|
||||
train_exe.run(fetch_list=[], program=train_program)
|
||||
|
||||
else:
|
||||
outputs = evaluate(train_exe,
|
||||
train_program,
|
||||
train_pyreader,
|
||||
graph_vars,
|
||||
"train",
|
||||
metric=args.metric)
|
||||
outputs = evaluate(
|
||||
train_exe, train_program, train_pyreader, graph_vars, "train", metric=args.metric
|
||||
)
|
||||
|
||||
if args.verbose:
|
||||
verbose = "train pyreader queue size: %d, " % train_pyreader.queue.size(
|
||||
)
|
||||
verbose = "train pyreader queue size: %d, " % train_pyreader.queue.size()
|
||||
verbose += "learning rate: %f" % (
|
||||
outputs["learning_rate"]
|
||||
if warmup_steps > 0 else args.learning_rate)
|
||||
outputs["learning_rate"] if warmup_steps > 0 else args.learning_rate
|
||||
)
|
||||
log.info(verbose)
|
||||
|
||||
current_example, current_epoch = reader.get_train_progress()
|
||||
@@ -258,47 +250,45 @@ def main(args):
|
||||
|
||||
log.info(
|
||||
"epoch: %d, progress: %d/%d, step: %d, ave loss: %f, "
|
||||
"ave acc: %f, speed: %f steps/s" %
|
||||
(current_epoch, current_example * dev_count,
|
||||
num_train_examples, steps, outputs["loss"],
|
||||
outputs["accuracy"], args.skip_steps / used_time))
|
||||
ce_info.append(
|
||||
[outputs["loss"], outputs["accuracy"], used_time])
|
||||
"ave acc: %f, speed: %f steps/s"
|
||||
% (
|
||||
current_epoch,
|
||||
current_example * dev_count,
|
||||
num_train_examples,
|
||||
steps,
|
||||
outputs["loss"],
|
||||
outputs["accuracy"],
|
||||
args.skip_steps / used_time,
|
||||
)
|
||||
)
|
||||
ce_info.append([outputs["loss"], outputs["accuracy"], used_time])
|
||||
|
||||
time_begin = time.time()
|
||||
|
||||
if steps % args.save_steps == 0:
|
||||
save_path = os.path.join(args.checkpoints,
|
||||
"step_" + str(steps))
|
||||
fluid.io.save_persistables(exe, save_path,
|
||||
fleet._origin_program)
|
||||
save_path = os.path.join(args.checkpoints, "step_" + str(steps))
|
||||
fluid.io.save_persistables(exe, save_path, fleet._origin_program)
|
||||
|
||||
if steps % args.validation_steps == 0:
|
||||
# evaluate dev set
|
||||
if args.do_val:
|
||||
evaluate_wrapper(args, reader, exe, test_prog,
|
||||
test_pyreader, graph_vars,
|
||||
current_epoch, steps)
|
||||
evaluate_wrapper(args, reader, exe, test_prog, test_pyreader, graph_vars, current_epoch, steps)
|
||||
|
||||
if args.do_test:
|
||||
predict_wrapper(args, reader, exe, test_prog,
|
||||
test_pyreader, graph_vars,
|
||||
current_epoch, steps)
|
||||
predict_wrapper(args, reader, exe, test_prog, test_pyreader, graph_vars, current_epoch, steps)
|
||||
|
||||
if last_epoch != current_epoch:
|
||||
last_epoch = current_epoch
|
||||
|
||||
except fluid.core.EOFException:
|
||||
save_path = os.path.join(args.checkpoints, "step_" + str(steps))
|
||||
fluid.io.save_persistables(exe, save_path,
|
||||
fleet._origin_program)
|
||||
fluid.io.save_persistables(exe, save_path, fleet._origin_program)
|
||||
train_pyreader.reset()
|
||||
break
|
||||
|
||||
# final eval on dev set
|
||||
if args.do_val:
|
||||
evaluate_wrapper(args, reader, exe, test_prog, test_pyreader,
|
||||
graph_vars, current_epoch, steps)
|
||||
evaluate_wrapper(args, reader, exe, test_prog, test_pyreader, graph_vars, current_epoch, steps)
|
||||
|
||||
# final eval on test set
|
||||
if args.do_test:
|
||||
@@ -307,68 +297,42 @@ def main(args):
|
||||
# final eval on dianostic, hack for glue-ax
|
||||
if args.diagnostic:
|
||||
test_pyreader.decorate_tensor_provider(
|
||||
reader.data_generator(args.diagnostic,
|
||||
batch_size=args.batch_size,
|
||||
epoch=1,
|
||||
dev_count=1,
|
||||
shuffle=False))
|
||||
reader.data_generator(args.diagnostic, batch_size=args.batch_size, epoch=1, dev_count=1, shuffle=False)
|
||||
)
|
||||
|
||||
log.info("Final diagnostic")
|
||||
qids, preds, probs = predict(test_exe, test_prog, test_pyreader,
|
||||
graph_vars)
|
||||
assert len(qids) == len(preds), '{} v.s. {}'.format(
|
||||
len(qids), len(preds))
|
||||
with open(args.diagnostic_save, 'w') as f:
|
||||
qids, preds, probs = predict(test_exe, test_prog, test_pyreader, graph_vars)
|
||||
assert len(qids) == len(preds), "{} v.s. {}".format(len(qids), len(preds))
|
||||
with open(args.diagnostic_save, "w") as f:
|
||||
for id, s, p in zip(qids, preds, probs):
|
||||
f.write('{}\t{}\t{}\n'.format(id, s, p))
|
||||
f.write("{}\t{}\t{}\n".format(id, s, p))
|
||||
|
||||
log.info("Done final diagnostic, saving to {}".format(
|
||||
args.diagnostic_save))
|
||||
log.info("Done final diagnostic, saving to {}".format(args.diagnostic_save))
|
||||
|
||||
|
||||
def evaluate_wrapper(args, reader, exe, test_prog, test_pyreader, graph_vars,
|
||||
epoch, steps):
|
||||
def evaluate_wrapper(args, reader, exe, test_prog, test_pyreader, graph_vars, epoch, steps):
|
||||
# evaluate dev set
|
||||
for ds in args.dev_set.split(','):
|
||||
for ds in args.dev_set.split(","):
|
||||
test_pyreader.decorate_tensor_provider(
|
||||
reader.data_generator(ds,
|
||||
batch_size=args.predict_batch_size,
|
||||
epoch=1,
|
||||
dev_count=1,
|
||||
shuffle=False))
|
||||
reader.data_generator(ds, batch_size=args.predict_batch_size, epoch=1, dev_count=1, shuffle=False)
|
||||
)
|
||||
log.info("validation result of dataset {}:".format(ds))
|
||||
evaluate_info = evaluate(exe,
|
||||
test_prog,
|
||||
test_pyreader,
|
||||
graph_vars,
|
||||
"dev",
|
||||
metric=args.metric)
|
||||
log.info(evaluate_info +
|
||||
', file: {}, epoch: {}, steps: {}'.format(ds, epoch, steps))
|
||||
evaluate_info = evaluate(exe, test_prog, test_pyreader, graph_vars, "dev", metric=args.metric)
|
||||
log.info(evaluate_info + ", file: {}, epoch: {}, steps: {}".format(ds, epoch, steps))
|
||||
|
||||
|
||||
def predict_wrapper(args,
|
||||
reader,
|
||||
exe,
|
||||
test_prog,
|
||||
test_pyreader,
|
||||
graph_vars,
|
||||
epoch=None,
|
||||
steps=None):
|
||||
test_sets = args.test_set.split(',')
|
||||
save_dirs = args.test_save.split(',')
|
||||
def predict_wrapper(args, reader, exe, test_prog, test_pyreader, graph_vars, epoch=None, steps=None):
|
||||
test_sets = args.test_set.split(",")
|
||||
save_dirs = args.test_save.split(",")
|
||||
assert len(test_sets) == len(save_dirs)
|
||||
|
||||
for test_f, save_f in zip(test_sets, save_dirs):
|
||||
test_pyreader.decorate_tensor_provider(
|
||||
reader.data_generator(test_f,
|
||||
batch_size=args.predict_batch_size,
|
||||
epoch=1,
|
||||
dev_count=1,
|
||||
shuffle=False))
|
||||
reader.data_generator(test_f, batch_size=args.predict_batch_size, epoch=1, dev_count=1, shuffle=False)
|
||||
)
|
||||
|
||||
if epoch is not None or steps is not None:
|
||||
save_path = save_f + '.' + str(epoch) + '.' + str(steps)
|
||||
save_path = save_f + "." + str(epoch) + "." + str(steps)
|
||||
else:
|
||||
save_path = save_f
|
||||
log.info("testing {}, save to {}".format(test_f, save_path))
|
||||
@@ -378,14 +342,14 @@ def predict_wrapper(args,
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
else:
|
||||
log.warning('save dir exsits: %s, will skip saving' % save_dir)
|
||||
log.warning("save dir exsits: %s, will skip saving" % save_dir)
|
||||
|
||||
with open(save_path, 'w') as f:
|
||||
with open(save_path, "w") as f:
|
||||
for p in probs:
|
||||
f.write('{}\n'.format(p[1]))
|
||||
f.write("{}\n".format(p[1]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
prepare_logger(log)
|
||||
print_arguments(args)
|
||||
check_cuda(args.use_cuda)
|
||||
|
||||
@@ -30,10 +30,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def prepare_logger(logger, debug=False, save_to_file=None):
|
||||
formatter = logging.Formatter(
|
||||
fmt=
|
||||
'[%(levelname)s] %(asctime)s [%(filename)12s:%(lineno)5d]:\t%(message)s'
|
||||
)
|
||||
formatter = logging.Formatter(fmt="[%(levelname)s] %(asctime)s [%(filename)12s:%(lineno)5d]:\t%(message)s")
|
||||
console_hdl = logging.StreamHandler()
|
||||
console_hdl.setFormatter(formatter)
|
||||
logger.addHandler(console_hdl)
|
||||
@@ -52,37 +49,29 @@ def str2bool(v):
|
||||
|
||||
|
||||
class ArgumentGroup(object):
|
||||
|
||||
def __init__(self, parser, title, des):
|
||||
self._group = parser.add_argument_group(title=title, description=des)
|
||||
|
||||
def add_arg(self,
|
||||
name,
|
||||
type,
|
||||
default,
|
||||
help,
|
||||
positional_arg=False,
|
||||
**kwargs):
|
||||
def add_arg(self, name, type, default, help, positional_arg=False, **kwargs):
|
||||
prefix = "" if positional_arg else "--"
|
||||
type = str2bool if type == bool else type
|
||||
self._group.add_argument(prefix + name,
|
||||
default=default,
|
||||
type=type,
|
||||
help=help + ' Default: %(default)s.',
|
||||
**kwargs)
|
||||
self._group.add_argument(
|
||||
prefix + name, default=default, type=type, help=help + " Default: %(default)s.", **kwargs
|
||||
)
|
||||
|
||||
|
||||
def print_arguments(args):
|
||||
log.info('----------- Configuration Arguments -----------')
|
||||
log.info("----------- Configuration Arguments -----------")
|
||||
for arg, value in sorted(six.iteritems(vars(args))):
|
||||
log.info('%s: %s' % (arg, value))
|
||||
log.info('------------------------------------------------')
|
||||
log.info("%s: %s" % (arg, value))
|
||||
log.info("------------------------------------------------")
|
||||
|
||||
|
||||
def check_cuda(use_cuda, err = \
|
||||
"\nYou can not set use_cuda = True in the model because you are using paddlepaddle-cpu.\n \
|
||||
Please: 1. Install paddlepaddle-gpu to run your models on GPU or 2. Set use_cuda = False to run models on CPU.\n"
|
||||
):
|
||||
def check_cuda(
|
||||
use_cuda,
|
||||
err="\nYou can not set use_cuda = True in the model because you are using paddlepaddle-cpu.\n \
|
||||
Please: 1. Install paddlepaddle-gpu to run your models on GPU or 2. Set use_cuda = False to run models on CPU.\n",
|
||||
):
|
||||
try:
|
||||
if use_cuda == True and fluid.is_compiled_with_cuda() == False:
|
||||
log.error(err)
|
||||
|
||||
@@ -31,43 +31,32 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def init_checkpoint(exe, init_checkpoint_path, main_program):
|
||||
assert os.path.exists(
|
||||
init_checkpoint_path), "[%s] cann't be found." % init_checkpoint_path
|
||||
assert os.path.exists(init_checkpoint_path), "[%s] cann't be found." % init_checkpoint_path
|
||||
|
||||
def existed_persitables(var):
|
||||
if not fluid.io.is_persistable(var):
|
||||
return False
|
||||
if not os.path.exists(os.path.join(init_checkpoint_path, var.name)):
|
||||
print("Var not exists: [%s]\t%s" %
|
||||
(var.name, os.path.join(init_checkpoint_path, var.name)))
|
||||
#else:
|
||||
print("Var not exists: [%s]\t%s" % (var.name, os.path.join(init_checkpoint_path, var.name)))
|
||||
# else:
|
||||
# print ("Var exists: [%s]" % (var.name))
|
||||
return os.path.exists(os.path.join(init_checkpoint_path, var.name))
|
||||
|
||||
fluid.io.load_vars(exe,
|
||||
init_checkpoint_path,
|
||||
main_program=main_program,
|
||||
predicate=existed_persitables)
|
||||
fluid.io.load_vars(exe, init_checkpoint_path, main_program=main_program, predicate=existed_persitables)
|
||||
log.info("Load model from {}".format(init_checkpoint_path))
|
||||
|
||||
|
||||
def init_pretraining_params(exe, pretraining_params_path, main_program):
|
||||
assert os.path.exists(pretraining_params_path
|
||||
), "[%s] cann't be found." % pretraining_params_path
|
||||
assert os.path.exists(pretraining_params_path), "[%s] cann't be found." % pretraining_params_path
|
||||
|
||||
def existed_params(var):
|
||||
if not isinstance(var, fluid.framework.Parameter):
|
||||
return False
|
||||
if not os.path.exists(os.path.join(pretraining_params_path, var.name)):
|
||||
print("Var not exists: [%s]\t%s" %
|
||||
(var.name, os.path.join(pretraining_params_path, var.name)))
|
||||
#else:
|
||||
print("Var not exists: [%s]\t%s" % (var.name, os.path.join(pretraining_params_path, var.name)))
|
||||
# else:
|
||||
# print ("Var exists: [%s]" % (var.name))
|
||||
return os.path.exists(os.path.join(pretraining_params_path, var.name))
|
||||
|
||||
fluid.io.load_vars(exe,
|
||||
pretraining_params_path,
|
||||
main_program=main_program,
|
||||
predicate=existed_params)
|
||||
log.info(
|
||||
"Load pretraining parameters from {}.".format(pretraining_params_path))
|
||||
fluid.io.load_vars(exe, pretraining_params_path, main_program=main_program, predicate=existed_params)
|
||||
log.info("Load pretraining parameters from {}.".format(pretraining_params_path))
|
||||
|
||||
@@ -15,16 +15,12 @@ import numpy as np
|
||||
import paddle
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
is_test=False,
|
||||
is_pair=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, is_test=False, is_pair=False):
|
||||
"""
|
||||
Builds model inputs from a sequence or a pair of sequence for sequence classification tasks
|
||||
by concatenating and adding special tokens. And creates a mask from the two sequences passed
|
||||
by concatenating and adding special tokens. And creates a mask from the two sequences passed
|
||||
to be used in a sequence-pair classification task.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
@@ -34,9 +30,9 @@ def convert_example(example,
|
||||
|
||||
Args:
|
||||
example(obj:`list[str]`): List of input data, containing text and label if it have label.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -52,9 +48,7 @@ def convert_example(example,
|
||||
else:
|
||||
text = example["text"]
|
||||
text_pair = None
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
text_pair=text_pair,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=text, text_pair=text_pair, max_seq_len=max_seq_length)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
|
||||
@@ -66,51 +60,40 @@ def convert_example(example,
|
||||
|
||||
def read_text_pair(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1]}
|
||||
yield {"text_a": data[0], "text_b": data[1]}
|
||||
|
||||
|
||||
def read_data(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
with open(data_path, "r", encoding="utf-8", errors="ignore") as f:
|
||||
for i, line in enumerate(f):
|
||||
# Skip column name
|
||||
if (i == 0):
|
||||
if i == 0:
|
||||
continue
|
||||
data = line.rstrip('\n').split("\t")
|
||||
if (len(data) != 3):
|
||||
data = line.rstrip("\n").split("\t")
|
||||
if len(data) != 3:
|
||||
print(data)
|
||||
continue
|
||||
query = data[0]
|
||||
title = data[1]
|
||||
label = data[-1]
|
||||
# breakpoint()
|
||||
yield {'text_a': query, 'text_b': title, 'label': int(label)}
|
||||
yield {"text_a": query, "text_b": title, "label": int(label)}
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
@@ -29,9 +29,7 @@ import paddlenlp as ppnlp
|
||||
def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
|
||||
@@ -39,34 +37,29 @@ def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
|
||||
# 启动python客户端
|
||||
endpoint_list = ['127.0.0.1:8600']
|
||||
endpoint_list = ["127.0.0.1:8600"]
|
||||
client = HttpClient()
|
||||
client.load_client_config('serving_client')
|
||||
client.load_client_config("serving_client")
|
||||
client.connect(endpoint_list)
|
||||
feed_names = client.feed_names_
|
||||
fetch_names = client.fetch_names_
|
||||
|
||||
# 创建tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained('rocketqa-base-cross-encoder')
|
||||
tokenizer = AutoTokenizer.from_pretrained("rocketqa-base-cross-encoder")
|
||||
max_seq_len = 64
|
||||
|
||||
# 数据预处理
|
||||
list_data = [{
|
||||
"query": "加强科研项目管理有效促进医学科研工作",
|
||||
"title": "科研项目管理策略科研项目,项目管理,实施,必要性,策略"
|
||||
}]
|
||||
list_data = [{"query": "加强科研项目管理有效促进医学科研工作", "title": "科研项目管理策略科研项目,项目管理,实施,必要性,策略"}]
|
||||
|
||||
input_ids, token_type_ids = [], []
|
||||
for example in list_data:
|
||||
input_id, token_type_id = convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=max_seq_len)
|
||||
input_id, token_type_id = convert_example(example, tokenizer, max_seq_length=max_seq_len)
|
||||
input_ids.append(input_id)
|
||||
token_type_ids.append(token_type_id)
|
||||
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = np.array(input_ids)
|
||||
feed_dict['token_type_ids'] = np.array(token_type_ids)
|
||||
feed_dict["input_ids"] = np.array(input_ids)
|
||||
feed_dict["token_type_ids"] = np.array(token_type_ids)
|
||||
# batch设置为True表示的是批量预测
|
||||
b_start = time.time()
|
||||
result = client.predict(feed=feed_dict, fetch=fetch_names, batch=True)
|
||||
|
||||
@@ -27,9 +27,7 @@ import paddlenlp as ppnlp
|
||||
def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -38,39 +36,34 @@ def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
|
||||
# 启动python客户端
|
||||
endpoint_list = ['127.0.0.1:8600']
|
||||
endpoint_list = ["127.0.0.1:8600"]
|
||||
client = Client()
|
||||
client.load_client_config('serving_client')
|
||||
client.load_client_config("serving_client")
|
||||
client.connect(endpoint_list)
|
||||
feed_names = client.feed_names_
|
||||
fetch_names = client.fetch_names_
|
||||
|
||||
# 创建tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained('rocketqa-base-cross-encoder')
|
||||
tokenizer = AutoTokenizer.from_pretrained("rocketqa-base-cross-encoder")
|
||||
max_seq_len = 64
|
||||
|
||||
# 数据预处理
|
||||
list_data = [{
|
||||
"query": "加强科研项目管理有效促进医学科研工作",
|
||||
"title": "科研项目管理策略科研项目,项目管理,实施,必要性,策略"
|
||||
}]
|
||||
list_data = [{"query": "加强科研项目管理有效促进医学科研工作", "title": "科研项目管理策略科研项目,项目管理,实施,必要性,策略"}]
|
||||
|
||||
input_ids, token_type_ids = [], []
|
||||
for example in list_data:
|
||||
input_id, token_type_id = convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=max_seq_len)
|
||||
input_id, token_type_id = convert_example(example, tokenizer, max_seq_length=max_seq_len)
|
||||
input_ids.append(input_id)
|
||||
token_type_ids.append(token_type_id)
|
||||
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = np.array(input_ids)
|
||||
feed_dict['token_type_ids'] = np.array(token_type_ids)
|
||||
feed_dict["input_ids"] = np.array(input_ids)
|
||||
feed_dict["token_type_ids"] = np.array(token_type_ids)
|
||||
# batch设置为True表示的是批量预测
|
||||
b_start = time.time()
|
||||
result = client.predict(feed=feed_dict, fetch=fetch_names, batch=True)
|
||||
# breakpoint()
|
||||
sim_score = expit(result['predict'])[:, 1]
|
||||
sim_score = expit(result["predict"])[:, 1]
|
||||
b_end = time.time()
|
||||
print("time to cost :{} seconds".format(b_end - b_start))
|
||||
print(sim_score)
|
||||
|
||||
@@ -29,7 +29,7 @@ from paddlenlp.datasets import load_dataset
|
||||
from paddlenlp.utils.log import logger
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
|
||||
sys.path.append('.')
|
||||
sys.path.append(".")
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -68,21 +68,19 @@ args = parser.parse_args()
|
||||
|
||||
def read_text_pair(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'query': data[0], 'title': data[1]}
|
||||
yield {"query": data[0], "title": data[1]}
|
||||
|
||||
|
||||
def convert_example(example, tokenizer, max_seq_length=512, is_test=False):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -95,16 +93,17 @@ def convert_example(example, tokenizer, max_seq_length=512, is_test=False):
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -123,14 +122,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -146,15 +145,12 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
if args.benchmark:
|
||||
import auto_log
|
||||
|
||||
pid = os.getpid()
|
||||
self.autolog = auto_log.AutoLogger(
|
||||
model_name=args.model_name_or_path,
|
||||
@@ -166,11 +162,10 @@ class Predictor(object):
|
||||
pids=pid,
|
||||
process_name=None,
|
||||
gpu_ids=0,
|
||||
time_keys=[
|
||||
'preprocess_time', 'inference_time', 'postprocess_time'
|
||||
],
|
||||
time_keys=["preprocess_time", "inference_time", "postprocess_time"],
|
||||
warmup=0,
|
||||
logger=logger)
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
def predict(self, data, tokenizer):
|
||||
"""
|
||||
@@ -178,7 +173,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
label_map(obj:`dict`): The label id (key) to label str (value) map.
|
||||
|
||||
@@ -190,17 +185,12 @@ class Predictor(object):
|
||||
|
||||
examples = []
|
||||
for text in data:
|
||||
input_ids, segment_ids = convert_example(
|
||||
text,
|
||||
tokenizer,
|
||||
max_seq_length=self.max_seq_length,
|
||||
is_test=True)
|
||||
input_ids, segment_ids = convert_example(text, tokenizer, max_seq_length=self.max_seq_length, is_test=True)
|
||||
examples.append((input_ids, segment_ids))
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
|
||||
if args.benchmark:
|
||||
@@ -223,27 +213,29 @@ class Predictor(object):
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Define predictor to do prediction.
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
test_ds = load_dataset(read_text_pair,
|
||||
data_path=args.input_file,
|
||||
lazy=False)
|
||||
test_ds = load_dataset(read_text_pair, data_path=args.input_file, lazy=False)
|
||||
|
||||
data = [{'query': d['query'], 'title': d['title']} for d in test_ds]
|
||||
data = [{"query": d["query"], "title": d["title"]} for d in test_ds]
|
||||
|
||||
batches = [
|
||||
data[idx:idx + args.batch_size]
|
||||
for idx in range(0, len(data), args.batch_size)
|
||||
]
|
||||
batches = [data[idx : idx + args.batch_size] for idx in range(0, len(data), args.batch_size)]
|
||||
|
||||
results = []
|
||||
for batch_data in batches:
|
||||
results.extend(predictor.predict(batch_data, tokenizer))
|
||||
for idx, text in enumerate(data):
|
||||
print('Data: {} \t prob: {}'.format(text, results[idx]))
|
||||
print("Data: {} \t prob: {}".format(text, results[idx]))
|
||||
if args.benchmark:
|
||||
predictor.autolog.report()
|
||||
|
||||
@@ -17,12 +17,9 @@ import numpy as np
|
||||
from paddle_serving_server.pipeline import PipelineClient
|
||||
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8089'])
|
||||
client.connect(["127.0.0.1:8089"])
|
||||
|
||||
list_data = [{
|
||||
"query": "加强科研项目管理有效促进医学科研工作",
|
||||
"title": "科研项目管理策略科研项目,项目管理,实施,必要性,策略"
|
||||
}]
|
||||
list_data = [{"query": "加强科研项目管理有效促进医学科研工作", "title": "科研项目管理策略科研项目,项目管理,实施,必要性,策略"}]
|
||||
feed = {}
|
||||
for i, item in enumerate(list_data):
|
||||
feed[str(i)] = str(item)
|
||||
|
||||
@@ -23,9 +23,7 @@ from paddle_serving_server.web_service import WebService, Op
|
||||
def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -34,33 +32,30 @@ def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
|
||||
class ErnieOp(Op):
|
||||
|
||||
def init_op(self):
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
self.tokenizer = AutoTokenizer.from_pretrained(
|
||||
'rocketqa-base-cross-encoder')
|
||||
|
||||
self.tokenizer = AutoTokenizer.from_pretrained("rocketqa-base-cross-encoder")
|
||||
|
||||
def preprocess(self, input_dicts, data_id, log_id):
|
||||
from paddlenlp.data import Stack, Tuple, Pad
|
||||
|
||||
(_, input_dict), = input_dicts.items()
|
||||
((_, input_dict),) = input_dicts.items()
|
||||
print("input dict", input_dict)
|
||||
batch_size = len(input_dict.keys())
|
||||
examples = []
|
||||
for i in range(batch_size):
|
||||
example = json.loads(input_dict[str(i)].replace("\'", "\""))
|
||||
example = json.loads(input_dict[str(i)].replace("'", '"'))
|
||||
input_ids, segment_ids = convert_example(example, self.tokenizer)
|
||||
examples.append((input_ids, segment_ids))
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = input_ids
|
||||
feed_dict['token_type_ids'] = segment_ids
|
||||
feed_dict["input_ids"] = input_ids
|
||||
feed_dict["token_type_ids"] = segment_ids
|
||||
return feed_dict, False, None, ""
|
||||
|
||||
def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
|
||||
@@ -71,7 +66,6 @@ class ErnieOp(Op):
|
||||
|
||||
|
||||
class ErnieService(WebService):
|
||||
|
||||
def get_pipeline_response(self, read_op):
|
||||
ernie_op = ErnieOp(name="ernie", input_ops=[read_op])
|
||||
return ernie_op
|
||||
|
||||
@@ -87,35 +87,26 @@ def main():
|
||||
|
||||
dev_ds = load_dataset(read_data, data_path=args.test_file, lazy=False)
|
||||
|
||||
model = AutoModelForSequenceClassification.from_pretrained(
|
||||
args.model_name_or_path, num_classes=2)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(args.model_name_or_path, num_classes=2)
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func_eval = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
is_pair=True)
|
||||
trans_func_eval = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length, is_pair=True)
|
||||
|
||||
batchify_fn_eval = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # pair_segment
|
||||
Stack(dtype="int64") # label
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # pair_segment
|
||||
Stack(dtype="int64"), # label
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
dev_data_loader = create_dataloader(dev_ds,
|
||||
mode='dev',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn_eval,
|
||||
trans_fn=trans_func_eval)
|
||||
dev_data_loader = create_dataloader(
|
||||
dev_ds, mode="dev", batch_size=args.batch_size, batchify_fn=batchify_fn_eval, trans_fn=trans_func_eval
|
||||
)
|
||||
|
||||
if args.init_from_ckpt and os.path.isfile(args.init_from_ckpt):
|
||||
state_dict = paddle.load(args.init_from_ckpt)
|
||||
model.set_dict(state_dict)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
metric = paddle.metric.Auc()
|
||||
evaluate(model, metric, dev_data_loader, "dev")
|
||||
|
||||
@@ -31,27 +31,24 @@ args = parser.parse_args()
|
||||
|
||||
if __name__ == "__main__":
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(
|
||||
args.model_name_or_path, num_classes=2)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(args.model_name_or_path, num_classes=2)
|
||||
|
||||
if args.params_path and os.path.isfile(args.params_path):
|
||||
state_dict = paddle.load(args.params_path)
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
model.eval()
|
||||
|
||||
# Convert to static graph with specific input description
|
||||
model = paddle.jit.to_static(
|
||||
model,
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64") # segment_ids
|
||||
])
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # segment_ids
|
||||
],
|
||||
)
|
||||
# Save in static graph model.
|
||||
save_path = os.path.join(args.output_path, "inference")
|
||||
paddle.jit.save(model, save_path)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import argparse
|
||||
import paddle_serving_client.io as serving_io
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dirname", type=str, required=True,
|
||||
@@ -44,4 +45,5 @@ if __name__ == "__main__":
|
||||
params_filename=args.params_filename,
|
||||
show_proto=args.show_proto,
|
||||
feed_alias_names=args.feed_alias_names,
|
||||
fetch_alias_names=args.fetch_alias_names)
|
||||
fetch_alias_names=args.fetch_alias_names,
|
||||
)
|
||||
|
||||
@@ -57,35 +57,28 @@ if __name__ == "__main__":
|
||||
paddle.set_device(args.device)
|
||||
|
||||
test_ds = load_dataset(read_text_pair, data_path=args.test_set, lazy=False)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(
|
||||
args.model_name_or_path, num_classes=2)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(args.model_name_or_path, num_classes=2)
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
is_test=True,
|
||||
is_pair=True)
|
||||
trans_func = partial(
|
||||
convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length, is_test=True, is_pair=True
|
||||
)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
test_data_loader = create_dataloader(test_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
test_data_loader = create_dataloader(
|
||||
test_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
if args.params_path and os.path.isfile(args.params_path):
|
||||
state_dict = paddle.load(args.params_path)
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
results = predict(model, test_data_loader)
|
||||
test_ds = load_dataset(read_text_pair, data_path=args.test_set, lazy=False)
|
||||
text_pairs = []
|
||||
@@ -93,7 +86,6 @@ if __name__ == "__main__":
|
||||
text_pair = test_ds[idx]
|
||||
text_pair["pred_prob"] = prob
|
||||
text_pairs.append(text_pair)
|
||||
text_pairs = sorted(text_pairs, key=lambda x: x['pred_prob'],
|
||||
reverse=True)[:args.topk]
|
||||
text_pairs = sorted(text_pairs, key=lambda x: x["pred_prob"], reverse=True)[: args.topk]
|
||||
for item in text_pairs:
|
||||
print(item)
|
||||
|
||||
@@ -102,31 +102,22 @@ def do_train():
|
||||
dev_ds = load_dataset(read_data, data_path=args.test_file, lazy=False)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(
|
||||
args.model_name_or_path, num_classes=2)
|
||||
model = AutoModelForSequenceClassification.from_pretrained(args.model_name_or_path, num_classes=2)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
is_pair=True)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length, is_pair=True)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Stack(dtype="int64") # label
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
Stack(dtype="int64"), # label
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
train_data_loader = create_dataloader(train_ds,
|
||||
mode='train',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
dev_data_loader = create_dataloader(dev_ds,
|
||||
mode='dev',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
train_data_loader = create_dataloader(
|
||||
train_ds, mode="train", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
dev_data_loader = create_dataloader(
|
||||
dev_ds, mode="dev", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
if args.init_from_ckpt and os.path.isfile(args.init_from_ckpt):
|
||||
state_dict = paddle.load(args.init_from_ckpt)
|
||||
@@ -147,16 +138,14 @@ def do_train():
|
||||
|
||||
# Generate parameter names needed to perform weight decay.
|
||||
# All bias and LayerNorm parameters are excluded.
|
||||
decay_params = [
|
||||
p.name for n, p in model.named_parameters()
|
||||
if not any(nd in n for nd in ["bias", "norm"])
|
||||
]
|
||||
decay_params = [p.name for n, p in model.named_parameters() if not any(nd in n for nd in ["bias", "norm"])]
|
||||
optimizer = paddle.optimizer.AdamW(
|
||||
learning_rate=args.learning_rate,
|
||||
parameters=model.parameters(),
|
||||
weight_decay=args.weight_decay,
|
||||
apply_decay_param_fun=lambda x: x in decay_params,
|
||||
grad_clip=paddle.nn.ClipGradByGlobalNorm(1.0))
|
||||
grad_clip=paddle.nn.ClipGradByGlobalNorm(1.0),
|
||||
)
|
||||
|
||||
criterion = paddle.nn.loss.CrossEntropyLoss()
|
||||
metric = paddle.metric.Auc()
|
||||
@@ -181,23 +170,21 @@ def do_train():
|
||||
time_diff = time.time() - tic_train
|
||||
print(
|
||||
"global step %d, epoch: %d, batch: %d, loss: %.5f, accuracy: %.5f, speed: %.2f step/s"
|
||||
% (global_step, epoch, step, loss, acc,
|
||||
args.logging_steps / time_diff))
|
||||
% (global_step, epoch, step, loss, acc, args.logging_steps / time_diff)
|
||||
)
|
||||
tic_train = time.time()
|
||||
if global_step % args.eval_step == 0 and rank == 0:
|
||||
evaluate(model, metric, dev_data_loader, "dev")
|
||||
if global_step % args.save_steps == 0 and rank == 0:
|
||||
save_dir = os.path.join(args.save_dir, "model_%d" % global_step)
|
||||
model_to_save = model._layers if isinstance(
|
||||
model, paddle.DataParallel) else model
|
||||
model_to_save = model._layers if isinstance(model, paddle.DataParallel) else model
|
||||
model_to_save.save_pretrained(save_dir)
|
||||
tokenizer.save_pretrained(save_dir)
|
||||
tic_train = time.time()
|
||||
|
||||
# save final checkpoint
|
||||
save_dir = os.path.join(args.save_dir, "model_%d" % global_step)
|
||||
model_to_save = model._layers if isinstance(model,
|
||||
paddle.DataParallel) else model
|
||||
model_to_save = model._layers if isinstance(model, paddle.DataParallel) else model
|
||||
model_to_save.save_pretrained(save_dir)
|
||||
tokenizer.save_pretrained(save_dir)
|
||||
|
||||
|
||||
@@ -18,50 +18,34 @@ import numpy as np
|
||||
from paddlenlp.datasets import MapDataset
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
|
||||
def read_text_pair(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'query': data[0], 'title': data[1]}
|
||||
yield {"query": data[0], "title": data[1]}
|
||||
|
||||
|
||||
def convert_pointwise_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
is_test=False):
|
||||
def convert_pointwise_example(example, tokenizer, max_seq_length=512, is_test=False):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -73,36 +57,25 @@ def convert_pointwise_example(example,
|
||||
return input_ids, token_type_ids
|
||||
|
||||
|
||||
def convert_pairwise_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
phase="train"):
|
||||
def convert_pairwise_example(example, tokenizer, max_seq_length=512, phase="train"):
|
||||
|
||||
if phase == "train":
|
||||
query, pos_title, neg_title = example["query"], example[
|
||||
"title"], example["neg_title"]
|
||||
query, pos_title, neg_title = example["query"], example["title"], example["neg_title"]
|
||||
|
||||
pos_inputs = tokenizer(text=query,
|
||||
text_pair=pos_title,
|
||||
max_seq_len=max_seq_length)
|
||||
neg_inputs = tokenizer(text=query,
|
||||
text_pair=neg_title,
|
||||
max_seq_len=max_seq_length)
|
||||
pos_inputs = tokenizer(text=query, text_pair=pos_title, max_seq_len=max_seq_length)
|
||||
neg_inputs = tokenizer(text=query, text_pair=neg_title, max_seq_len=max_seq_length)
|
||||
|
||||
pos_input_ids = pos_inputs["input_ids"]
|
||||
pos_token_type_ids = pos_inputs["token_type_ids"]
|
||||
neg_input_ids = neg_inputs["input_ids"]
|
||||
neg_token_type_ids = neg_inputs["token_type_ids"]
|
||||
|
||||
return (pos_input_ids, pos_token_type_ids, neg_input_ids,
|
||||
neg_token_type_ids)
|
||||
return (pos_input_ids, pos_token_type_ids, neg_input_ids, neg_token_type_ids)
|
||||
|
||||
else:
|
||||
query, title = example["query"], example["title"]
|
||||
|
||||
inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = inputs["input_ids"]
|
||||
token_type_ids = inputs["token_type_ids"]
|
||||
@@ -115,11 +88,11 @@ def convert_pairwise_example(example,
|
||||
|
||||
|
||||
def gen_pair(dataset, pool_size=100):
|
||||
"""
|
||||
"""
|
||||
Generate triplet randomly based on dataset
|
||||
|
||||
|
||||
Args:
|
||||
dataset: A `MapDataset` or `IterDataset` or a tuple of those.
|
||||
dataset: A `MapDataset` or `IterDataset` or a tuple of those.
|
||||
Each example is composed of 2 texts: exampe["query"], example["title"]
|
||||
pool_size: the number of example to sample negative example randomly
|
||||
|
||||
|
||||
@@ -27,9 +27,7 @@ import paddlenlp as ppnlp
|
||||
def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
|
||||
@@ -37,15 +35,15 @@ def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
|
||||
# 启动python客户端
|
||||
endpoint_list = ['127.0.0.1:8600']
|
||||
endpoint_list = ["127.0.0.1:8600"]
|
||||
client = HttpClient()
|
||||
client.load_client_config('serving_client')
|
||||
client.load_client_config("serving_client")
|
||||
client.connect(endpoint_list)
|
||||
feed_names = client.feed_names_
|
||||
fetch_names = client.fetch_names_
|
||||
|
||||
# 创建tokenizer
|
||||
tokenizer = ppnlp.transformers.ErnieTokenizer.from_pretrained('ernie-gram-zh')
|
||||
tokenizer = ppnlp.transformers.ErnieTokenizer.from_pretrained("ernie-gram-zh")
|
||||
max_seq_len = 64
|
||||
|
||||
# 数据预处理
|
||||
@@ -53,15 +51,13 @@ list_data = [{"query": "中西方语言与文化的差异", "title": "第二语
|
||||
|
||||
input_ids, token_type_ids = [], []
|
||||
for example in list_data:
|
||||
input_id, token_type_id = convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=max_seq_len)
|
||||
input_id, token_type_id = convert_example(example, tokenizer, max_seq_length=max_seq_len)
|
||||
input_ids.append(input_id)
|
||||
token_type_ids.append(token_type_id)
|
||||
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = np.array(input_ids)
|
||||
feed_dict['token_type_ids'] = np.array(token_type_ids)
|
||||
feed_dict["input_ids"] = np.array(input_ids)
|
||||
feed_dict["token_type_ids"] = np.array(token_type_ids)
|
||||
# batch设置为True表示的是批量预测
|
||||
b_start = time.time()
|
||||
result = client.predict(feed=feed_dict, fetch=fetch_names, batch=True)
|
||||
|
||||
@@ -25,9 +25,7 @@ import paddlenlp as ppnlp
|
||||
def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -36,15 +34,15 @@ def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
|
||||
# 启动python客户端
|
||||
endpoint_list = ['127.0.0.1:8600']
|
||||
endpoint_list = ["127.0.0.1:8600"]
|
||||
client = Client()
|
||||
client.load_client_config('serving_client')
|
||||
client.load_client_config("serving_client")
|
||||
client.connect(endpoint_list)
|
||||
feed_names = client.feed_names_
|
||||
fetch_names = client.fetch_names_
|
||||
|
||||
# 创建tokenizer
|
||||
tokenizer = ppnlp.transformers.ErnieTokenizer.from_pretrained('ernie-gram-zh')
|
||||
tokenizer = ppnlp.transformers.ErnieTokenizer.from_pretrained("ernie-gram-zh")
|
||||
max_seq_len = 64
|
||||
|
||||
# 数据预处理
|
||||
@@ -52,15 +50,13 @@ list_data = [{"query": "中西方语言与文化的差异", "title": "第二语
|
||||
|
||||
input_ids, token_type_ids = [], []
|
||||
for example in list_data:
|
||||
input_id, token_type_id = convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=max_seq_len)
|
||||
input_id, token_type_id = convert_example(example, tokenizer, max_seq_length=max_seq_len)
|
||||
input_ids.append(input_id)
|
||||
token_type_ids.append(token_type_id)
|
||||
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = np.array(input_ids)
|
||||
feed_dict['token_type_ids'] = np.array(token_type_ids)
|
||||
feed_dict["input_ids"] = np.array(input_ids)
|
||||
feed_dict["token_type_ids"] = np.array(token_type_ids)
|
||||
# batch设置为True表示的是批量预测
|
||||
b_start = time.time()
|
||||
result = client.predict(feed=feed_dict, fetch=fetch_names, batch=True)
|
||||
|
||||
@@ -30,7 +30,7 @@ from paddlenlp.datasets import load_dataset
|
||||
from paddlenlp.utils.log import logger
|
||||
from paddlenlp.transformers import AutoTokenizer, AutoModel
|
||||
|
||||
sys.path.append('.')
|
||||
sys.path.append(".")
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -67,21 +67,19 @@ args = parser.parse_args()
|
||||
|
||||
def read_text_pair(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'query': data[0], 'title': data[1]}
|
||||
yield {"query": data[0], "title": data[1]}
|
||||
|
||||
|
||||
def convert_example(example, tokenizer, max_seq_length=512, is_test=False):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -94,16 +92,17 @@ def convert_example(example, tokenizer, max_seq_length=512, is_test=False):
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -122,14 +121,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -145,32 +144,27 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
if args.benchmark:
|
||||
import auto_log
|
||||
|
||||
pid = os.getpid()
|
||||
self.autolog = auto_log.AutoLogger(model_name="ernie-tiny",
|
||||
model_precision=precision,
|
||||
batch_size=self.batch_size,
|
||||
data_shape="dynamic",
|
||||
save_path=args.save_log_path,
|
||||
inference_config=config,
|
||||
pids=pid,
|
||||
process_name=None,
|
||||
gpu_ids=0,
|
||||
time_keys=[
|
||||
'preprocess_time',
|
||||
'inference_time',
|
||||
'postprocess_time'
|
||||
],
|
||||
warmup=0,
|
||||
logger=logger)
|
||||
self.autolog = auto_log.AutoLogger(
|
||||
model_name="ernie-tiny",
|
||||
model_precision=precision,
|
||||
batch_size=self.batch_size,
|
||||
data_shape="dynamic",
|
||||
save_path=args.save_log_path,
|
||||
inference_config=config,
|
||||
pids=pid,
|
||||
process_name=None,
|
||||
gpu_ids=0,
|
||||
time_keys=["preprocess_time", "inference_time", "postprocess_time"],
|
||||
warmup=0,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
def predict(self, data, tokenizer):
|
||||
"""
|
||||
@@ -178,7 +172,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
label_map(obj:`dict`): The label id (key) to label str (value) map.
|
||||
|
||||
@@ -190,17 +184,12 @@ class Predictor(object):
|
||||
|
||||
examples = []
|
||||
for text in data:
|
||||
input_ids, segment_ids = convert_example(
|
||||
text,
|
||||
tokenizer,
|
||||
max_seq_length=self.max_seq_length,
|
||||
is_test=True)
|
||||
input_ids, segment_ids = convert_example(text, tokenizer, max_seq_length=self.max_seq_length, is_test=True)
|
||||
examples.append((input_ids, segment_ids))
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
|
||||
if args.benchmark:
|
||||
@@ -223,27 +212,29 @@ class Predictor(object):
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Define predictor to do prediction.
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
test_ds = load_dataset(read_text_pair,
|
||||
data_path=args.input_file,
|
||||
lazy=False)
|
||||
test_ds = load_dataset(read_text_pair, data_path=args.input_file, lazy=False)
|
||||
|
||||
data = [{'query': d['query'], 'title': d['title']} for d in test_ds]
|
||||
data = [{"query": d["query"], "title": d["title"]} for d in test_ds]
|
||||
|
||||
batches = [
|
||||
data[idx:idx + args.batch_size]
|
||||
for idx in range(0, len(data), args.batch_size)
|
||||
]
|
||||
batches = [data[idx : idx + args.batch_size] for idx in range(0, len(data), args.batch_size)]
|
||||
|
||||
results = []
|
||||
for batch_data in batches:
|
||||
results.extend(predictor.predict(batch_data, tokenizer))
|
||||
for idx, text in enumerate(data):
|
||||
print('Data: {} \t prob: {}'.format(text, results[idx]))
|
||||
print("Data: {} \t prob: {}".format(text, results[idx]))
|
||||
if args.benchmark:
|
||||
predictor.autolog.report()
|
||||
|
||||
@@ -17,7 +17,7 @@ import numpy as np
|
||||
from paddle_serving_server.pipeline import PipelineClient
|
||||
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8089'])
|
||||
client.connect(["127.0.0.1:8089"])
|
||||
|
||||
list_data = [{"query": "中西方语言与文化的差异", "title": "第二语言习得的一大障碍就是文化差异。"}]
|
||||
feed = {}
|
||||
|
||||
@@ -22,9 +22,7 @@ from paddle_serving_server.web_service import WebService, Op
|
||||
def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
query, title = example["query"], example["title"]
|
||||
encoded_inputs = tokenizer(text=query,
|
||||
text_pair=title,
|
||||
max_seq_len=max_seq_length)
|
||||
encoded_inputs = tokenizer(text=query, text_pair=title, max_seq_len=max_seq_length)
|
||||
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
@@ -33,32 +31,30 @@ def convert_example(example, tokenizer, max_seq_length=512):
|
||||
|
||||
|
||||
class ErnieOp(Op):
|
||||
|
||||
def init_op(self):
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
self.tokenizer = AutoTokenizer.from_pretrained('ernie-3.0-medium-zh')
|
||||
|
||||
self.tokenizer = AutoTokenizer.from_pretrained("ernie-3.0-medium-zh")
|
||||
|
||||
def preprocess(self, input_dicts, data_id, log_id):
|
||||
from paddlenlp.data import Stack, Tuple, Pad
|
||||
|
||||
(_, input_dict), = input_dicts.items()
|
||||
((_, input_dict),) = input_dicts.items()
|
||||
print("input dict", input_dict)
|
||||
batch_size = len(input_dict.keys())
|
||||
examples = []
|
||||
for i in range(batch_size):
|
||||
example = json.loads(input_dict[str(i)].replace("\'", "\""))
|
||||
example = json.loads(input_dict[str(i)].replace("'", '"'))
|
||||
input_ids, segment_ids = convert_example(example, self.tokenizer)
|
||||
examples.append((input_ids, segment_ids))
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = input_ids
|
||||
feed_dict['token_type_ids'] = segment_ids
|
||||
feed_dict["input_ids"] = input_ids
|
||||
feed_dict["token_type_ids"] = segment_ids
|
||||
return feed_dict, False, None, ""
|
||||
|
||||
def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
|
||||
@@ -68,7 +64,6 @@ class ErnieOp(Op):
|
||||
|
||||
|
||||
class ErnieService(WebService):
|
||||
|
||||
def get_pipeline_response(self, read_op):
|
||||
ernie_op = ErnieOp(name="ernie", input_ops=[read_op])
|
||||
return ernie_op
|
||||
|
||||
@@ -71,8 +71,7 @@ def evaluate(model, metric, data_loader, phase="dev"):
|
||||
for idx, batch in enumerate(data_loader):
|
||||
input_ids, token_type_ids, labels = batch
|
||||
|
||||
pos_probs = model.predict(input_ids=input_ids,
|
||||
token_type_ids=token_type_ids)
|
||||
pos_probs = model.predict(input_ids=input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
neg_probs = 1.0 - pos_probs
|
||||
|
||||
@@ -86,21 +85,21 @@ def evaluate(model, metric, data_loader, phase="dev"):
|
||||
|
||||
# 构建读取函数,读取原始数据
|
||||
def read(src_path, is_predict=False):
|
||||
data = pd.read_csv(src_path, sep='\t')
|
||||
data = pd.read_csv(src_path, sep="\t")
|
||||
for index, row in tqdm(data.iterrows()):
|
||||
query = row['query']
|
||||
title = row['title']
|
||||
neg_title = row['neg_title']
|
||||
yield {'query': query, 'title': title, 'neg_title': neg_title}
|
||||
query = row["query"]
|
||||
title = row["title"]
|
||||
neg_title = row["neg_title"]
|
||||
yield {"query": query, "title": title, "neg_title": neg_title}
|
||||
|
||||
|
||||
def read_test(src_path, is_predict=False):
|
||||
data = pd.read_csv(src_path, sep='\t')
|
||||
data = pd.read_csv(src_path, sep="\t")
|
||||
for index, row in tqdm(data.iterrows()):
|
||||
query = row['query']
|
||||
title = row['title']
|
||||
label = row['label']
|
||||
yield {'query': query, 'title': title, 'label': label}
|
||||
query = row["query"]
|
||||
title = row["title"]
|
||||
label = row["label"]
|
||||
yield {"query": query, "title": title, "label": label}
|
||||
|
||||
|
||||
def main():
|
||||
@@ -117,24 +116,17 @@ def main():
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func_eval = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
phase="eval")
|
||||
trans_func_eval = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length, phase="eval")
|
||||
|
||||
batchify_fn_eval = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # pair_segment
|
||||
Stack(dtype="int64") # label
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # pair_segment
|
||||
Stack(dtype="int64"), # label
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
dev_data_loader = create_dataloader(dev_ds,
|
||||
mode='dev',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn_eval,
|
||||
trans_fn=trans_func_eval)
|
||||
dev_data_loader = create_dataloader(
|
||||
dev_ds, mode="dev", batch_size=args.batch_size, batchify_fn=batchify_fn_eval, trans_fn=trans_func_eval
|
||||
)
|
||||
|
||||
model = PairwiseMatching(pretrained_model, margin=args.margin)
|
||||
|
||||
|
||||
@@ -40,19 +40,17 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
model.eval()
|
||||
|
||||
# Convert to static graph with specific input description
|
||||
model = paddle.jit.to_static(
|
||||
model,
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64") # segment_ids
|
||||
])
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # segment_ids
|
||||
],
|
||||
)
|
||||
# Save in static graph model.
|
||||
save_path = os.path.join(args.output_path, "inference")
|
||||
paddle.jit.save(model, save_path)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import argparse
|
||||
import paddle_serving_client.io as serving_io
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dirname", type=str, required=True,
|
||||
@@ -44,4 +45,5 @@ if __name__ == "__main__":
|
||||
params_filename=args.params_filename,
|
||||
show_proto=args.show_proto,
|
||||
feed_alias_names=args.feed_alias_names,
|
||||
fetch_alias_names=args.fetch_alias_names)
|
||||
fetch_alias_names=args.fetch_alias_names,
|
||||
)
|
||||
|
||||
@@ -18,7 +18,6 @@ import paddle.nn.functional as F
|
||||
|
||||
|
||||
class PairwiseMatching(nn.Layer):
|
||||
|
||||
def __init__(self, pretrained_model, dropout=None, margin=0.1):
|
||||
super().__init__()
|
||||
self.ptm = pretrained_model
|
||||
@@ -28,18 +27,15 @@ class PairwiseMatching(nn.Layer):
|
||||
# hidden_size -> 1, calculate similarity
|
||||
self.similarity = nn.Linear(self.ptm.config["hidden_size"], 1)
|
||||
|
||||
@paddle.jit.to_static(input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64'),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64')
|
||||
])
|
||||
def predict(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
@paddle.jit.to_static(
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
]
|
||||
)
|
||||
def predict(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
cls_embedding = self.dropout(cls_embedding)
|
||||
sim_score = self.similarity(cls_embedding)
|
||||
@@ -47,21 +43,21 @@ class PairwiseMatching(nn.Layer):
|
||||
|
||||
return sim_score
|
||||
|
||||
def forward(self,
|
||||
pos_input_ids,
|
||||
neg_input_ids,
|
||||
pos_token_type_ids=None,
|
||||
neg_token_type_ids=None,
|
||||
pos_position_ids=None,
|
||||
neg_position_ids=None,
|
||||
pos_attention_mask=None,
|
||||
neg_attention_mask=None):
|
||||
def forward(
|
||||
self,
|
||||
pos_input_ids,
|
||||
neg_input_ids,
|
||||
pos_token_type_ids=None,
|
||||
neg_token_type_ids=None,
|
||||
pos_position_ids=None,
|
||||
neg_position_ids=None,
|
||||
pos_attention_mask=None,
|
||||
neg_attention_mask=None,
|
||||
):
|
||||
|
||||
_, pos_cls_embedding = self.ptm(pos_input_ids, pos_token_type_ids,
|
||||
pos_position_ids, pos_attention_mask)
|
||||
_, pos_cls_embedding = self.ptm(pos_input_ids, pos_token_type_ids, pos_position_ids, pos_attention_mask)
|
||||
|
||||
_, neg_cls_embedding = self.ptm(neg_input_ids, neg_token_type_ids,
|
||||
neg_position_ids, neg_attention_mask)
|
||||
_, neg_cls_embedding = self.ptm(neg_input_ids, neg_token_type_ids, neg_position_ids, neg_attention_mask)
|
||||
|
||||
pos_embedding = self.dropout(pos_cls_embedding)
|
||||
neg_embedding = self.dropout(neg_cls_embedding)
|
||||
@@ -72,13 +68,8 @@ class PairwiseMatching(nn.Layer):
|
||||
pos_sim = F.sigmoid(pos_sim)
|
||||
neg_sim = F.sigmoid(neg_sim)
|
||||
|
||||
labels = paddle.full(shape=[pos_cls_embedding.shape[0]],
|
||||
fill_value=1.0,
|
||||
dtype='float32')
|
||||
labels = paddle.full(shape=[pos_cls_embedding.shape[0]], fill_value=1.0, dtype="float32")
|
||||
|
||||
loss = F.margin_ranking_loss(pos_sim,
|
||||
neg_sim,
|
||||
labels,
|
||||
margin=self.margin)
|
||||
loss = F.margin_ranking_loss(pos_sim, neg_sim, labels, margin=self.margin)
|
||||
|
||||
return loss
|
||||
|
||||
@@ -61,11 +61,10 @@ def predict(model, data_loader):
|
||||
for batch_data in data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
|
||||
batch_prob = model.predict(input_ids=input_ids,
|
||||
token_type_ids=token_type_ids).numpy()
|
||||
batch_prob = model.predict(input_ids=input_ids, token_type_ids=token_type_ids).numpy()
|
||||
|
||||
batch_probs.append(batch_prob)
|
||||
if (len(batch_prob) == 1):
|
||||
if len(batch_prob) == 1:
|
||||
batch_probs = np.array(batch_probs)
|
||||
else:
|
||||
batch_probs = np.concatenate(batch_probs, axis=0)
|
||||
@@ -79,26 +78,18 @@ if __name__ == "__main__":
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
phase="predict")
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length, phase="predict")
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input_ids
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment_ids
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # segment_ids
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
valid_ds = load_dataset(read_text_pair,
|
||||
data_path=args.input_file,
|
||||
lazy=False)
|
||||
valid_ds = load_dataset(read_text_pair, data_path=args.input_file, lazy=False)
|
||||
|
||||
valid_data_loader = create_dataloader(valid_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
valid_data_loader = create_dataloader(
|
||||
valid_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
model = PairwiseMatching(pretrained_model)
|
||||
|
||||
@@ -107,14 +98,11 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
y_probs = predict(model, valid_data_loader)
|
||||
|
||||
valid_ds = load_dataset(read_text_pair,
|
||||
data_path=args.input_file,
|
||||
lazy=False)
|
||||
valid_ds = load_dataset(read_text_pair, data_path=args.input_file, lazy=False)
|
||||
|
||||
for idx, prob in enumerate(y_probs):
|
||||
text_pair = valid_ds[idx]
|
||||
|
||||
@@ -79,8 +79,7 @@ def evaluate(model, metric, data_loader, phase="dev"):
|
||||
for idx, batch in enumerate(data_loader):
|
||||
input_ids, token_type_ids, labels = batch
|
||||
|
||||
pos_probs = model.predict(input_ids=input_ids,
|
||||
token_type_ids=token_type_ids)
|
||||
pos_probs = model.predict(input_ids=input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
neg_probs = 1.0 - pos_probs
|
||||
|
||||
@@ -94,21 +93,21 @@ def evaluate(model, metric, data_loader, phase="dev"):
|
||||
|
||||
# 构建读取函数,读取原始数据
|
||||
def read(src_path, is_predict=False):
|
||||
data = pd.read_csv(src_path, sep='\t')
|
||||
data = pd.read_csv(src_path, sep="\t")
|
||||
for index, row in tqdm(data.iterrows()):
|
||||
query = row['query']
|
||||
title = row['title']
|
||||
neg_title = row['neg_title']
|
||||
yield {'query': query, 'title': title, 'neg_title': neg_title}
|
||||
query = row["query"]
|
||||
title = row["title"]
|
||||
neg_title = row["neg_title"]
|
||||
yield {"query": query, "title": title, "neg_title": neg_title}
|
||||
|
||||
|
||||
def read_test(src_path, is_predict=False):
|
||||
data = pd.read_csv(src_path, sep='\t')
|
||||
data = pd.read_csv(src_path, sep="\t")
|
||||
for index, row in tqdm(data.iterrows()):
|
||||
query = row['query']
|
||||
title = row['title']
|
||||
label = row['label']
|
||||
yield {'query': query, 'title': title, 'label': label}
|
||||
query = row["query"]
|
||||
title = row["title"]
|
||||
label = row["label"]
|
||||
yield {"query": query, "title": title, "label": label}
|
||||
|
||||
|
||||
def do_train():
|
||||
@@ -125,45 +124,30 @@ def do_train():
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func_train = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length)
|
||||
trans_func_train = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length)
|
||||
|
||||
trans_func_eval = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
phase="eval")
|
||||
trans_func_eval = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length, phase="eval")
|
||||
|
||||
batchify_fn_train = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # pos_pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # pos_pair_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # neg_pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
) # neg_pair_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # pos_pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # pos_pair_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # neg_pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # neg_pair_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
batchify_fn_eval = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # pair_segment
|
||||
Stack(dtype="int64") # label
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # pair_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # pair_segment
|
||||
Stack(dtype="int64"), # label
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
train_data_loader = create_dataloader(train_ds,
|
||||
mode='train',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn_train,
|
||||
trans_fn=trans_func_train)
|
||||
train_data_loader = create_dataloader(
|
||||
train_ds, mode="train", batch_size=args.batch_size, batchify_fn=batchify_fn_train, trans_fn=trans_func_train
|
||||
)
|
||||
|
||||
dev_data_loader = create_dataloader(dev_ds,
|
||||
mode='dev',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn_eval,
|
||||
trans_fn=trans_func_eval)
|
||||
dev_data_loader = create_dataloader(
|
||||
dev_ds, mode="dev", batch_size=args.batch_size, batchify_fn=batchify_fn_eval, trans_fn=trans_func_eval
|
||||
)
|
||||
|
||||
model = PairwiseMatching(pretrained_model, margin=args.margin)
|
||||
|
||||
@@ -173,20 +157,17 @@ def do_train():
|
||||
|
||||
num_training_steps = len(train_data_loader) * args.epochs
|
||||
|
||||
lr_scheduler = LinearDecayWithWarmup(args.learning_rate, num_training_steps,
|
||||
args.warmup_proportion)
|
||||
lr_scheduler = LinearDecayWithWarmup(args.learning_rate, num_training_steps, args.warmup_proportion)
|
||||
|
||||
# Generate parameter names needed to perform weight decay.
|
||||
# All bias and LayerNorm parameters are excluded.
|
||||
decay_params = [
|
||||
p.name for n, p in model.named_parameters()
|
||||
if not any(nd in n for nd in ["bias", "norm"])
|
||||
]
|
||||
decay_params = [p.name for n, p in model.named_parameters() if not any(nd in n for nd in ["bias", "norm"])]
|
||||
optimizer = paddle.optimizer.AdamW(
|
||||
learning_rate=lr_scheduler,
|
||||
parameters=model.parameters(),
|
||||
weight_decay=args.weight_decay,
|
||||
apply_decay_param_fun=lambda x: x in decay_params)
|
||||
apply_decay_param_fun=lambda x: x in decay_params,
|
||||
)
|
||||
|
||||
metric = paddle.metric.Auc()
|
||||
|
||||
@@ -196,17 +177,19 @@ def do_train():
|
||||
for step, batch in enumerate(train_data_loader, start=1):
|
||||
pos_input_ids, pos_token_type_ids, neg_input_ids, neg_token_type_ids = batch
|
||||
|
||||
loss = model(pos_input_ids=pos_input_ids,
|
||||
neg_input_ids=neg_input_ids,
|
||||
pos_token_type_ids=pos_token_type_ids,
|
||||
neg_token_type_ids=neg_token_type_ids)
|
||||
loss = model(
|
||||
pos_input_ids=pos_input_ids,
|
||||
neg_input_ids=neg_input_ids,
|
||||
pos_token_type_ids=pos_token_type_ids,
|
||||
neg_token_type_ids=neg_token_type_ids,
|
||||
)
|
||||
|
||||
global_step += 1
|
||||
if global_step % 10 == 0 and rank == 0:
|
||||
print(
|
||||
"global step %d, epoch: %d, batch: %d, loss: %.5f, speed: %.2f step/s"
|
||||
% (global_step, epoch, step, loss, 10 /
|
||||
(time.time() - tic_train)))
|
||||
% (global_step, epoch, step, loss, 10 / (time.time() - tic_train))
|
||||
)
|
||||
tic_train = time.time()
|
||||
|
||||
loss.backward()
|
||||
@@ -221,7 +204,7 @@ def do_train():
|
||||
save_dir = os.path.join(args.save_dir, "model_%d" % global_step)
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
save_param_path = os.path.join(save_dir, 'model_state.pdparams')
|
||||
save_param_path = os.path.join(save_dir, "model_state.pdparams")
|
||||
paddle.save(model.state_dict(), save_param_path)
|
||||
tokenizer.save_pretrained(save_dir)
|
||||
|
||||
|
||||
@@ -21,9 +21,7 @@ from paddlenlp.utils.log import logger
|
||||
|
||||
def build_index(args, data_loader, model):
|
||||
|
||||
index = hnswlib.Index(
|
||||
space='ip',
|
||||
dim=args.output_emb_size if args.output_emb_size > 0 else 768)
|
||||
index = hnswlib.Index(space="ip", dim=args.output_emb_size if args.output_emb_size > 0 else 768)
|
||||
|
||||
# Initializing index
|
||||
# max_elements - the maximum number of elements (capacity). Will throw an exception if exceeded
|
||||
@@ -34,9 +32,7 @@ def build_index(args, data_loader, model):
|
||||
#
|
||||
# M - is tightly connected with internal dimensionality of the data. Strongly affects memory consumption (~M)
|
||||
# Higher M leads to higher accuracy/run_time at fixed ef/efConstruction
|
||||
index.init_index(max_elements=args.hnsw_max_elements,
|
||||
ef_construction=args.hnsw_ef,
|
||||
M=args.hnsw_m)
|
||||
index.init_index(max_elements=args.hnsw_max_elements, ef_construction=args.hnsw_ef, M=args.hnsw_m)
|
||||
|
||||
# Controlling the recall by setting ef:
|
||||
# higher ef leads to better accuracy, but slower search
|
||||
|
||||
@@ -23,7 +23,6 @@ import paddle.nn.functional as F
|
||||
|
||||
|
||||
class SemanticIndexBase(nn.Layer):
|
||||
|
||||
def __init__(self, pretrained_model, dropout=None, output_emb_size=None):
|
||||
super().__init__()
|
||||
self.ptm = pretrained_model
|
||||
@@ -35,19 +34,11 @@ class SemanticIndexBase(nn.Layer):
|
||||
|
||||
self.output_emb_size = output_emb_size
|
||||
if output_emb_size > 0:
|
||||
weight_attr = paddle.ParamAttr(
|
||||
initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768,
|
||||
output_emb_size,
|
||||
weight_attr=weight_attr)
|
||||
weight_attr = paddle.ParamAttr(initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768, output_emb_size, weight_attr=weight_attr)
|
||||
|
||||
def get_pooled_embedding(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
def get_pooled_embedding(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if self.output_emb_size > 0:
|
||||
cls_embedding = self.emb_reduce_linear(cls_embedding)
|
||||
@@ -62,33 +53,31 @@ class SemanticIndexBase(nn.Layer):
|
||||
for batch_data in data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
|
||||
text_embeddings = self.get_pooled_embedding(
|
||||
input_ids, token_type_ids=token_type_ids)
|
||||
text_embeddings = self.get_pooled_embedding(input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
yield text_embeddings
|
||||
|
||||
def cosine_sim(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def cosine_sim(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding,
|
||||
axis=-1)
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding, axis=-1)
|
||||
return cosine_sim
|
||||
|
||||
@abc.abstractmethod
|
||||
@@ -97,7 +86,6 @@ class SemanticIndexBase(nn.Layer):
|
||||
|
||||
|
||||
class SemanticIndexBaseStatic(nn.Layer):
|
||||
|
||||
def __init__(self, pretrained_model, dropout=None, output_emb_size=None):
|
||||
super().__init__()
|
||||
self.ptm = pretrained_model
|
||||
@@ -109,23 +97,17 @@ class SemanticIndexBaseStatic(nn.Layer):
|
||||
|
||||
self.output_emb_size = output_emb_size
|
||||
if output_emb_size > 0:
|
||||
weight_attr = paddle.ParamAttr(
|
||||
initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768,
|
||||
output_emb_size,
|
||||
weight_attr=weight_attr)
|
||||
weight_attr = paddle.ParamAttr(initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768, output_emb_size, weight_attr=weight_attr)
|
||||
|
||||
@paddle.jit.to_static(input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64'),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64')
|
||||
])
|
||||
def get_pooled_embedding(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
@paddle.jit.to_static(
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
]
|
||||
)
|
||||
def get_pooled_embedding(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if self.output_emb_size > 0:
|
||||
cls_embedding = self.emb_reduce_linear(cls_embedding)
|
||||
@@ -140,42 +122,35 @@ class SemanticIndexBaseStatic(nn.Layer):
|
||||
for batch_data in data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
|
||||
text_embeddings = self.get_pooled_embedding(
|
||||
input_ids, token_type_ids=token_type_ids)
|
||||
text_embeddings = self.get_pooled_embedding(input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
yield text_embeddings
|
||||
|
||||
def cosine_sim(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def cosine_sim(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding,
|
||||
axis=-1)
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding, axis=-1)
|
||||
return cosine_sim
|
||||
|
||||
def forward(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
def forward(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if self.output_emb_size > 0:
|
||||
cls_embedding = self.emb_reduce_linear(cls_embedding)
|
||||
|
||||
@@ -23,54 +23,46 @@ from base_model import SemanticIndexBase
|
||||
|
||||
|
||||
class SemanticIndexBatchNeg(SemanticIndexBase):
|
||||
|
||||
def __init__(self,
|
||||
pretrained_model,
|
||||
dropout=None,
|
||||
margin=0.3,
|
||||
scale=30,
|
||||
output_emb_size=None):
|
||||
def __init__(self, pretrained_model, dropout=None, margin=0.3, scale=30, output_emb_size=None):
|
||||
super().__init__(pretrained_model, dropout, output_emb_size)
|
||||
|
||||
self.margin = margin
|
||||
# Used scaling cosine similarity to ease converge
|
||||
self.sacle = scale
|
||||
|
||||
def forward(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def forward(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.matmul(query_cls_embedding,
|
||||
title_cls_embedding,
|
||||
transpose_y=True)
|
||||
cosine_sim = paddle.matmul(query_cls_embedding, title_cls_embedding, transpose_y=True)
|
||||
|
||||
# Substract margin from all positive samples cosine_sim()
|
||||
margin_diag = paddle.full(shape=[query_cls_embedding.shape[0]],
|
||||
fill_value=self.margin,
|
||||
dtype=paddle.get_default_dtype())
|
||||
margin_diag = paddle.full(
|
||||
shape=[query_cls_embedding.shape[0]], fill_value=self.margin, dtype=paddle.get_default_dtype()
|
||||
)
|
||||
|
||||
cosine_sim = cosine_sim - paddle.diag(margin_diag)
|
||||
|
||||
# Scale cosine to ease training converge
|
||||
cosine_sim *= self.sacle
|
||||
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype='int64')
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype="int64")
|
||||
labels = paddle.reshape(labels, shape=[-1, 1])
|
||||
|
||||
loss = F.cross_entropy(input=cosine_sim, label=labels)
|
||||
@@ -79,53 +71,43 @@ class SemanticIndexBatchNeg(SemanticIndexBase):
|
||||
|
||||
|
||||
class SemanticIndexCacheNeg(SemanticIndexBase):
|
||||
|
||||
def __init__(self,
|
||||
pretrained_model,
|
||||
dropout=None,
|
||||
margin=0.3,
|
||||
scale=30,
|
||||
output_emb_size=None):
|
||||
def __init__(self, pretrained_model, dropout=None, margin=0.3, scale=30, output_emb_size=None):
|
||||
super().__init__(pretrained_model, dropout, output_emb_size)
|
||||
self.margin = margin
|
||||
# Used scaling cosine similarity to ease converge
|
||||
self.sacle = scale
|
||||
|
||||
def forward(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def forward(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.matmul(query_cls_embedding,
|
||||
title_cls_embedding,
|
||||
transpose_y=True)
|
||||
cosine_sim = paddle.matmul(query_cls_embedding, title_cls_embedding, transpose_y=True)
|
||||
|
||||
# Substract margin from all positive samples cosine_sim()
|
||||
margin_diag = paddle.full(shape=[query_cls_embedding.shape[0]],
|
||||
fill_value=self.margin,
|
||||
dtype=cosine_sim.dtype)
|
||||
margin_diag = paddle.full(shape=[query_cls_embedding.shape[0]], fill_value=self.margin, dtype=cosine_sim.dtype)
|
||||
|
||||
cosine_sim = cosine_sim - paddle.diag(margin_diag)
|
||||
|
||||
# Scale cosine to ease training converge
|
||||
cosine_sim *= self.sacle
|
||||
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype='int64')
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype="int64")
|
||||
labels = paddle.reshape(labels, shape=[-1, 1])
|
||||
|
||||
return [cosine_sim, labels, query_cls_embedding, title_cls_embedding]
|
||||
|
||||
@@ -17,33 +17,19 @@ import paddle
|
||||
from paddlenlp.utils.log import logger
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
@@ -53,9 +39,9 @@ def convert_example(example,
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -66,9 +52,7 @@ def convert_example(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -77,32 +61,28 @@ def convert_example(example,
|
||||
|
||||
def read_text_pair(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 2:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1]}
|
||||
yield {"text_a": data[0], "text_b": data[1]}
|
||||
|
||||
|
||||
def read_text_triplet(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {
|
||||
'text': data[0],
|
||||
'pos_sample': data[1],
|
||||
'neg_sample': data[2]
|
||||
}
|
||||
yield {"text": data[0], "pos_sample": data[1], "neg_sample": data[2]}
|
||||
|
||||
|
||||
# ANN - active learning ------------------------------------------------------
|
||||
def get_latest_checkpoint(args):
|
||||
"""
|
||||
Return: (latest_checkpint_path, global_step)
|
||||
Return: (latest_checkpint_path, global_step)
|
||||
"""
|
||||
if not os.path.exists(args.save_dir):
|
||||
return args.init_from_ckpt, 0
|
||||
@@ -113,14 +93,12 @@ def get_latest_checkpoint(args):
|
||||
chk_path = os.path.join(args.save_dir, checkpoint)
|
||||
scheduler_path = os.path.join(chk_path, "model_state.pdparams")
|
||||
succeed_flag_file = os.path.join(chk_path, "succeed_flag_file")
|
||||
return os.path.exists(scheduler_path) and os.path.exists(
|
||||
succeed_flag_file)
|
||||
return os.path.exists(scheduler_path) and os.path.exists(succeed_flag_file)
|
||||
|
||||
trained_steps = [int(s) for s in subdirectories if valid_checkpoint(s)]
|
||||
|
||||
if len(trained_steps) > 0:
|
||||
return os.path.join(args.save_dir, str(max(trained_steps)),
|
||||
"model_state.pdparams"), max(trained_steps)
|
||||
return os.path.join(args.save_dir, str(max(trained_steps)), "model_state.pdparams"), max(trained_steps)
|
||||
|
||||
return args.init_from_ckpt, 0
|
||||
|
||||
@@ -135,19 +113,14 @@ def get_latest_ann_data(ann_data_dir):
|
||||
def valid_checkpoint(step):
|
||||
ann_data_file = os.path.join(ann_data_dir, step, "new_ann_data")
|
||||
# succed_flag_file is an empty file that indicates ann data has been generated
|
||||
succeed_flag_file = os.path.join(ann_data_dir, step,
|
||||
"succeed_flag_file")
|
||||
return os.path.exists(succeed_flag_file) and os.path.exists(
|
||||
ann_data_file)
|
||||
succeed_flag_file = os.path.join(ann_data_dir, step, "succeed_flag_file")
|
||||
return os.path.exists(succeed_flag_file) and os.path.exists(ann_data_file)
|
||||
|
||||
ann_data_steps = [int(s) for s in subdirectories if valid_checkpoint(s)]
|
||||
|
||||
if len(ann_data_steps) > 0:
|
||||
latest_ann_data_file = os.path.join(ann_data_dir,
|
||||
str(max(ann_data_steps)),
|
||||
"new_ann_data")
|
||||
logger.info(
|
||||
"Using lateset ann_data_file:{}".format(latest_ann_data_file))
|
||||
latest_ann_data_file = os.path.join(ann_data_dir, str(max(ann_data_steps)), "new_ann_data")
|
||||
logger.info("Using lateset ann_data_file:{}".format(latest_ann_data_file))
|
||||
return latest_ann_data_file, max(ann_data_steps)
|
||||
|
||||
logger.info("no new ann_data, return (None, -1)")
|
||||
@@ -156,7 +129,7 @@ def get_latest_ann_data(ann_data_dir):
|
||||
|
||||
def gen_id2corpus(corpus_file):
|
||||
id2corpus = {}
|
||||
with open(corpus_file, 'r', encoding='utf-8') as f:
|
||||
with open(corpus_file, "r", encoding="utf-8") as f:
|
||||
for idx, line in enumerate(f):
|
||||
id2corpus[idx] = line.rstrip()
|
||||
return id2corpus
|
||||
@@ -165,7 +138,7 @@ def gen_id2corpus(corpus_file):
|
||||
def gen_text_file(similar_text_pair_file):
|
||||
text2similar_text = {}
|
||||
texts = []
|
||||
with open(similar_text_pair_file, 'r', encoding='utf-8') as f:
|
||||
with open(similar_text_pair_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
splited_line = line.rstrip().split("\t")
|
||||
if len(splited_line) != 2:
|
||||
|
||||
@@ -25,16 +25,11 @@ from paddlenlp.transformers import AutoModel, AutoTokenizer
|
||||
from paddle_serving_client import HttpClient
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=True):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=True):
|
||||
list_input_ids = []
|
||||
list_token_type_ids = []
|
||||
for text in example:
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
|
||||
@@ -44,9 +39,9 @@ def convert_example(example,
|
||||
|
||||
|
||||
# 启动python客户端
|
||||
endpoint_list = ['127.0.0.1:9393']
|
||||
endpoint_list = ["127.0.0.1:9393"]
|
||||
client = HttpClient()
|
||||
client.load_client_config('serving_client')
|
||||
client.load_client_config("serving_client")
|
||||
client.connect(endpoint_list)
|
||||
feed_names = client.feed_names_
|
||||
fetch_names = client.fetch_names_
|
||||
@@ -54,12 +49,12 @@ print(feed_names)
|
||||
print(fetch_names)
|
||||
|
||||
# 创建tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained('rocketqa-zh-base-query-encoder')
|
||||
tokenizer = AutoTokenizer.from_pretrained("rocketqa-zh-base-query-encoder")
|
||||
max_seq_len = 64
|
||||
|
||||
# 数据预处理
|
||||
|
||||
list_data = ['国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据.', '面向生态系统服务的生态系统分类方案研发与应用']
|
||||
list_data = ["国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据.", "面向生态系统服务的生态系统分类方案研发与应用"]
|
||||
# for i in range(5):
|
||||
# list_data.extend(list_data)
|
||||
# print(len(list_data))
|
||||
@@ -67,11 +62,11 @@ examples = convert_example(list_data, tokenizer, max_seq_length=max_seq_len)
|
||||
print(examples)
|
||||
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = np.array(examples[0])
|
||||
feed_dict['token_type_ids'] = np.array(examples[1])
|
||||
feed_dict["input_ids"] = np.array(examples[0])
|
||||
feed_dict["token_type_ids"] = np.array(examples[1])
|
||||
|
||||
print(feed_dict['input_ids'].shape)
|
||||
print(feed_dict['token_type_ids'].shape)
|
||||
print(feed_dict["input_ids"].shape)
|
||||
print(feed_dict["token_type_ids"].shape)
|
||||
|
||||
# batch设置为True表示的是批量预测
|
||||
b_start = time.time()
|
||||
|
||||
@@ -22,16 +22,11 @@ from paddle_serving_client import Client
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=True):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=True):
|
||||
list_input_ids = []
|
||||
list_token_type_ids = []
|
||||
for text in example:
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
list_input_ids.append(input_ids)
|
||||
@@ -40,9 +35,9 @@ def convert_example(example,
|
||||
|
||||
|
||||
# 启动python客户端
|
||||
endpoint_list = ['127.0.0.1:9393']
|
||||
endpoint_list = ["127.0.0.1:9393"]
|
||||
client = Client()
|
||||
client.load_client_config('serving_client')
|
||||
client.load_client_config("serving_client")
|
||||
client.connect(endpoint_list)
|
||||
feed_names = client.feed_names_
|
||||
fetch_names = client.fetch_names_
|
||||
@@ -50,12 +45,12 @@ print(feed_names)
|
||||
print(fetch_names)
|
||||
|
||||
# 创建tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained('rocketqa-zh-base-query-encoder')
|
||||
tokenizer = AutoTokenizer.from_pretrained("rocketqa-zh-base-query-encoder")
|
||||
max_seq_len = 64
|
||||
|
||||
# 数据预处理
|
||||
|
||||
list_data = ['国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据.', '面向生态系统服务的生态系统分类方案研发与应用']
|
||||
list_data = ["国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据.", "面向生态系统服务的生态系统分类方案研发与应用"]
|
||||
# for i in range(5):
|
||||
# list_data.extend(list_data)
|
||||
# print(len(list_data))
|
||||
@@ -63,11 +58,11 @@ examples = convert_example(list_data, tokenizer, max_seq_length=max_seq_len)
|
||||
print(examples)
|
||||
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = np.array(examples[0])
|
||||
feed_dict['token_type_ids'] = np.array(examples[1])
|
||||
feed_dict["input_ids"] = np.array(examples[0])
|
||||
feed_dict["token_type_ids"] = np.array(examples[1])
|
||||
|
||||
print(feed_dict['input_ids'].shape)
|
||||
print(feed_dict['token_type_ids'].shape)
|
||||
print(feed_dict["input_ids"].shape)
|
||||
print(feed_dict["token_type_ids"].shape)
|
||||
# batch设置为True表示的是批量预测
|
||||
b_start = time.time()
|
||||
result = client.predict(feed=feed_dict, fetch=fetch_names, batch=True)
|
||||
|
||||
@@ -26,7 +26,7 @@ from paddlenlp.data import Stack, Tuple, Pad
|
||||
from paddlenlp.datasets import load_dataset
|
||||
from paddlenlp.utils.log import logger
|
||||
|
||||
sys.path.append('.')
|
||||
sys.path.append(".")
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -59,22 +59,19 @@ args = parser.parse_args()
|
||||
# yapf: enable
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -85,9 +82,7 @@ def convert_example(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -95,16 +90,17 @@ def convert_example(example,
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -123,14 +119,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -146,15 +142,12 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
if args.benchmark:
|
||||
import auto_log
|
||||
|
||||
pid = os.getpid()
|
||||
self.autolog = auto_log.AutoLogger(
|
||||
model_name=args.model_name_or_path,
|
||||
@@ -166,11 +159,10 @@ class Predictor(object):
|
||||
pids=pid,
|
||||
process_name=None,
|
||||
gpu_ids=0,
|
||||
time_keys=[
|
||||
'preprocess_time', 'inference_time', 'postprocess_time'
|
||||
],
|
||||
time_keys=["preprocess_time", "inference_time", "postprocess_time"],
|
||||
warmup=0,
|
||||
logger=logger)
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
def extract_embedding(self, data, tokenizer):
|
||||
"""
|
||||
@@ -178,7 +170,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -219,7 +211,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -231,10 +223,8 @@ class Predictor(object):
|
||||
examples = []
|
||||
for idx, text in enumerate(data):
|
||||
input_ids, segment_ids = convert_example({idx: text[0]}, tokenizer)
|
||||
title_ids, title_segment_ids = convert_example({idx: text[1]},
|
||||
tokenizer)
|
||||
examples.append(
|
||||
(input_ids, segment_ids, title_ids, title_segment_ids))
|
||||
title_ids, title_segment_ids = convert_example({idx: text[1]}, tokenizer)
|
||||
examples.append((input_ids, segment_ids, title_ids, title_segment_ids))
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id), # input
|
||||
@@ -246,8 +236,7 @@ class Predictor(object):
|
||||
if args.benchmark:
|
||||
self.autolog.times.stamp()
|
||||
|
||||
query_ids, query_segment_ids, title_ids, title_segment_ids = batchify_fn(
|
||||
examples)
|
||||
query_ids, query_segment_ids, title_ids, title_segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(query_ids)
|
||||
self.input_handles[1].copy_from_cpu(query_segment_ids)
|
||||
self.predictor.run()
|
||||
@@ -263,28 +252,31 @@ class Predictor(object):
|
||||
|
||||
if args.benchmark:
|
||||
self.autolog.times.end(stamp=True)
|
||||
result = [
|
||||
float(1 - spatial.distance.cosine(arr1, arr2))
|
||||
for arr1, arr2 in zip(query_logits, title_logits)
|
||||
]
|
||||
result = [float(1 - spatial.distance.cosine(arr1, arr2)) for arr1, arr2 in zip(query_logits, title_logits)]
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Define predictor to do prediction.
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
# ErnieTinyTokenizer is special for ernie-tiny pretained model.
|
||||
output_emb_size = 256
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
id2corpus = {0: '国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}
|
||||
id2corpus = {0: "国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据"}
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
res = predictor.extract_embedding(corpus_list, tokenizer)
|
||||
print(res.shape)
|
||||
print(res)
|
||||
corpus_list = [['中西方语言与文化的差异', '中西方文化差异以及语言体现中西方文化,差异,语言体现'],
|
||||
['中西方语言与文化的差异', '飞桨致力于让深度学习技术的创新与应用更简单']]
|
||||
corpus_list = [["中西方语言与文化的差异", "中西方文化差异以及语言体现中西方文化,差异,语言体现"], ["中西方语言与文化的差异", "飞桨致力于让深度学习技术的创新与应用更简单"]]
|
||||
res = predictor.predict(corpus_list, tokenizer)
|
||||
print(res)
|
||||
|
||||
@@ -17,12 +17,9 @@ import numpy as np
|
||||
from paddle_serving_server.pipeline import PipelineClient
|
||||
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8080'])
|
||||
client.connect(["127.0.0.1:8080"])
|
||||
|
||||
list_data = [
|
||||
"国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据",
|
||||
"试论翻译过程中的文化差异与语言空缺翻译过程,文化差异,语言空缺,文化对比"
|
||||
]
|
||||
list_data = ["国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据", "试论翻译过程中的文化差异与语言空缺翻译过程,文化差异,语言空缺,文化对比"]
|
||||
feed = {}
|
||||
for i, item in enumerate(list_data):
|
||||
feed[str(i)] = item
|
||||
|
||||
@@ -21,15 +21,10 @@ from paddle_serving_server.web_service import WebService, Op
|
||||
_LOGGER = logging.getLogger()
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
result = []
|
||||
for text in example:
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -37,44 +32,38 @@ def convert_example(example,
|
||||
|
||||
|
||||
class ErnieOp(Op):
|
||||
|
||||
def init_op(self):
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
self.tokenizer = AutoTokenizer.from_pretrained(
|
||||
"rocketqa-zh-base-query-encoder")
|
||||
|
||||
self.tokenizer = AutoTokenizer.from_pretrained("rocketqa-zh-base-query-encoder")
|
||||
|
||||
def preprocess(self, input_dicts, data_id, log_id):
|
||||
from paddlenlp.data import Stack, Tuple, Pad
|
||||
|
||||
(_, input_dict), = input_dicts.items()
|
||||
((_, input_dict),) = input_dicts.items()
|
||||
print("input dict", input_dict)
|
||||
batch_size = len(input_dict.keys())
|
||||
examples = []
|
||||
for i in range(batch_size):
|
||||
input_ids, segment_ids = convert_example([input_dict[str(i)]],
|
||||
self.tokenizer)
|
||||
input_ids, segment_ids = convert_example([input_dict[str(i)]], self.tokenizer)
|
||||
examples.append((input_ids, segment_ids))
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = input_ids
|
||||
feed_dict['token_type_ids'] = segment_ids
|
||||
feed_dict["input_ids"] = input_ids
|
||||
feed_dict["token_type_ids"] = segment_ids
|
||||
return feed_dict, False, None, ""
|
||||
|
||||
def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
|
||||
new_dict = {}
|
||||
new_dict["output_embedding"] = str(
|
||||
fetch_dict["output_embedding"].tolist())
|
||||
new_dict["output_embedding"] = str(fetch_dict["output_embedding"].tolist())
|
||||
return new_dict, None, ""
|
||||
|
||||
|
||||
class ErnieService(WebService):
|
||||
|
||||
def get_pipeline_response(self, read_op):
|
||||
ernie_op = ErnieOp(name="ernie", input_ops=[read_op])
|
||||
return ernie_op
|
||||
|
||||
@@ -56,14 +56,14 @@ def recall(rs, N=10):
|
||||
|
||||
if __name__ == "__main__":
|
||||
text2similar = {}
|
||||
with open(args.similar_text_pair, 'r', encoding='utf-8') as f:
|
||||
with open(args.similar_text_pair, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
text, similar_text = line.rstrip().split("\t")
|
||||
text2similar[text] = similar_text
|
||||
|
||||
rs = []
|
||||
|
||||
with open(args.recall_result_file, 'r', encoding='utf-8') as f:
|
||||
with open(args.recall_result_file, "r", encoding="utf-8") as f:
|
||||
relevance_labels = []
|
||||
for index, line in enumerate(f):
|
||||
|
||||
@@ -82,11 +82,11 @@ if __name__ == "__main__":
|
||||
for topN in recall_num:
|
||||
R = round(100 * recall(rs, N=topN), 3)
|
||||
recall_N.append(str(R))
|
||||
result = open('result.tsv', 'a')
|
||||
result = open("result.tsv", "a")
|
||||
res = []
|
||||
timestamp = time.strftime('%Y%m%d-%H%M%S', time.localtime())
|
||||
timestamp = time.strftime("%Y%m%d-%H%M%S", time.localtime())
|
||||
res.append(timestamp)
|
||||
for key, val in zip(recall_num, recall_N):
|
||||
print('recall@{}={}'.format(key, val))
|
||||
print("recall@{}={}".format(key, val))
|
||||
res.append(str(val))
|
||||
result.write('\t'.join(res) + '\n')
|
||||
result.write("\t".join(res) + "\n")
|
||||
|
||||
@@ -38,26 +38,23 @@ if __name__ == "__main__":
|
||||
output_emb_size = 256
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
model = SemanticIndexBaseStatic(pretrained_model,
|
||||
output_emb_size=output_emb_size)
|
||||
model = SemanticIndexBaseStatic(pretrained_model, output_emb_size=output_emb_size)
|
||||
if args.params_path and os.path.isfile(args.params_path):
|
||||
state_dict = paddle.load(args.params_path)
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
model.eval()
|
||||
# Convert to static graph with specific input description
|
||||
model = paddle.jit.to_static(
|
||||
model,
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64") # segment_ids
|
||||
])
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # segment_ids
|
||||
],
|
||||
)
|
||||
# Save in static graph model.
|
||||
save_path = os.path.join(args.output_path, "inference")
|
||||
paddle.jit.save(model, save_path)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import argparse
|
||||
import paddle_serving_client.io as serving_io
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dirname", type=str, required=True,
|
||||
@@ -44,4 +45,5 @@ if __name__ == "__main__":
|
||||
params_filename=args.params_filename,
|
||||
show_proto=args.show_proto,
|
||||
feed_alias_names=args.feed_alias_names,
|
||||
fetch_alias_names=args.fetch_alias_names)
|
||||
fetch_alias_names=args.fetch_alias_names,
|
||||
)
|
||||
|
||||
@@ -34,19 +34,17 @@ from ann_util import build_index
|
||||
from tqdm import tqdm
|
||||
|
||||
if __name__ == "__main__":
|
||||
device = 'gpu'
|
||||
device = "gpu"
|
||||
max_seq_length = 64
|
||||
output_emb_size = 256
|
||||
batch_size = 1
|
||||
params_path = 'checkpoints/inbatch/model_40/model_state.pdparams'
|
||||
id2corpus = {0: '国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}
|
||||
params_path = "checkpoints/inbatch/model_40/model_state.pdparams"
|
||||
id2corpus = {0: "国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据"}
|
||||
model_name_or_path = "rocketqa-zh-base-query-encoder"
|
||||
paddle.set_device(device)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=max_seq_length)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id), # text_input
|
||||
@@ -55,8 +53,7 @@ if __name__ == "__main__":
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(model_name_or_path)
|
||||
|
||||
model = SemanticIndexBaseStatic(pretrained_model,
|
||||
output_emb_size=output_emb_size)
|
||||
model = SemanticIndexBaseStatic(pretrained_model, output_emb_size=output_emb_size)
|
||||
|
||||
# Load pretrained semantic model
|
||||
if params_path and os.path.isfile(params_path):
|
||||
@@ -64,18 +61,15 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
# conver_example function's input must be dict
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
all_embeddings = []
|
||||
model.eval()
|
||||
@@ -83,8 +77,7 @@ if __name__ == "__main__":
|
||||
for batch_data in corpus_data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
|
||||
text_embeddings = model.get_pooled_embedding(
|
||||
input_ids, token_type_ids)
|
||||
text_embeddings = model.get_pooled_embedding(input_ids, token_type_ids)
|
||||
all_embeddings.append(text_embeddings)
|
||||
|
||||
text_embedding = all_embeddings[0]
|
||||
|
||||
@@ -72,7 +72,8 @@ def predict(model, data_loader):
|
||||
query_input_ids=query_input_ids,
|
||||
title_input_ids=title_input_ids,
|
||||
query_token_type_ids=query_token_type_ids,
|
||||
title_token_type_ids=title_token_type_ids).numpy()
|
||||
title_token_type_ids=title_token_type_ids,
|
||||
).numpy()
|
||||
|
||||
cosine_sims.append(batch_cosine_sim)
|
||||
|
||||
@@ -86,46 +87,38 @@ if __name__ == "__main__":
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
pad_to_max_seq_len=args.pad_to_max_seq_len)
|
||||
trans_func = partial(
|
||||
convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length,
|
||||
pad_to_max_seq_len=args.pad_to_max_seq_len,
|
||||
)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # query_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype='int64'
|
||||
), # query_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # title_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype='int64'
|
||||
), # tilte_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # query_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # query_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # title_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # tilte_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
valid_ds = load_dataset(read_text_pair,
|
||||
data_path=args.text_pair_file,
|
||||
lazy=False)
|
||||
valid_ds = load_dataset(read_text_pair, data_path=args.text_pair_file, lazy=False)
|
||||
|
||||
valid_data_loader = create_dataloader(valid_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
valid_data_loader = create_dataloader(
|
||||
valid_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
|
||||
model = SemanticIndexBase(pretrained_model,
|
||||
output_emb_size=args.output_emb_size)
|
||||
model = SemanticIndexBase(pretrained_model, output_emb_size=args.output_emb_size)
|
||||
|
||||
if args.params_path and os.path.isfile(args.params_path):
|
||||
state_dict = paddle.load(args.params_path)
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
cosin_sim = predict(model, valid_data_loader)
|
||||
|
||||
for idx, cosine in enumerate(cosin_sim):
|
||||
print('{}'.format(cosine))
|
||||
print("{}".format(cosine))
|
||||
|
||||
@@ -76,21 +76,16 @@ if __name__ == "__main__":
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # text_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # text_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
|
||||
model = SemanticIndexBase(pretrained_model,
|
||||
output_emb_size=args.output_emb_size)
|
||||
model = SemanticIndexBase(pretrained_model, output_emb_size=args.output_emb_size)
|
||||
model = paddle.DataParallel(model)
|
||||
|
||||
# Load pretrained semantic model
|
||||
@@ -99,8 +94,7 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
logger.info("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
id2corpus = gen_id2corpus(args.corpus_file)
|
||||
|
||||
@@ -108,11 +102,9 @@ if __name__ == "__main__":
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
# Need better way to get inner model of DataParallel
|
||||
inner_model = model._layers
|
||||
@@ -123,29 +115,27 @@ if __name__ == "__main__":
|
||||
|
||||
query_ds = MapDataset(text_list)
|
||||
|
||||
query_data_loader = create_dataloader(query_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
query_data_loader = create_dataloader(
|
||||
query_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
query_embedding = inner_model.get_semantic_embedding(query_data_loader)
|
||||
|
||||
if not os.path.exists(args.recall_result_dir):
|
||||
os.mkdir(args.recall_result_dir)
|
||||
|
||||
recall_result_file = os.path.join(args.recall_result_dir,
|
||||
args.recall_result_file)
|
||||
with open(recall_result_file, 'w', encoding='utf-8') as f:
|
||||
recall_result_file = os.path.join(args.recall_result_dir, args.recall_result_file)
|
||||
with open(recall_result_file, "w", encoding="utf-8") as f:
|
||||
for batch_index, batch_query_embedding in enumerate(query_embedding):
|
||||
recalled_idx, cosine_sims = final_index.knn_query(
|
||||
batch_query_embedding.numpy(), args.recall_num)
|
||||
recalled_idx, cosine_sims = final_index.knn_query(batch_query_embedding.numpy(), args.recall_num)
|
||||
|
||||
batch_size = len(cosine_sims)
|
||||
|
||||
for row_index in range(batch_size):
|
||||
text_index = args.batch_size * batch_index + row_index
|
||||
for idx, doc_idx in enumerate(recalled_idx[row_index]):
|
||||
f.write("{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx],
|
||||
1.0 - cosine_sims[row_index][idx]))
|
||||
f.write(
|
||||
"{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx], 1.0 - cosine_sims[row_index][idx]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -118,30 +118,30 @@ def recall(rs, N=10):
|
||||
|
||||
|
||||
@paddle.no_grad()
|
||||
def evaluate(model, corpus_data_loader, query_data_loader, recall_result_file,
|
||||
text_list, id2corpus):
|
||||
def evaluate(model, corpus_data_loader, query_data_loader, recall_result_file, text_list, id2corpus):
|
||||
# Load pretrained semantic model
|
||||
inner_model = model._layers
|
||||
final_index = build_index(args, corpus_data_loader, inner_model)
|
||||
query_embedding = inner_model.get_semantic_embedding(query_data_loader)
|
||||
with open(recall_result_file, 'w', encoding='utf-8') as f:
|
||||
with open(recall_result_file, "w", encoding="utf-8") as f:
|
||||
for batch_index, batch_query_embedding in enumerate(query_embedding):
|
||||
recalled_idx, cosine_sims = final_index.knn_query(
|
||||
batch_query_embedding.numpy(), args.recall_num)
|
||||
recalled_idx, cosine_sims = final_index.knn_query(batch_query_embedding.numpy(), args.recall_num)
|
||||
batch_size = len(cosine_sims)
|
||||
for row_index in range(batch_size):
|
||||
text_index = args.batch_size * batch_index + row_index
|
||||
for idx, doc_idx in enumerate(recalled_idx[row_index]):
|
||||
f.write("{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx],
|
||||
1.0 - cosine_sims[row_index][idx]))
|
||||
f.write(
|
||||
"{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx], 1.0 - cosine_sims[row_index][idx]
|
||||
)
|
||||
)
|
||||
text2similar = {}
|
||||
with open(args.similar_text_pair_file, 'r', encoding='utf-8') as f:
|
||||
with open(args.similar_text_pair_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
text, similar_text = line.rstrip().split("\t")
|
||||
text2similar[text] = similar_text
|
||||
rs = []
|
||||
with open(recall_result_file, 'r', encoding='utf-8') as f:
|
||||
with open(recall_result_file, "r", encoding="utf-8") as f:
|
||||
relevance_labels = []
|
||||
for index, line in enumerate(f):
|
||||
if index % args.recall_num == 0 and index != 0:
|
||||
@@ -160,22 +160,31 @@ def evaluate(model, corpus_data_loader, query_data_loader, recall_result_file,
|
||||
for topN in recall_num:
|
||||
R = round(100 * recall(rs, N=topN), 3)
|
||||
recall_N.append(str(R))
|
||||
evaluate_result_file = os.path.join(args.recall_result_dir,
|
||||
args.evaluate_result)
|
||||
result = open(evaluate_result_file, 'a')
|
||||
evaluate_result_file = os.path.join(args.recall_result_dir, args.evaluate_result)
|
||||
result = open(evaluate_result_file, "a")
|
||||
res = []
|
||||
timestamp = time.strftime('%Y%m%d-%H%M%S', time.localtime())
|
||||
timestamp = time.strftime("%Y%m%d-%H%M%S", time.localtime())
|
||||
res.append(timestamp)
|
||||
for key, val in zip(recall_num, recall_N):
|
||||
print('recall@{}={}'.format(key, val))
|
||||
print("recall@{}={}".format(key, val))
|
||||
res.append(str(val))
|
||||
result.write('\t'.join(res) + '\n')
|
||||
result.write("\t".join(res) + "\n")
|
||||
return float(recall_N[1])
|
||||
|
||||
|
||||
def train(train_data_loader, model, optimizer, lr_scheduler, rank,
|
||||
corpus_data_loader, query_data_loader, recall_result_file, text_list,
|
||||
id2corpus, tokenizer):
|
||||
def train(
|
||||
train_data_loader,
|
||||
model,
|
||||
optimizer,
|
||||
lr_scheduler,
|
||||
rank,
|
||||
corpus_data_loader,
|
||||
query_data_loader,
|
||||
recall_result_file,
|
||||
text_list,
|
||||
id2corpus,
|
||||
tokenizer,
|
||||
):
|
||||
global_step = 0
|
||||
best_recall = 0.0
|
||||
tic_train = time.time()
|
||||
@@ -183,17 +192,19 @@ def train(train_data_loader, model, optimizer, lr_scheduler, rank,
|
||||
for step, batch in enumerate(train_data_loader, start=1):
|
||||
query_input_ids, query_token_type_ids, title_input_ids, title_token_type_ids = batch
|
||||
|
||||
loss = model(query_input_ids=query_input_ids,
|
||||
title_input_ids=title_input_ids,
|
||||
query_token_type_ids=query_token_type_ids,
|
||||
title_token_type_ids=title_token_type_ids)
|
||||
loss = model(
|
||||
query_input_ids=query_input_ids,
|
||||
title_input_ids=title_input_ids,
|
||||
query_token_type_ids=query_token_type_ids,
|
||||
title_token_type_ids=title_token_type_ids,
|
||||
)
|
||||
|
||||
global_step += 1
|
||||
if global_step % args.log_steps == 0 and rank == 0:
|
||||
print(
|
||||
"global step %d, epoch: %d, batch: %d, loss: %.5f, speed: %.2f step/s"
|
||||
% (global_step, epoch, step, loss, args.log_steps /
|
||||
(time.time() - tic_train)))
|
||||
% (global_step, epoch, step, loss, args.log_steps / (time.time() - tic_train))
|
||||
)
|
||||
tic_train = time.time()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
@@ -201,36 +212,29 @@ def train(train_data_loader, model, optimizer, lr_scheduler, rank,
|
||||
optimizer.clear_grad()
|
||||
if not args.evaluate:
|
||||
if global_step % args.save_steps == 0 and rank == 0:
|
||||
save_dir = os.path.join(args.save_dir,
|
||||
"model_%d" % global_step)
|
||||
save_dir = os.path.join(args.save_dir, "model_%d" % global_step)
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
save_param_path = os.path.join(save_dir,
|
||||
'model_state.pdparams')
|
||||
save_param_path = os.path.join(save_dir, "model_state.pdparams")
|
||||
paddle.save(model.state_dict(), save_param_path)
|
||||
tokenizer.save_pretrained(save_dir)
|
||||
if args.evaluate and rank == 0:
|
||||
print("evaluating")
|
||||
recall_5 = evaluate(model, corpus_data_loader, query_data_loader,
|
||||
recall_result_file, text_list, id2corpus)
|
||||
recall_5 = evaluate(model, corpus_data_loader, query_data_loader, recall_result_file, text_list, id2corpus)
|
||||
if recall_5 > best_recall:
|
||||
best_recall = recall_5
|
||||
|
||||
save_dir = os.path.join(args.save_dir, "model_best")
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
save_param_path = os.path.join(save_dir, 'model_state.pdparams')
|
||||
save_param_path = os.path.join(save_dir, "model_state.pdparams")
|
||||
paddle.save(model.state_dict(), save_param_path)
|
||||
tokenizer.save_pretrained(save_dir)
|
||||
with open(os.path.join(save_dir, "train_result.txt"),
|
||||
'a',
|
||||
encoding='utf-8') as fp:
|
||||
fp.write('epoch=%d, global_step: %d, recall: %s\n' %
|
||||
(epoch, global_step, recall_5))
|
||||
with open(os.path.join(save_dir, "train_result.txt"), "a", encoding="utf-8") as fp:
|
||||
fp.write("epoch=%d, global_step: %d, recall: %s\n" % (epoch, global_step, recall_5))
|
||||
|
||||
|
||||
def gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler,
|
||||
rank, tokenizer):
|
||||
def gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler, rank, tokenizer):
|
||||
|
||||
if args.use_amp:
|
||||
scaler = paddle.amp.GradScaler(init_loss_scaling=args.amp_loss_scale)
|
||||
@@ -264,20 +268,23 @@ def gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler,
|
||||
for sub_batch in sub_batchs:
|
||||
all_reps = []
|
||||
all_labels = []
|
||||
sub_query_input_ids, sub_query_token_type_ids, sub_title_input_ids, sub_title_token_type_ids = sub_batch
|
||||
with paddle.amp.auto_cast(
|
||||
args.use_amp,
|
||||
custom_white_list=["layer_norm", "softmax", "gelu"]):
|
||||
(
|
||||
sub_query_input_ids,
|
||||
sub_query_token_type_ids,
|
||||
sub_title_input_ids,
|
||||
sub_title_token_type_ids,
|
||||
) = sub_batch
|
||||
with paddle.amp.auto_cast(args.use_amp, custom_white_list=["layer_norm", "softmax", "gelu"]):
|
||||
|
||||
with paddle.no_grad():
|
||||
sub_CUDA_rnd_state = paddle.framework.random.get_cuda_rng_state(
|
||||
)
|
||||
sub_CUDA_rnd_state = paddle.framework.random.get_cuda_rng_state()
|
||||
all_CUDA_rnd_state.append(sub_CUDA_rnd_state)
|
||||
sub_cosine_sim, sub_label, query_embedding, title_embedding = model(
|
||||
query_input_ids=sub_query_input_ids,
|
||||
title_input_ids=sub_title_input_ids,
|
||||
query_token_type_ids=sub_query_token_type_ids,
|
||||
title_token_type_ids=sub_title_token_type_ids)
|
||||
title_token_type_ids=sub_title_token_type_ids,
|
||||
)
|
||||
all_reps.append(sub_cosine_sim)
|
||||
all_labels.append(sub_label)
|
||||
all_title.append(title_embedding)
|
||||
@@ -300,18 +307,22 @@ def gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler,
|
||||
# Store gradients
|
||||
all_grads.append(model_reps.grad)
|
||||
|
||||
for sub_batch, CUDA_state, grad in zip(sub_batchs,
|
||||
all_CUDA_rnd_state,
|
||||
all_grads):
|
||||
for sub_batch, CUDA_state, grad in zip(sub_batchs, all_CUDA_rnd_state, all_grads):
|
||||
|
||||
sub_query_input_ids, sub_query_token_type_ids, sub_title_input_ids, sub_title_token_type_ids = sub_batch
|
||||
(
|
||||
sub_query_input_ids,
|
||||
sub_query_token_type_ids,
|
||||
sub_title_input_ids,
|
||||
sub_title_token_type_ids,
|
||||
) = sub_batch
|
||||
paddle.framework.random.set_cuda_rng_state(CUDA_state)
|
||||
# Recompute the forward propogation
|
||||
sub_cosine_sim, sub_label, query_embedding, title_embedding = model(
|
||||
query_input_ids=sub_query_input_ids,
|
||||
title_input_ids=sub_title_input_ids,
|
||||
query_token_type_ids=sub_query_token_type_ids,
|
||||
title_token_type_ids=sub_title_token_type_ids)
|
||||
title_token_type_ids=sub_title_token_type_ids,
|
||||
)
|
||||
# Chain rule
|
||||
surrogate = paddle.dot(sub_cosine_sim, grad)
|
||||
# Backward propogation
|
||||
@@ -330,8 +341,8 @@ def gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler,
|
||||
if global_step % args.log_steps == 0 and rank == 0:
|
||||
print(
|
||||
"global step %d, epoch: %d, batch: %d, loss: %.5f, speed: %.2f step/s"
|
||||
% (global_step, epoch, step, loss, args.log_steps /
|
||||
(time.time() - tic_train)))
|
||||
% (global_step, epoch, step, loss, args.log_steps / (time.time() - tic_train))
|
||||
)
|
||||
tic_train = time.time()
|
||||
|
||||
lr_scheduler.step()
|
||||
@@ -341,7 +352,7 @@ def gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler,
|
||||
save_dir = os.path.join(args.save_dir, "model_%d" % global_step)
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
save_param_path = os.path.join(save_dir, 'model_state.pdparams')
|
||||
save_param_path = os.path.join(save_dir, "model_state.pdparams")
|
||||
paddle.save(model.state_dict(), save_param_path)
|
||||
tokenizer.save_pretrained(save_dir)
|
||||
|
||||
@@ -354,45 +365,32 @@ def do_train():
|
||||
|
||||
set_seed(args.seed)
|
||||
|
||||
train_ds = load_dataset(read_text_pair,
|
||||
data_path=args.train_set_file,
|
||||
lazy=False)
|
||||
train_ds = load_dataset(read_text_pair, data_path=args.train_set_file, lazy=False)
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(
|
||||
args.model_name_or_path, enable_recompute=args.use_recompute)
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path, enable_recompute=args.use_recompute)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # query_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype='int64'
|
||||
), # query_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # title_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype='int64'
|
||||
), # tilte_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # query_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # query_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # title_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # tilte_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
train_data_loader = create_dataloader(train_ds,
|
||||
mode='train',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
if (args.use_gradient_cache):
|
||||
model = SemanticIndexCacheNeg(pretrained_model,
|
||||
margin=args.margin,
|
||||
scale=args.scale,
|
||||
output_emb_size=args.output_emb_size)
|
||||
train_data_loader = create_dataloader(
|
||||
train_ds, mode="train", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
if args.use_gradient_cache:
|
||||
model = SemanticIndexCacheNeg(
|
||||
pretrained_model, margin=args.margin, scale=args.scale, output_emb_size=args.output_emb_size
|
||||
)
|
||||
else:
|
||||
model = SemanticIndexBatchNeg(pretrained_model,
|
||||
margin=args.margin,
|
||||
scale=args.scale,
|
||||
output_emb_size=args.output_emb_size)
|
||||
model = SemanticIndexBatchNeg(
|
||||
pretrained_model, margin=args.margin, scale=args.scale, output_emb_size=args.output_emb_size
|
||||
)
|
||||
|
||||
if args.init_from_ckpt and os.path.isfile(args.init_from_ckpt):
|
||||
state_dict = paddle.load(args.init_from_ckpt)
|
||||
@@ -402,10 +400,8 @@ def do_train():
|
||||
model = paddle.DataParallel(model)
|
||||
|
||||
batchify_fn_dev = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype='int64'
|
||||
), # text_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # text_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
id2corpus = gen_id2corpus(args.corpus_file)
|
||||
@@ -414,52 +410,53 @@ def do_train():
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn_dev,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn_dev, trans_fn=trans_func
|
||||
)
|
||||
|
||||
text_list, text2similar_text = gen_text_file(args.similar_text_pair_file)
|
||||
|
||||
query_ds = MapDataset(text_list)
|
||||
|
||||
query_data_loader = create_dataloader(query_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn_dev,
|
||||
trans_fn=trans_func)
|
||||
query_data_loader = create_dataloader(
|
||||
query_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn_dev, trans_fn=trans_func
|
||||
)
|
||||
|
||||
if not os.path.exists(args.recall_result_dir):
|
||||
os.mkdir(args.recall_result_dir)
|
||||
|
||||
recall_result_file = os.path.join(args.recall_result_dir,
|
||||
args.recall_result_file)
|
||||
recall_result_file = os.path.join(args.recall_result_dir, args.recall_result_file)
|
||||
|
||||
num_training_steps = len(train_data_loader) * args.epochs
|
||||
|
||||
lr_scheduler = LinearDecayWithWarmup(args.learning_rate, num_training_steps,
|
||||
args.warmup_proportion)
|
||||
lr_scheduler = LinearDecayWithWarmup(args.learning_rate, num_training_steps, args.warmup_proportion)
|
||||
|
||||
# Generate parameter names needed to perform weight decay.
|
||||
# All bias and LayerNorm parameters are excluded.
|
||||
decay_params = [
|
||||
p.name for n, p in model.named_parameters()
|
||||
if not any(nd in n for nd in ["bias", "norm"])
|
||||
]
|
||||
decay_params = [p.name for n, p in model.named_parameters() if not any(nd in n for nd in ["bias", "norm"])]
|
||||
optimizer = paddle.optimizer.AdamW(
|
||||
learning_rate=lr_scheduler,
|
||||
parameters=model.parameters(),
|
||||
weight_decay=args.weight_decay,
|
||||
apply_decay_param_fun=lambda x: x in decay_params)
|
||||
apply_decay_param_fun=lambda x: x in decay_params,
|
||||
)
|
||||
|
||||
if (args.use_gradient_cache):
|
||||
gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler,
|
||||
rank, tokenizer)
|
||||
if args.use_gradient_cache:
|
||||
gradient_cache_train(train_data_loader, model, optimizer, lr_scheduler, rank, tokenizer)
|
||||
else:
|
||||
train(train_data_loader, model, optimizer, lr_scheduler, rank,
|
||||
corpus_data_loader, query_data_loader, recall_result_file,
|
||||
text_list, id2corpus, tokenizer)
|
||||
train(
|
||||
train_data_loader,
|
||||
model,
|
||||
optimizer,
|
||||
lr_scheduler,
|
||||
rank,
|
||||
corpus_data_loader,
|
||||
query_data_loader,
|
||||
recall_result_file,
|
||||
text_list,
|
||||
id2corpus,
|
||||
tokenizer,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -23,7 +23,6 @@ import paddle.nn.functional as F
|
||||
|
||||
|
||||
class SemanticIndexBase(nn.Layer):
|
||||
|
||||
def __init__(self, pretrained_model, dropout=None, output_emb_size=None):
|
||||
super().__init__()
|
||||
self.ptm = pretrained_model
|
||||
@@ -35,23 +34,17 @@ class SemanticIndexBase(nn.Layer):
|
||||
|
||||
self.output_emb_size = output_emb_size
|
||||
if output_emb_size > 0:
|
||||
weight_attr = paddle.ParamAttr(
|
||||
initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768,
|
||||
output_emb_size,
|
||||
weight_attr=weight_attr)
|
||||
weight_attr = paddle.ParamAttr(initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768, output_emb_size, weight_attr=weight_attr)
|
||||
|
||||
@paddle.jit.to_static(input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64'),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64')
|
||||
])
|
||||
def get_pooled_embedding(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
@paddle.jit.to_static(
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
]
|
||||
)
|
||||
def get_pooled_embedding(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if self.output_emb_size > 0:
|
||||
cls_embedding = self.emb_reduce_linear(cls_embedding)
|
||||
@@ -68,33 +61,31 @@ class SemanticIndexBase(nn.Layer):
|
||||
input_ids = paddle.to_tensor(input_ids)
|
||||
token_type_ids = paddle.to_tensor(token_type_ids)
|
||||
|
||||
text_embeddings = self.get_pooled_embedding(
|
||||
input_ids, token_type_ids=token_type_ids)
|
||||
text_embeddings = self.get_pooled_embedding(input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
yield text_embeddings
|
||||
|
||||
def cosine_sim(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def cosine_sim(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding,
|
||||
axis=-1)
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding, axis=-1)
|
||||
return cosine_sim
|
||||
|
||||
@abc.abstractmethod
|
||||
@@ -103,7 +94,6 @@ class SemanticIndexBase(nn.Layer):
|
||||
|
||||
|
||||
class SemanticIndexBaseStatic(nn.Layer):
|
||||
|
||||
def __init__(self, pretrained_model, dropout=None, output_emb_size=None):
|
||||
super().__init__()
|
||||
self.ptm = pretrained_model
|
||||
@@ -115,23 +105,17 @@ class SemanticIndexBaseStatic(nn.Layer):
|
||||
|
||||
self.output_emb_size = output_emb_size
|
||||
if output_emb_size > 0:
|
||||
weight_attr = paddle.ParamAttr(
|
||||
initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768,
|
||||
output_emb_size,
|
||||
weight_attr=weight_attr)
|
||||
weight_attr = paddle.ParamAttr(initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768, output_emb_size, weight_attr=weight_attr)
|
||||
|
||||
@paddle.jit.to_static(input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64'),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64')
|
||||
])
|
||||
def get_pooled_embedding(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
@paddle.jit.to_static(
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
]
|
||||
)
|
||||
def get_pooled_embedding(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if self.output_emb_size > 0:
|
||||
cls_embedding = self.emb_reduce_linear(cls_embedding)
|
||||
@@ -148,42 +132,35 @@ class SemanticIndexBaseStatic(nn.Layer):
|
||||
input_ids = paddle.to_tensor(input_ids)
|
||||
token_type_ids = paddle.to_tensor(token_type_ids)
|
||||
|
||||
text_embeddings = self.get_pooled_embedding(
|
||||
input_ids, token_type_ids=token_type_ids)
|
||||
text_embeddings = self.get_pooled_embedding(input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
yield text_embeddings
|
||||
|
||||
def cosine_sim(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def cosine_sim(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding,
|
||||
axis=-1)
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding, axis=-1)
|
||||
return cosine_sim
|
||||
|
||||
def forward(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids,
|
||||
attention_mask)
|
||||
def forward(self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None):
|
||||
_, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
if self.output_emb_size > 0:
|
||||
cls_embedding = self.emb_reduce_linear(cls_embedding)
|
||||
cls_embedding = self.dropout(cls_embedding)
|
||||
|
||||
@@ -12,25 +12,21 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
MILVUS_HOST = '10.21.226.175'
|
||||
MILVUS_HOST = "10.21.226.175"
|
||||
MILVUS_PORT = 8530
|
||||
data_dim = 256
|
||||
top_k = 100
|
||||
collection_name = 'literature_search'
|
||||
partition_tag = 'partition_2'
|
||||
embedding_name = 'embeddings'
|
||||
collection_name = "literature_search"
|
||||
partition_tag = "partition_2"
|
||||
embedding_name = "embeddings"
|
||||
|
||||
index_config = {
|
||||
"index_type": "IVF_FLAT",
|
||||
"metric_type": "L2",
|
||||
"params": {
|
||||
"nlist": 1000
|
||||
},
|
||||
"params": {"nlist": 1000},
|
||||
}
|
||||
|
||||
search_params = {
|
||||
"metric_type": "L2",
|
||||
"params": {
|
||||
"nprobe": top_k
|
||||
},
|
||||
}
|
||||
"params": {"nprobe": top_k},
|
||||
}
|
||||
|
||||
@@ -19,45 +19,31 @@ import paddle
|
||||
from paddlenlp.utils.log import logger
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -68,9 +54,7 @@ def convert_example(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -79,32 +63,28 @@ def convert_example(example,
|
||||
|
||||
def read_text_pair(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 2:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1]}
|
||||
yield {"text_a": data[0], "text_b": data[1]}
|
||||
|
||||
|
||||
def read_text_triplet(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {
|
||||
'text': data[0],
|
||||
'pos_sample': data[1],
|
||||
'neg_sample': data[2]
|
||||
}
|
||||
yield {"text": data[0], "pos_sample": data[1], "neg_sample": data[2]}
|
||||
|
||||
|
||||
# ANN - active learning ------------------------------------------------------
|
||||
def get_latest_checkpoint(args):
|
||||
"""
|
||||
Return: (latest_checkpint_path, global_step)
|
||||
Return: (latest_checkpint_path, global_step)
|
||||
"""
|
||||
if not os.path.exists(args.save_dir):
|
||||
return args.init_from_ckpt, 0
|
||||
@@ -115,14 +95,12 @@ def get_latest_checkpoint(args):
|
||||
chk_path = os.path.join(args.save_dir, checkpoint)
|
||||
scheduler_path = os.path.join(chk_path, "model_state.pdparams")
|
||||
succeed_flag_file = os.path.join(chk_path, "succeed_flag_file")
|
||||
return os.path.exists(scheduler_path) and os.path.exists(
|
||||
succeed_flag_file)
|
||||
return os.path.exists(scheduler_path) and os.path.exists(succeed_flag_file)
|
||||
|
||||
trained_steps = [int(s) for s in subdirectories if valid_checkpoint(s)]
|
||||
|
||||
if len(trained_steps) > 0:
|
||||
return os.path.join(args.save_dir, str(max(trained_steps)),
|
||||
"model_state.pdparams"), max(trained_steps)
|
||||
return os.path.join(args.save_dir, str(max(trained_steps)), "model_state.pdparams"), max(trained_steps)
|
||||
|
||||
return args.init_from_ckpt, 0
|
||||
|
||||
@@ -137,19 +115,14 @@ def get_latest_ann_data(ann_data_dir):
|
||||
def valid_checkpoint(step):
|
||||
ann_data_file = os.path.join(ann_data_dir, step, "new_ann_data")
|
||||
# succed_flag_file is an empty file that indicates ann data has been generated
|
||||
succeed_flag_file = os.path.join(ann_data_dir, step,
|
||||
"succeed_flag_file")
|
||||
return os.path.exists(succeed_flag_file) and os.path.exists(
|
||||
ann_data_file)
|
||||
succeed_flag_file = os.path.join(ann_data_dir, step, "succeed_flag_file")
|
||||
return os.path.exists(succeed_flag_file) and os.path.exists(ann_data_file)
|
||||
|
||||
ann_data_steps = [int(s) for s in subdirectories if valid_checkpoint(s)]
|
||||
|
||||
if len(ann_data_steps) > 0:
|
||||
latest_ann_data_file = os.path.join(ann_data_dir,
|
||||
str(max(ann_data_steps)),
|
||||
"new_ann_data")
|
||||
logger.info(
|
||||
"Using lateset ann_data_file:{}".format(latest_ann_data_file))
|
||||
latest_ann_data_file = os.path.join(ann_data_dir, str(max(ann_data_steps)), "new_ann_data")
|
||||
logger.info("Using lateset ann_data_file:{}".format(latest_ann_data_file))
|
||||
return latest_ann_data_file, max(ann_data_steps)
|
||||
|
||||
logger.info("no new ann_data, return (None, -1)")
|
||||
@@ -158,7 +131,7 @@ def get_latest_ann_data(ann_data_dir):
|
||||
|
||||
def gen_id2corpus(corpus_file):
|
||||
id2corpus = {}
|
||||
with open(corpus_file, 'r', encoding='utf-8') as f:
|
||||
with open(corpus_file, "r", encoding="utf-8") as f:
|
||||
for idx, line in enumerate(f):
|
||||
id2corpus[idx] = line.rstrip()
|
||||
return id2corpus
|
||||
@@ -167,7 +140,7 @@ def gen_id2corpus(corpus_file):
|
||||
def gen_text_file(similar_text_pair_file):
|
||||
text2similar_text = {}
|
||||
texts = []
|
||||
with open(similar_text_pair_file, 'r', encoding='utf-8') as f:
|
||||
with open(similar_text_pair_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
splited_line = line.rstrip().split("\t")
|
||||
if len(splited_line) != 2:
|
||||
|
||||
@@ -25,7 +25,7 @@ from paddlenlp.data import Stack, Tuple, Pad
|
||||
from paddlenlp.datasets import load_dataset
|
||||
from paddlenlp.utils.log import logger
|
||||
|
||||
sys.path.append('.')
|
||||
sys.path.append(".")
|
||||
|
||||
from data import convert_example
|
||||
|
||||
@@ -57,16 +57,17 @@ args = parser.parse_args()
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -85,14 +86,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -108,12 +109,8 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
def predict(self, data, tokenizer):
|
||||
"""
|
||||
@@ -121,7 +118,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -129,20 +126,17 @@ class Predictor(object):
|
||||
"""
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
|
||||
all_embeddings = []
|
||||
examples = []
|
||||
for idx, text in enumerate(tqdm(data)):
|
||||
input_ids, segment_ids = convert_example(
|
||||
text,
|
||||
tokenizer,
|
||||
max_seq_length=self.max_seq_length,
|
||||
pad_to_max_seq_len=True)
|
||||
text, tokenizer, max_seq_length=self.max_seq_length, pad_to_max_seq_len=True
|
||||
)
|
||||
examples.append((input_ids, segment_ids))
|
||||
if (len(examples) > self.batch_size):
|
||||
if len(examples) > self.batch_size:
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(input_ids)
|
||||
self.input_handles[1].copy_from_cpu(segment_ids)
|
||||
@@ -150,7 +144,7 @@ class Predictor(object):
|
||||
logits = self.output_handle.copy_to_cpu()
|
||||
all_embeddings.append(logits)
|
||||
examples = []
|
||||
if (len(examples) > 0):
|
||||
if len(examples) > 0:
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(input_ids)
|
||||
self.input_handles[1].copy_from_cpu(segment_ids)
|
||||
@@ -158,7 +152,7 @@ class Predictor(object):
|
||||
logits = self.output_handle.copy_to_cpu()
|
||||
all_embeddings.append(logits)
|
||||
all_embeddings = np.concatenate(all_embeddings, axis=0)
|
||||
np.save('corpus_embedding', all_embeddings)
|
||||
np.save("corpus_embedding", all_embeddings)
|
||||
|
||||
|
||||
def read_text(file_path):
|
||||
@@ -170,9 +164,16 @@ def read_text(file_path):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
id2corpus = read_text(args.corpus_file)
|
||||
|
||||
@@ -37,62 +37,55 @@ from config import embedding_name, collection_name, partition_tag
|
||||
|
||||
def search_in_milvus(text_embedding):
|
||||
recall_client = RecallByMilvus()
|
||||
result = recall_client.search(text_embedding.numpy(),
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'text'])
|
||||
result = recall_client.search(
|
||||
text_embedding.numpy(),
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=["pk", "text"],
|
||||
)
|
||||
for hits in result:
|
||||
for hit in hits:
|
||||
print(f"hit: {hit}, text field: {hit.entity.get('text')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
device = 'gpu'
|
||||
device = "gpu"
|
||||
max_seq_length = 64
|
||||
output_emb_size = 256
|
||||
batch_size = 1
|
||||
params_path = 'checkpoints/model_40/model_state.pdparams'
|
||||
id2corpus = {0: '国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}
|
||||
params_path = "checkpoints/model_40/model_state.pdparams"
|
||||
id2corpus = {0: "国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据"}
|
||||
model_name_or_path = "rocketqa-zh-base-query-encoder"
|
||||
paddle.set_device(device)
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=max_seq_length)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=max_seq_length)
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # text_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # text_segment
|
||||
): [data for data in fn(samples)]
|
||||
pretrained_model = AutoModel.from_pretrained(model_name_or_path)
|
||||
model = SemanticIndexBaseStatic(pretrained_model,
|
||||
output_emb_size=output_emb_size)
|
||||
model = SemanticIndexBaseStatic(pretrained_model, output_emb_size=output_emb_size)
|
||||
# Load pretrained semantic model
|
||||
if params_path and os.path.isfile(params_path):
|
||||
state_dict = paddle.load(params_path)
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
# conver_example function's input must be dict
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
# Need better way to get inner model of DataParallel
|
||||
all_embeddings = []
|
||||
model.eval()
|
||||
with paddle.no_grad():
|
||||
for batch_data in corpus_data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
text_embeddings = model.get_pooled_embedding(
|
||||
input_ids, token_type_ids)
|
||||
text_embeddings = model.get_pooled_embedding(input_ids, token_type_ids)
|
||||
all_embeddings.append(text_embeddings)
|
||||
text_embedding = all_embeddings[0]
|
||||
print(text_embedding.shape)
|
||||
|
||||
@@ -22,30 +22,16 @@ from milvus_util import VecToMilvus, RecallByMilvus, text_max_len
|
||||
from config import collection_name, partition_tag, embedding_name
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--data_path",
|
||||
default='milvus/milvus_data.csv',
|
||||
type=str,
|
||||
required=True,
|
||||
help="The data for vector extraction.")
|
||||
parser.add_argument("--embedding_path",
|
||||
default='corpus_embedding.npy',
|
||||
type=str,
|
||||
required=True,
|
||||
help="The vector path for data.")
|
||||
parser.add_argument('--index',
|
||||
default=0,
|
||||
type=int,
|
||||
help='index of the vector for search')
|
||||
parser.add_argument('--insert',
|
||||
action='store_true',
|
||||
help='whether to insert data')
|
||||
parser.add_argument('--search',
|
||||
action='store_true',
|
||||
help='whether to search data')
|
||||
parser.add_argument('--batch_size',
|
||||
default=100000,
|
||||
type=int,
|
||||
help='number of examples to insert each time')
|
||||
parser.add_argument(
|
||||
"--data_path", default="milvus/milvus_data.csv", type=str, required=True, help="The data for vector extraction."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--embedding_path", default="corpus_embedding.npy", type=str, required=True, help="The vector path for data."
|
||||
)
|
||||
parser.add_argument("--index", default=0, type=int, help="index of the vector for search")
|
||||
parser.add_argument("--insert", action="store_true", help="whether to insert data")
|
||||
parser.add_argument("--search", action="store_true", help="whether to search data")
|
||||
parser.add_argument("--batch_size", default=100000, type=int, help="number of examples to insert each time")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -66,44 +52,41 @@ def milvus_data_insert(data_path, embedding_path, batch_size):
|
||||
data_size = len(embedding_ids)
|
||||
for i in tqdm(range(0, data_size, batch_size)):
|
||||
cur_end = i + batch_size
|
||||
if (cur_end > data_size):
|
||||
if cur_end > data_size:
|
||||
cur_end = data_size
|
||||
batch_emb = embeddings[np.arange(i, cur_end)]
|
||||
entities = [
|
||||
[j for j in range(i, cur_end, 1)],
|
||||
[corpus_list[j][:text_max_len - 1] for j in range(i, cur_end, 1)],
|
||||
batch_emb # field embeddings, supports numpy.ndarray and list
|
||||
[corpus_list[j][: text_max_len - 1] for j in range(i, cur_end, 1)],
|
||||
batch_emb, # field embeddings, supports numpy.ndarray and list
|
||||
]
|
||||
client.insert(collection_name=collection_name,
|
||||
entities=entities,
|
||||
index_name=embedding_name,
|
||||
partition_tag=partition_tag)
|
||||
client.insert(
|
||||
collection_name=collection_name, entities=entities, index_name=embedding_name, partition_tag=partition_tag
|
||||
)
|
||||
|
||||
|
||||
def milvus_data_recall(embedding_path, index):
|
||||
embeddings = np.load(embedding_path)
|
||||
embedding_ids = [i for i in range(embeddings.shape[0])]
|
||||
recall_client = RecallByMilvus()
|
||||
if (index > len(embedding_ids)):
|
||||
print('Index should not be larger than embedding szie')
|
||||
if index > len(embedding_ids):
|
||||
print("Index should not be larger than embedding szie")
|
||||
return
|
||||
embeddings = embeddings[np.arange(index, index + 1)]
|
||||
time_start = time.time()
|
||||
result = recall_client.search(embeddings,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'text'])
|
||||
result = recall_client.search(
|
||||
embeddings, embedding_name, collection_name, partition_names=[partition_tag], output_fields=["pk", "text"]
|
||||
)
|
||||
time_end = time.time()
|
||||
sum_t = time_end - time_start
|
||||
print('time cost', sum_t, 's')
|
||||
print("time cost", sum_t, "s")
|
||||
for hits in result:
|
||||
for hit in hits:
|
||||
print(f"hit: {hit}, text field: {hit.entity.get('text')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if (args.insert):
|
||||
if args.insert:
|
||||
milvus_data_insert(args.data_path, args.embedding_path, args.batch_size)
|
||||
if (args.search):
|
||||
if args.search:
|
||||
milvus_data_recall(args.embedding_path, args.index)
|
||||
|
||||
@@ -29,19 +29,14 @@ from config import MILVUS_HOST, MILVUS_PORT, data_dim, index_config, top_k, sear
|
||||
fmt = "\n=== {:30} ===\n"
|
||||
text_max_len = 1000
|
||||
fields = [
|
||||
FieldSchema(name="pk",
|
||||
dtype=DataType.INT64,
|
||||
is_primary=True,
|
||||
auto_id=False,
|
||||
max_length=100),
|
||||
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=False, max_length=100),
|
||||
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=text_max_len),
|
||||
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=data_dim)
|
||||
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=data_dim),
|
||||
]
|
||||
schema = CollectionSchema(fields, "Neural Search Index")
|
||||
|
||||
|
||||
class VecToMilvus():
|
||||
|
||||
class VecToMilvus:
|
||||
def __init__(self):
|
||||
print(fmt.format("start connecting to Milvus"))
|
||||
connections.connect("default", host=MILVUS_HOST, port=MILVUS_PORT)
|
||||
@@ -58,9 +53,7 @@ class VecToMilvus():
|
||||
def creat_collection(self, collection_name):
|
||||
try:
|
||||
print(fmt.format("Create collection {}".format(collection_name)))
|
||||
self.collection = Collection(collection_name,
|
||||
schema,
|
||||
consistency_level="Strong")
|
||||
self.collection = Collection(collection_name, schema, consistency_level="Strong")
|
||||
except Exception as e:
|
||||
print("Milvus create collection error:", e)
|
||||
|
||||
@@ -89,9 +82,9 @@ class VecToMilvus():
|
||||
def create_partition(self, partition_tag):
|
||||
try:
|
||||
self.collection.create_partition(partition_tag)
|
||||
print('create partition {} successfully'.format(partition_tag))
|
||||
print("create partition {} successfully".format(partition_tag))
|
||||
except Exception as e:
|
||||
print('Milvus create partition error: ', e)
|
||||
print("Milvus create partition error: ", e)
|
||||
|
||||
def insert(self, entities, collection_name, index_name, partition_tag=None):
|
||||
try:
|
||||
@@ -100,20 +93,16 @@ class VecToMilvus():
|
||||
self.create_index(index_name)
|
||||
else:
|
||||
self.collection = Collection(collection_name)
|
||||
if (partition_tag
|
||||
is not None) and (not self.has_partition(partition_tag)):
|
||||
if (partition_tag is not None) and (not self.has_partition(partition_tag)):
|
||||
self.create_partition(partition_tag)
|
||||
|
||||
self.collection.insert(entities, partition_name=partition_tag)
|
||||
print(
|
||||
f"Number of entities in Milvus: {self.collection.num_entities}"
|
||||
) # check the num_entites
|
||||
print(f"Number of entities in Milvus: {self.collection.num_entities}") # check the num_entites
|
||||
except Exception as e:
|
||||
print("Milvus insert error:", e)
|
||||
|
||||
|
||||
class RecallByMilvus():
|
||||
|
||||
class RecallByMilvus:
|
||||
def __init__(self):
|
||||
print(fmt.format("start connecting to Milvus"))
|
||||
connections.connect("default", host=MILVUS_HOST, port=MILVUS_PORT)
|
||||
@@ -126,55 +115,50 @@ class RecallByMilvus():
|
||||
except Exception as e:
|
||||
print("Milvus create collection error:", e)
|
||||
|
||||
def search(self,
|
||||
vectors,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[],
|
||||
output_fields=[]):
|
||||
def search(self, vectors, embedding_name, collection_name, partition_names=[], output_fields=[]):
|
||||
try:
|
||||
self.get_collection(collection_name)
|
||||
result = self.collection.search(vectors,
|
||||
embedding_name,
|
||||
search_params,
|
||||
limit=top_k,
|
||||
partition_names=partition_names,
|
||||
output_fields=output_fields)
|
||||
result = self.collection.search(
|
||||
vectors,
|
||||
embedding_name,
|
||||
search_params,
|
||||
limit=top_k,
|
||||
partition_names=partition_names,
|
||||
output_fields=output_fields,
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
print('Milvus recall error: ', e)
|
||||
print("Milvus recall error: ", e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
print(fmt.format("Start inserting entities"))
|
||||
rng = np.random.default_rng(seed=19530)
|
||||
num_entities = 3000
|
||||
entities = [
|
||||
# provide the pk field because `auto_id` is set to False
|
||||
[i for i in range(num_entities)],
|
||||
['第{}个样本'.format(i)
|
||||
for i in range(num_entities)], # field text, only supports list
|
||||
rng.random(
|
||||
(num_entities,
|
||||
data_dim)), # field embeddings, supports numpy.ndarray and list
|
||||
["第{}个样本".format(i) for i in range(num_entities)], # field text, only supports list
|
||||
rng.random((num_entities, data_dim)), # field embeddings, supports numpy.ndarray and list
|
||||
]
|
||||
print(entities[-1].shape)
|
||||
collection_name = 'test1'
|
||||
partition_tag = 'partition_1'
|
||||
embedding_name = 'embeddings'
|
||||
collection_name = "test1"
|
||||
partition_tag = "partition_1"
|
||||
embedding_name = "embeddings"
|
||||
client = VecToMilvus()
|
||||
client.insert(collection_name=collection_name,
|
||||
entities=entities,
|
||||
index_name=embedding_name,
|
||||
partition_tag=partition_tag)
|
||||
client.insert(
|
||||
collection_name=collection_name, entities=entities, index_name=embedding_name, partition_tag=partition_tag
|
||||
)
|
||||
print(fmt.format("Start searching entities"))
|
||||
vectors_to_search = entities[-1][-2:]
|
||||
recall_client = RecallByMilvus()
|
||||
result = recall_client.search(vectors_to_search,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'text'])
|
||||
result = recall_client.search(
|
||||
vectors_to_search,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=["pk", "text"],
|
||||
)
|
||||
for hits in result:
|
||||
for hit in hits:
|
||||
print(f"hit: {hit}, random field: {hit.entity.get('text')}")
|
||||
|
||||
@@ -21,7 +21,7 @@ from paddlenlp.utils.log import logger
|
||||
|
||||
def build_index(args, data_loader, model):
|
||||
|
||||
index = hnswlib.Index(space='ip', dim=args.output_emb_size)
|
||||
index = hnswlib.Index(space="ip", dim=args.output_emb_size)
|
||||
|
||||
# Initializing index
|
||||
# max_elements - the maximum number of elements (capacity). Will throw an exception if exceeded
|
||||
@@ -32,9 +32,7 @@ def build_index(args, data_loader, model):
|
||||
#
|
||||
# M - is tightly connected with internal dimensionality of the data. Strongly affects memory consumption (~M)
|
||||
# Higher M leads to higher accuracy/run_time at fixed ef/efConstruction
|
||||
index.init_index(max_elements=args.hnsw_max_elements,
|
||||
ef_construction=args.hnsw_ef,
|
||||
M=args.hnsw_m)
|
||||
index.init_index(max_elements=args.hnsw_max_elements, ef_construction=args.hnsw_ef, M=args.hnsw_m)
|
||||
|
||||
# Controlling the recall by setting ef:
|
||||
# higher ef leads to better accuracy, but slower search
|
||||
|
||||
@@ -19,46 +19,32 @@ import paddle
|
||||
from paddlenlp.utils.log import logger
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
|
||||
def convert_example_test(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example_test(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -69,9 +55,7 @@ def convert_example_test(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -81,16 +65,16 @@ def convert_example_test(example,
|
||||
def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -102,9 +86,9 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
result = []
|
||||
|
||||
for key, text in example.items():
|
||||
if 'label' in key:
|
||||
if "label" in key:
|
||||
# do_evaluate
|
||||
result += [example['label']]
|
||||
result += [example["label"]]
|
||||
else:
|
||||
# do_train
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length)
|
||||
@@ -117,7 +101,7 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
|
||||
def gen_id2corpus(corpus_file):
|
||||
id2corpus = {}
|
||||
with open(corpus_file, 'r', encoding='utf-8') as f:
|
||||
with open(corpus_file, "r", encoding="utf-8") as f:
|
||||
for idx, line in enumerate(f):
|
||||
id2corpus[idx] = line.rstrip()
|
||||
return id2corpus
|
||||
@@ -126,7 +110,7 @@ def gen_id2corpus(corpus_file):
|
||||
def gen_text_file(similar_text_pair_file):
|
||||
text2similar_text = {}
|
||||
texts = []
|
||||
with open(similar_text_pair_file, 'r', encoding='utf-8') as f:
|
||||
with open(similar_text_pair_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
splited_line = line.rstrip().split("\t")
|
||||
if len(splited_line) != 2:
|
||||
@@ -144,22 +128,22 @@ def gen_text_file(similar_text_pair_file):
|
||||
|
||||
def read_simcse_text(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip()
|
||||
yield {'text_a': data, 'text_b': data}
|
||||
yield {"text_a": data, "text_b": data}
|
||||
|
||||
|
||||
def read_text_pair(data_path, is_test=False):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if is_test == False:
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1], 'label': data[2]}
|
||||
yield {"text_a": data[0], "text_b": data[1], "label": data[2]}
|
||||
else:
|
||||
if len(data) != 2:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1]}
|
||||
yield {"text_a": data[0], "text_b": data[1]}
|
||||
|
||||
@@ -26,7 +26,7 @@ from paddlenlp.data import Stack, Tuple, Pad
|
||||
from paddlenlp.datasets import load_dataset
|
||||
from paddlenlp.utils.log import logger
|
||||
|
||||
sys.path.append('.')
|
||||
sys.path.append(".")
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -62,16 +62,16 @@ args = parser.parse_args()
|
||||
def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -92,16 +92,17 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -120,14 +121,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -143,15 +144,12 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
if args.benchmark:
|
||||
import auto_log
|
||||
|
||||
pid = os.getpid()
|
||||
self.autolog = auto_log.AutoLogger(
|
||||
model_name=args.model_name_or_path,
|
||||
@@ -163,11 +161,10 @@ class Predictor(object):
|
||||
pids=pid,
|
||||
process_name=None,
|
||||
gpu_ids=0,
|
||||
time_keys=[
|
||||
'preprocess_time', 'inference_time', 'postprocess_time'
|
||||
],
|
||||
time_keys=["preprocess_time", "inference_time", "postprocess_time"],
|
||||
warmup=0,
|
||||
logger=logger)
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
def extract_embedding(self, data, tokenizer):
|
||||
"""
|
||||
@@ -175,7 +172,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -216,7 +213,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -228,10 +225,8 @@ class Predictor(object):
|
||||
examples = []
|
||||
for idx, text in enumerate(data):
|
||||
input_ids, segment_ids = convert_example({idx: text[0]}, tokenizer)
|
||||
title_ids, title_segment_ids = convert_example({idx: text[1]},
|
||||
tokenizer)
|
||||
examples.append(
|
||||
(input_ids, segment_ids, title_ids, title_segment_ids))
|
||||
title_ids, title_segment_ids = convert_example({idx: text[1]}, tokenizer)
|
||||
examples.append((input_ids, segment_ids, title_ids, title_segment_ids))
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id), # input
|
||||
@@ -243,8 +238,7 @@ class Predictor(object):
|
||||
if args.benchmark:
|
||||
self.autolog.times.stamp()
|
||||
|
||||
query_ids, query_segment_ids, title_ids, title_segment_ids = batchify_fn(
|
||||
examples)
|
||||
query_ids, query_segment_ids, title_ids, title_segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(query_ids)
|
||||
self.input_handles[1].copy_from_cpu(query_segment_ids)
|
||||
self.predictor.run()
|
||||
@@ -260,28 +254,31 @@ class Predictor(object):
|
||||
|
||||
if args.benchmark:
|
||||
self.autolog.times.end(stamp=True)
|
||||
result = [
|
||||
float(1 - spatial.distance.cosine(arr1, arr2))
|
||||
for arr1, arr2 in zip(query_logits, title_logits)
|
||||
]
|
||||
result = [float(1 - spatial.distance.cosine(arr1, arr2)) for arr1, arr2 in zip(query_logits, title_logits)]
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Define predictor to do prediction.
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
# ErnieTinyTokenizer is special for ernie-tiny pretained model.
|
||||
output_emb_size = 256
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
id2corpus = {0: '国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}
|
||||
id2corpus = {0: "国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据"}
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
res = predictor.extract_embedding(corpus_list, tokenizer)
|
||||
print(res.shape)
|
||||
print(res)
|
||||
corpus_list = [['中西方语言与文化的差异', '中西方文化差异以及语言体现中西方文化,差异,语言体现'],
|
||||
['中西方语言与文化的差异', '飞桨致力于让深度学习技术的创新与应用更简单']]
|
||||
corpus_list = [["中西方语言与文化的差异", "中西方文化差异以及语言体现中西方文化,差异,语言体现"], ["中西方语言与文化的差异", "飞桨致力于让深度学习技术的创新与应用更简单"]]
|
||||
res = predictor.predict(corpus_list, tokenizer)
|
||||
print(res)
|
||||
|
||||
@@ -52,14 +52,14 @@ def recall(rs, N=10):
|
||||
|
||||
if __name__ == "__main__":
|
||||
text2similar = {}
|
||||
with open(args.similar_text_pair, 'r', encoding='utf-8') as f:
|
||||
with open(args.similar_text_pair, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
text, similar_text = line.rstrip().split("\t")
|
||||
text2similar[text] = similar_text
|
||||
|
||||
rs = []
|
||||
|
||||
with open(args.recall_result_file, 'r', encoding='utf-8') as f:
|
||||
with open(args.recall_result_file, "r", encoding="utf-8") as f:
|
||||
relevance_labels = []
|
||||
for index, line in enumerate(f):
|
||||
|
||||
@@ -75,12 +75,12 @@ if __name__ == "__main__":
|
||||
|
||||
recall_N = []
|
||||
recall_num = [1, 5, 10, 20, 50]
|
||||
result = open('result.tsv', 'a')
|
||||
result = open("result.tsv", "a")
|
||||
res = []
|
||||
for topN in recall_num:
|
||||
R = round(100 * recall(rs, N=topN), 3)
|
||||
recall_N.append(str(R))
|
||||
for key, val in zip(recall_num, recall_N):
|
||||
print('recall@{}={}'.format(key, val))
|
||||
print("recall@{}={}".format(key, val))
|
||||
res.append(str(val))
|
||||
result.write('\t'.join(res) + '\n')
|
||||
result.write("\t".join(res) + "\n")
|
||||
|
||||
@@ -51,11 +51,10 @@ if __name__ == "__main__":
|
||||
model = paddle.jit.to_static(
|
||||
model,
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64") # segment_ids
|
||||
])
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # segment_ids
|
||||
],
|
||||
)
|
||||
# Save in static graph model.
|
||||
save_path = os.path.join(args.output_path, "inference")
|
||||
paddle.jit.save(model, save_path)
|
||||
|
||||
@@ -35,16 +35,16 @@ from tqdm import tqdm
|
||||
def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -65,25 +65,21 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
device = 'gpu'
|
||||
device = "gpu"
|
||||
max_seq_length = 64
|
||||
output_emb_size = 256
|
||||
batch_size = 1
|
||||
params_path = 'checkpoints/model_20000/model_state.pdparams'
|
||||
id2corpus = {0: '国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据'}
|
||||
params_path = "checkpoints/model_20000/model_state.pdparams"
|
||||
id2corpus = {0: "国有企业引入非国有资本对创新绩效的影响——基于制造业国有上市公司的经验证据"}
|
||||
model_name_or_path = "rocketqa-zh-base-query-encoder"
|
||||
paddle.set_device(device)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=max_seq_length)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # text_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # text_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(model_name_or_path)
|
||||
@@ -96,18 +92,15 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
# conver_example function's input must be dict
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
all_embeddings = []
|
||||
model.eval()
|
||||
@@ -115,8 +108,7 @@ if __name__ == "__main__":
|
||||
for batch_data in corpus_data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
|
||||
text_embeddings = model.get_pooled_embedding(
|
||||
input_ids, token_type_ids)
|
||||
text_embeddings = model.get_pooled_embedding(input_ids, token_type_ids)
|
||||
all_embeddings.append(text_embeddings)
|
||||
|
||||
text_embedding = all_embeddings[0]
|
||||
|
||||
@@ -23,13 +23,7 @@ import paddle.nn.functional as F
|
||||
|
||||
|
||||
class SimCSE(nn.Layer):
|
||||
|
||||
def __init__(self,
|
||||
pretrained_model,
|
||||
dropout=None,
|
||||
margin=0.0,
|
||||
scale=20,
|
||||
output_emb_size=None):
|
||||
def __init__(self, pretrained_model, dropout=None, margin=0.0, scale=20, output_emb_size=None):
|
||||
|
||||
super().__init__()
|
||||
|
||||
@@ -41,30 +35,25 @@ class SimCSE(nn.Layer):
|
||||
# recall performance and efficiency
|
||||
self.output_emb_size = output_emb_size
|
||||
if output_emb_size > 0:
|
||||
weight_attr = paddle.ParamAttr(
|
||||
initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768,
|
||||
output_emb_size,
|
||||
weight_attr=weight_attr)
|
||||
weight_attr = paddle.ParamAttr(initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768, output_emb_size, weight_attr=weight_attr)
|
||||
|
||||
self.margin = margin
|
||||
# Used scaling cosine similarity to ease converge
|
||||
self.sacle = scale
|
||||
|
||||
@paddle.jit.to_static(input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64'),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64')
|
||||
])
|
||||
def get_pooled_embedding(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None,
|
||||
with_pooler=True):
|
||||
@paddle.jit.to_static(
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
]
|
||||
)
|
||||
def get_pooled_embedding(
|
||||
self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None, with_pooler=True
|
||||
):
|
||||
|
||||
# Note: cls_embedding is poolerd embedding with act tanh
|
||||
sequence_output, cls_embedding = self.ptm(input_ids, token_type_ids,
|
||||
position_ids, attention_mask)
|
||||
sequence_output, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if with_pooler == False:
|
||||
cls_embedding = sequence_output[:, 0, :]
|
||||
@@ -85,73 +74,67 @@ class SimCSE(nn.Layer):
|
||||
input_ids = paddle.to_tensor(input_ids)
|
||||
token_type_ids = paddle.to_tensor(token_type_ids)
|
||||
|
||||
text_embeddings = self.get_pooled_embedding(
|
||||
input_ids, token_type_ids=token_type_ids)
|
||||
text_embeddings = self.get_pooled_embedding(input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
yield text_embeddings
|
||||
|
||||
def cosine_sim(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
with_pooler=True):
|
||||
def cosine_sim(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
with_pooler=True,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask,
|
||||
with_pooler=with_pooler)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask, with_pooler=with_pooler
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask,
|
||||
with_pooler=with_pooler)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask, with_pooler=with_pooler
|
||||
)
|
||||
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding,
|
||||
axis=-1)
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding, axis=-1)
|
||||
return cosine_sim
|
||||
|
||||
def forward(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def forward(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
cosine_sim = paddle.matmul(query_cls_embedding,
|
||||
title_cls_embedding,
|
||||
transpose_y=True)
|
||||
cosine_sim = paddle.matmul(query_cls_embedding, title_cls_embedding, transpose_y=True)
|
||||
|
||||
# substract margin from all positive samples cosine_sim()
|
||||
margin_diag = paddle.full(shape=[query_cls_embedding.shape[0]],
|
||||
fill_value=self.margin,
|
||||
dtype=paddle.get_default_dtype())
|
||||
margin_diag = paddle.full(
|
||||
shape=[query_cls_embedding.shape[0]], fill_value=self.margin, dtype=paddle.get_default_dtype()
|
||||
)
|
||||
|
||||
cosine_sim = cosine_sim - paddle.diag(margin_diag)
|
||||
|
||||
# scale cosine to ease training converge
|
||||
cosine_sim *= self.sacle
|
||||
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype='int64')
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype="int64")
|
||||
labels = paddle.reshape(labels, shape=[-1, 1])
|
||||
|
||||
loss = F.cross_entropy(input=cosine_sim, label=labels)
|
||||
|
||||
@@ -70,7 +70,8 @@ def predict(model, data_loader):
|
||||
query_input_ids=query_input_ids,
|
||||
title_input_ids=title_input_ids,
|
||||
query_token_type_ids=query_token_type_ids,
|
||||
title_token_type_ids=title_token_type_ids).numpy()
|
||||
title_token_type_ids=title_token_type_ids,
|
||||
).numpy()
|
||||
|
||||
cosine_sims.append(batch_cosine_sim)
|
||||
|
||||
@@ -84,9 +85,7 @@ if __name__ == "__main__":
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length)
|
||||
trans_func = partial(convert_example, tokenizer=tokenizer, max_seq_length=args.max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id), # query_input
|
||||
@@ -95,33 +94,24 @@ if __name__ == "__main__":
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id), # tilte_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
valid_ds = load_dataset(read_text_pair,
|
||||
data_path=args.text_pair_file,
|
||||
lazy=False,
|
||||
is_test=True)
|
||||
valid_ds = load_dataset(read_text_pair, data_path=args.text_pair_file, lazy=False, is_test=True)
|
||||
|
||||
valid_data_loader = create_dataloader(valid_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
valid_data_loader = create_dataloader(
|
||||
valid_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
|
||||
model = SimCSE(pretrained_model,
|
||||
margin=args.margin,
|
||||
scale=args.scale,
|
||||
output_emb_size=args.output_emb_size)
|
||||
model = SimCSE(pretrained_model, margin=args.margin, scale=args.scale, output_emb_size=args.output_emb_size)
|
||||
|
||||
if args.params_path and os.path.isfile(args.params_path):
|
||||
state_dict = paddle.load(args.params_path)
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
cosin_sim = predict(model, valid_data_loader)
|
||||
|
||||
for idx, cosine in enumerate(cosin_sim):
|
||||
print('{}'.format(cosine))
|
||||
print("{}".format(cosine))
|
||||
|
||||
@@ -63,15 +63,11 @@ if __name__ == "__main__":
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example_test,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length)
|
||||
trans_func = partial(convert_example_test, tokenizer=tokenizer, max_seq_length=args.max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"
|
||||
), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # text_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # text_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
@@ -85,8 +81,7 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
logger.info("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
id2corpus = gen_id2corpus(args.corpus_file)
|
||||
|
||||
@@ -94,11 +89,9 @@ if __name__ == "__main__":
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
# Need better way to get inner model of DataParallel
|
||||
inner_model = model._layers
|
||||
@@ -109,29 +102,27 @@ if __name__ == "__main__":
|
||||
|
||||
query_ds = MapDataset(text_list)
|
||||
|
||||
query_data_loader = create_dataloader(query_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
query_data_loader = create_dataloader(
|
||||
query_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
query_embedding = inner_model.get_semantic_embedding(query_data_loader)
|
||||
|
||||
if not os.path.exists(args.recall_result_dir):
|
||||
os.mkdir(args.recall_result_dir)
|
||||
|
||||
recall_result_file = os.path.join(args.recall_result_dir,
|
||||
args.recall_result_file)
|
||||
with open(recall_result_file, 'w', encoding='utf-8') as f:
|
||||
recall_result_file = os.path.join(args.recall_result_dir, args.recall_result_file)
|
||||
with open(recall_result_file, "w", encoding="utf-8") as f:
|
||||
for batch_index, batch_query_embedding in enumerate(query_embedding):
|
||||
recalled_idx, cosine_sims = final_index.knn_query(
|
||||
batch_query_embedding.numpy(), args.recall_num)
|
||||
recalled_idx, cosine_sims = final_index.knn_query(batch_query_embedding.numpy(), args.recall_num)
|
||||
|
||||
batch_size = len(cosine_sims)
|
||||
|
||||
for row_index in range(batch_size):
|
||||
text_index = args.batch_size * batch_index + row_index
|
||||
for idx, doc_idx in enumerate(recalled_idx[row_index]):
|
||||
f.write("{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx],
|
||||
1.0 - cosine_sims[row_index][idx]))
|
||||
f.write(
|
||||
"{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx], 1.0 - cosine_sims[row_index][idx]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ import sys
|
||||
import random
|
||||
import time
|
||||
|
||||
sys.path.append('./recall/milvus')
|
||||
sys.path.append("./recall/milvus")
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from tqdm import tqdm
|
||||
@@ -30,15 +30,14 @@ from config import collection_name, partition_tag, embedding_name
|
||||
|
||||
def recall_result(list_data):
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8080'])
|
||||
client.connect(["127.0.0.1:8080"])
|
||||
feed = {}
|
||||
for i, item in enumerate(list_data):
|
||||
feed[str(i)] = item
|
||||
start_time = time.time()
|
||||
ret = client.predict(feed_dict=feed)
|
||||
end_time = time.time()
|
||||
print("Extract feature time to cost :{} seconds".format(end_time -
|
||||
start_time))
|
||||
print("Extract feature time to cost :{} seconds".format(end_time - start_time))
|
||||
result = np.array(eval(ret.value[0]))
|
||||
return result
|
||||
|
||||
@@ -46,32 +45,29 @@ def recall_result(list_data):
|
||||
def search_in_milvus(embeddings, query_text):
|
||||
recall_client = RecallByMilvus()
|
||||
start_time = time.time()
|
||||
results = recall_client.search(embeddings,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'text'])
|
||||
results = recall_client.search(
|
||||
embeddings, embedding_name, collection_name, partition_names=[partition_tag], output_fields=["pk", "text"]
|
||||
)
|
||||
end_time = time.time()
|
||||
print('Search milvus time cost is {} seconds '.format(end_time -
|
||||
start_time))
|
||||
print("Search milvus time cost is {} seconds ".format(end_time - start_time))
|
||||
list_data = []
|
||||
for line in results:
|
||||
for item in line:
|
||||
idx = item.id
|
||||
distance = item.distance
|
||||
text = item.entity.get('text')
|
||||
text = item.entity.get("text")
|
||||
list_data.append([query_text, text, distance])
|
||||
df = pd.DataFrame(list_data, columns=['query_text', 'text', 'distance'])
|
||||
df.to_csv('recall_result.csv', index=False)
|
||||
df = pd.DataFrame(list_data, columns=["query_text", "text", "distance"])
|
||||
df.to_csv("recall_result.csv", index=False)
|
||||
return df
|
||||
|
||||
|
||||
def rerank(df):
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8089'])
|
||||
client.connect(["127.0.0.1:8089"])
|
||||
list_data = []
|
||||
for index, row in df.iterrows():
|
||||
example = {"query": row['query_text'], "title": row['text']}
|
||||
example = {"query": row["query_text"], "title": row["text"]}
|
||||
list_data.append(example)
|
||||
feed = {}
|
||||
for i, item in enumerate(list_data):
|
||||
@@ -82,9 +78,9 @@ def rerank(df):
|
||||
end_time = time.time()
|
||||
print("time to cost :{} seconds".format(end_time - start_time))
|
||||
result = np.array(eval(ret.value[0]))
|
||||
df['distance'] = result
|
||||
df["distance"] = result
|
||||
df = df.sort_values(by=["distance"], ascending=False)
|
||||
df.to_csv('rank_result.csv', index=False)
|
||||
df.to_csv("rank_result.csv", index=False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -19,9 +19,7 @@ from paddlenlp.utils.log import logger
|
||||
|
||||
def build_index(args, data_loader, model):
|
||||
|
||||
index = hnswlib.Index(
|
||||
space='ip',
|
||||
dim=args.output_emb_size if args.output_emb_size > 0 else 768)
|
||||
index = hnswlib.Index(space="ip", dim=args.output_emb_size if args.output_emb_size > 0 else 768)
|
||||
|
||||
# Initializing index
|
||||
# max_elements - the maximum number of elements (capacity). Will throw an exception if exceeded
|
||||
@@ -32,9 +30,7 @@ def build_index(args, data_loader, model):
|
||||
#
|
||||
# M - is tightly connected with internal dimensionality of the data. Strongly affects memory consumption (~M)
|
||||
# Higher M leads to higher accuracy/run_time at fixed ef/efConstruction
|
||||
index.init_index(max_elements=args.hnsw_max_elements,
|
||||
ef_construction=args.hnsw_ef,
|
||||
M=args.hnsw_m)
|
||||
index.init_index(max_elements=args.hnsw_max_elements, ef_construction=args.hnsw_ef, M=args.hnsw_m)
|
||||
|
||||
# Controlling the recall by setting ef:
|
||||
# higher ef leads to better accuracy, but slower search
|
||||
|
||||
@@ -12,27 +12,23 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
search_param = {'nprobe': 20}
|
||||
collection_name = 'faq_finance'
|
||||
partition_tag = 'partition_1'
|
||||
search_param = {"nprobe": 20}
|
||||
collection_name = "faq_finance"
|
||||
partition_tag = "partition_1"
|
||||
|
||||
MILVUS_HOST = '10.21.226.175'
|
||||
MILVUS_HOST = "10.21.226.175"
|
||||
MILVUS_PORT = 8530
|
||||
data_dim = 256
|
||||
top_k = 10
|
||||
embedding_name = 'embeddings'
|
||||
embedding_name = "embeddings"
|
||||
|
||||
index_config = {
|
||||
"index_type": "IVF_FLAT",
|
||||
"metric_type": "L2",
|
||||
"params": {
|
||||
"nlist": 1000
|
||||
},
|
||||
"params": {"nlist": 1000},
|
||||
}
|
||||
|
||||
search_params = {
|
||||
"metric_type": "L2",
|
||||
"params": {
|
||||
"nprobe": top_k
|
||||
},
|
||||
"params": {"nprobe": top_k},
|
||||
}
|
||||
|
||||
@@ -21,49 +21,38 @@ import paddle
|
||||
|
||||
def gen_id2corpus(corpus_file):
|
||||
id2corpus = {}
|
||||
with open(corpus_file, 'r', encoding='utf-8') as f:
|
||||
with open(corpus_file, "r", encoding="utf-8") as f:
|
||||
for idx, line in enumerate(f):
|
||||
id2corpus[idx] = line.rstrip()
|
||||
return id2corpus
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
|
||||
def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -75,9 +64,9 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
result = []
|
||||
|
||||
for key, text in example.items():
|
||||
if 'label' in key:
|
||||
if "label" in key:
|
||||
# do_evaluate
|
||||
result += [example['label']]
|
||||
result += [example["label"]]
|
||||
else:
|
||||
# do_train
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length)
|
||||
@@ -88,22 +77,19 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
return result
|
||||
|
||||
|
||||
def convert_example_test(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example_test(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -114,9 +100,7 @@ def convert_example_test(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -125,32 +109,32 @@ def convert_example_test(example,
|
||||
|
||||
def read_simcse_text(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip()
|
||||
yield {'text_a': data, 'text_b': data}
|
||||
yield {"text_a": data, "text_b": data}
|
||||
|
||||
|
||||
def read_text_pair(data_path, is_test=False):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if is_test == True:
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1], 'label': data[2]}
|
||||
yield {"text_a": data[0], "text_b": data[1], "label": data[2]}
|
||||
else:
|
||||
if len(data) != 2:
|
||||
continue
|
||||
|
||||
yield {'text_a': data[0], 'text_b': data[1]}
|
||||
yield {"text_a": data[0], "text_b": data[1]}
|
||||
|
||||
|
||||
def gen_text_file(similar_text_pair_file):
|
||||
text2similar_text = {}
|
||||
texts = []
|
||||
with open(similar_text_pair_file, 'r', encoding='utf-8') as f:
|
||||
with open(similar_text_pair_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
splited_line = line.rstrip().split("\t")
|
||||
if len(splited_line) != 2:
|
||||
@@ -180,11 +164,10 @@ def word_repetition(input_ids, token_type_ids, dup_rate=0.32):
|
||||
actual_len = np.count_nonzero(cur_input_id)
|
||||
dup_word_index = []
|
||||
# If sequence length is less than 5, skip it
|
||||
if (actual_len > 5):
|
||||
if actual_len > 5:
|
||||
dup_len = random.randint(a=0, b=max(2, int(dup_rate * actual_len)))
|
||||
# Skip cls and sep position
|
||||
dup_word_index = random.sample(list(range(1, actual_len - 1)),
|
||||
k=dup_len)
|
||||
dup_word_index = random.sample(list(range(1, actual_len - 1)), k=dup_len)
|
||||
|
||||
r_input_id = []
|
||||
r_token_type_id = []
|
||||
@@ -208,6 +191,6 @@ def word_repetition(input_ids, token_type_ids, dup_rate=0.32):
|
||||
repetitied_input_ids[batch_id] += [0] * pad_len
|
||||
repetitied_token_type_ids[batch_id] += [0] * pad_len
|
||||
|
||||
return paddle.to_tensor(repetitied_input_ids,
|
||||
dtype='int64'), paddle.to_tensor(
|
||||
repetitied_token_type_ids, dtype='int64')
|
||||
return paddle.to_tensor(repetitied_input_ids, dtype="int64"), paddle.to_tensor(
|
||||
repetitied_token_type_ids, dtype="int64"
|
||||
)
|
||||
|
||||
@@ -27,5 +27,5 @@ print(data)
|
||||
r = requests.post(url=url, headers=headers, data=data)
|
||||
print(r.json())
|
||||
json_data = r.json()
|
||||
data = np.array(json_data['result']['output_embedding'])
|
||||
print(data.shape)
|
||||
data = np.array(json_data["result"]["output_embedding"])
|
||||
print(data.shape)
|
||||
|
||||
@@ -17,7 +17,7 @@ import numpy as np
|
||||
from paddle_serving_server.pipeline import PipelineClient
|
||||
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8080'])
|
||||
client.connect(["127.0.0.1:8080"])
|
||||
|
||||
list_data = ["买了社保,是不是就不用买商业保险了?"]
|
||||
feed = {}
|
||||
|
||||
@@ -25,15 +25,10 @@ args = parser.parse_args()
|
||||
# yapf: enable
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
result = []
|
||||
for text in example:
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -41,43 +36,38 @@ def convert_example(example,
|
||||
|
||||
|
||||
class ErnieOp(Op):
|
||||
|
||||
def init_op(self):
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
|
||||
self.tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
def preprocess(self, input_dicts, data_id, log_id):
|
||||
from paddlenlp.data import Stack, Tuple, Pad
|
||||
|
||||
(_, input_dict), = input_dicts.items()
|
||||
((_, input_dict),) = input_dicts.items()
|
||||
print("input dict", input_dict)
|
||||
batch_size = len(input_dict.keys())
|
||||
examples = []
|
||||
for i in range(batch_size):
|
||||
input_ids, segment_ids = convert_example([input_dict[str(i)]],
|
||||
self.tokenizer)
|
||||
input_ids, segment_ids = convert_example([input_dict[str(i)]], self.tokenizer)
|
||||
examples.append((input_ids, segment_ids))
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = input_ids
|
||||
feed_dict['token_type_ids'] = segment_ids
|
||||
feed_dict["input_ids"] = input_ids
|
||||
feed_dict["token_type_ids"] = segment_ids
|
||||
return feed_dict, False, None, ""
|
||||
|
||||
def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
|
||||
new_dict = {}
|
||||
new_dict["output_embedding"] = str(
|
||||
fetch_dict["output_embedding"].tolist())
|
||||
new_dict["output_embedding"] = str(fetch_dict["output_embedding"].tolist())
|
||||
return new_dict, None, ""
|
||||
|
||||
|
||||
class ErnieService(WebService):
|
||||
|
||||
def get_pipeline_response(self, read_op):
|
||||
ernie_op = ErnieOp(name="ernie", input_ops=[read_op])
|
||||
return ernie_op
|
||||
|
||||
@@ -25,15 +25,10 @@ args = parser.parse_args()
|
||||
# yapf: enable
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
result = []
|
||||
for text in example:
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -41,13 +36,14 @@ def convert_example(example,
|
||||
|
||||
|
||||
class ErnieService(WebService):
|
||||
|
||||
def init_service(self):
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
|
||||
self.tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
def preprocess(self, feed=[], fetch=[]):
|
||||
from paddlenlp.data import Stack, Tuple, Pad
|
||||
|
||||
print("input dict", feed)
|
||||
batch_size = len(feed)
|
||||
is_batch = True
|
||||
@@ -56,15 +52,13 @@ class ErnieService(WebService):
|
||||
input_ids, segment_ids = convert_example([feed[i]], self.tokenizer)
|
||||
examples.append((input_ids, segment_ids))
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_type_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = input_ids
|
||||
feed_dict['token_type_ids'] = segment_ids
|
||||
feed_dict["input_ids"] = input_ids
|
||||
feed_dict["token_type_ids"] = segment_ids
|
||||
return feed_dict, fetch, is_batch
|
||||
|
||||
def postprocess(self, feed=[], fetch=[], fetch_map=None):
|
||||
|
||||
@@ -50,14 +50,14 @@ def recall(rs, N=10):
|
||||
|
||||
if __name__ == "__main__":
|
||||
text2similar = {}
|
||||
with open(args.similar_text_pair, 'r', encoding='utf-8') as f:
|
||||
with open(args.similar_text_pair, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
text, similar_text = line.rstrip().split("\t")
|
||||
text2similar[text] = similar_text
|
||||
|
||||
rs = []
|
||||
|
||||
with open(args.recall_result_file, 'r', encoding='utf-8') as f:
|
||||
with open(args.recall_result_file, "r", encoding="utf-8") as f:
|
||||
relevance_labels = []
|
||||
for index, line in enumerate(f):
|
||||
|
||||
@@ -72,13 +72,13 @@ if __name__ == "__main__":
|
||||
relevance_labels.append(0)
|
||||
recall_N = []
|
||||
recall_num = [1, 5, 10]
|
||||
result = open('result.tsv', 'a')
|
||||
result = open("result.tsv", "a")
|
||||
res = []
|
||||
for topN in recall_num:
|
||||
R = round(100 * recall(rs, N=topN), 3)
|
||||
recall_N.append(str(R))
|
||||
for key, val in zip(recall_num, recall_N):
|
||||
print('recall@{}={}'.format(key, val))
|
||||
print("recall@{}={}".format(key, val))
|
||||
res.append(str(val))
|
||||
result.write('\t'.join(res) + '\n')
|
||||
result.write("\t".join(res) + "\n")
|
||||
# print("\t".join(recall_N))
|
||||
|
||||
@@ -47,18 +47,16 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
print("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
model.eval()
|
||||
# Convert to static graph with specific input description
|
||||
model = paddle.jit.to_static(
|
||||
model,
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64") # segment_ids
|
||||
])
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # segment_ids
|
||||
],
|
||||
)
|
||||
# Save in static graph model.
|
||||
save_path = os.path.join(args.output_path, "inference")
|
||||
paddle.jit.save(model, save_path)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import argparse
|
||||
import paddle_serving_client.io as serving_io
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dirname", type=str, required=True,
|
||||
@@ -44,4 +45,5 @@ if __name__ == "__main__":
|
||||
params_filename=args.params_filename,
|
||||
show_proto=args.show_proto,
|
||||
feed_alias_names=args.feed_alias_names,
|
||||
fetch_alias_names=args.fetch_alias_names)
|
||||
fetch_alias_names=args.fetch_alias_names,
|
||||
)
|
||||
|
||||
@@ -58,22 +58,19 @@ args = parser.parse_args()
|
||||
# yapf: enable
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -84,9 +81,7 @@ def convert_example(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -94,16 +89,17 @@ def convert_example(example,
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -122,14 +118,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -145,12 +141,8 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
def predict(self, data, tokenizer):
|
||||
"""
|
||||
@@ -158,7 +150,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -166,21 +158,18 @@ class Predictor(object):
|
||||
"""
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
|
||||
all_embeddings = []
|
||||
examples = []
|
||||
for idx, text in enumerate(tqdm(data)):
|
||||
input_ids, segment_ids = convert_example(
|
||||
text,
|
||||
tokenizer,
|
||||
max_seq_length=self.max_seq_length,
|
||||
pad_to_max_seq_len=True)
|
||||
text, tokenizer, max_seq_length=self.max_seq_length, pad_to_max_seq_len=True
|
||||
)
|
||||
examples.append((input_ids, segment_ids))
|
||||
if (len(examples) >= self.batch_size):
|
||||
if len(examples) >= self.batch_size:
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(input_ids)
|
||||
self.input_handles[1].copy_from_cpu(segment_ids)
|
||||
@@ -189,7 +178,7 @@ class Predictor(object):
|
||||
all_embeddings.append(logits)
|
||||
examples = []
|
||||
|
||||
if (len(examples) > 0):
|
||||
if len(examples) > 0:
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(input_ids)
|
||||
self.input_handles[1].copy_from_cpu(segment_ids)
|
||||
@@ -198,7 +187,7 @@ class Predictor(object):
|
||||
all_embeddings.append(logits)
|
||||
|
||||
all_embeddings = np.concatenate(all_embeddings, axis=0)
|
||||
np.save('corpus_embedding', all_embeddings)
|
||||
np.save("corpus_embedding", all_embeddings)
|
||||
|
||||
|
||||
def read_text(file_path):
|
||||
@@ -210,9 +199,16 @@ def read_text(file_path):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
id2corpus = read_text(args.corpus_file)
|
||||
|
||||
@@ -22,30 +22,16 @@ from milvus_util import VecToMilvus, RecallByMilvus, text_max_len
|
||||
from config import collection_name, partition_tag, embedding_name
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--data_path",
|
||||
default='data/corpus.csv',
|
||||
type=str,
|
||||
required=True,
|
||||
help="The data for vector extraction.")
|
||||
parser.add_argument("--embedding_path",
|
||||
default='corpus_embedding.npy',
|
||||
type=str,
|
||||
required=True,
|
||||
help="The vector path for data.")
|
||||
parser.add_argument('--index',
|
||||
default=0,
|
||||
type=int,
|
||||
help='index of the vector for search')
|
||||
parser.add_argument('--insert',
|
||||
action='store_true',
|
||||
help='whether to insert data')
|
||||
parser.add_argument('--search',
|
||||
action='store_true',
|
||||
help='whether to search data')
|
||||
parser.add_argument('--batch_size',
|
||||
default=100000,
|
||||
type=int,
|
||||
help='number of examples to insert each time')
|
||||
parser.add_argument(
|
||||
"--data_path", default="data/corpus.csv", type=str, required=True, help="The data for vector extraction."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--embedding_path", default="corpus_embedding.npy", type=str, required=True, help="The vector path for data."
|
||||
)
|
||||
parser.add_argument("--index", default=0, type=int, help="index of the vector for search")
|
||||
parser.add_argument("--insert", action="store_true", help="whether to insert data")
|
||||
parser.add_argument("--search", action="store_true", help="whether to search data")
|
||||
parser.add_argument("--batch_size", default=100000, type=int, help="number of examples to insert each time")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -53,8 +39,8 @@ def read_text(file_path):
|
||||
file = open(file_path)
|
||||
id2corpus = []
|
||||
for idx, data in enumerate(file.readlines()):
|
||||
question, answer = data.strip().split('\t')
|
||||
id2corpus.append({'question': question, 'answer': answer})
|
||||
question, answer = data.strip().split("\t")
|
||||
id2corpus.append({"question": question, "answer": answer})
|
||||
return id2corpus
|
||||
|
||||
|
||||
@@ -67,51 +53,42 @@ def milvus_data_insert(data_path, embedding_path, batch_size):
|
||||
data_size = len(embedding_ids)
|
||||
for i in tqdm(range(0, data_size, batch_size)):
|
||||
cur_end = i + batch_size
|
||||
if (cur_end > data_size):
|
||||
if cur_end > data_size:
|
||||
cur_end = data_size
|
||||
batch_emb = embeddings[np.arange(i, cur_end)]
|
||||
entities = [
|
||||
[j for j in range(i, cur_end, 1)],
|
||||
[
|
||||
corpus_list[j]['question'][:text_max_len - 1]
|
||||
for j in range(i, cur_end, 1)
|
||||
],
|
||||
[
|
||||
corpus_list[j]['answer'][:text_max_len - 1]
|
||||
for j in range(i, cur_end, 1)
|
||||
],
|
||||
batch_emb # field embeddings, supports numpy.ndarray and list
|
||||
[corpus_list[j]["question"][: text_max_len - 1] for j in range(i, cur_end, 1)],
|
||||
[corpus_list[j]["answer"][: text_max_len - 1] for j in range(i, cur_end, 1)],
|
||||
batch_emb, # field embeddings, supports numpy.ndarray and list
|
||||
]
|
||||
client.insert(collection_name=collection_name,
|
||||
entities=entities,
|
||||
index_name=embedding_name,
|
||||
partition_tag=partition_tag)
|
||||
client.insert(
|
||||
collection_name=collection_name, entities=entities, index_name=embedding_name, partition_tag=partition_tag
|
||||
)
|
||||
|
||||
|
||||
def milvus_data_recall(embedding_path, index):
|
||||
embeddings = np.load(embedding_path)
|
||||
embedding_ids = [i for i in range(embeddings.shape[0])]
|
||||
recall_client = RecallByMilvus()
|
||||
if (index > len(embedding_ids)):
|
||||
print('Index should not be larger than embedding szie')
|
||||
if index > len(embedding_ids):
|
||||
print("Index should not be larger than embedding szie")
|
||||
return
|
||||
embeddings = embeddings[np.arange(index, index + 1)]
|
||||
time_start = time.time()
|
||||
result = recall_client.search(embeddings,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'text'])
|
||||
result = recall_client.search(
|
||||
embeddings, embedding_name, collection_name, partition_names=[partition_tag], output_fields=["pk", "text"]
|
||||
)
|
||||
time_end = time.time()
|
||||
sum_t = time_end - time_start
|
||||
print('time cost', sum_t, 's')
|
||||
print("time cost", sum_t, "s")
|
||||
for hits in result:
|
||||
for hit in hits:
|
||||
print(f"hit: {hit}, text field: {hit.entity.get('text')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if (args.insert):
|
||||
if args.insert:
|
||||
milvus_data_insert(args.data_path, args.embedding_path, args.batch_size)
|
||||
if (args.search):
|
||||
if args.search:
|
||||
milvus_data_recall(args.embedding_path, args.index)
|
||||
|
||||
@@ -29,22 +29,15 @@ from config import MILVUS_HOST, MILVUS_PORT, data_dim, index_config, top_k, sear
|
||||
fmt = "\n=== {:30} ===\n"
|
||||
text_max_len = 1000
|
||||
fields = [
|
||||
FieldSchema(name="pk",
|
||||
dtype=DataType.INT64,
|
||||
is_primary=True,
|
||||
auto_id=False,
|
||||
max_length=100),
|
||||
FieldSchema(name="question",
|
||||
dtype=DataType.VARCHAR,
|
||||
max_length=text_max_len),
|
||||
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=False, max_length=100),
|
||||
FieldSchema(name="question", dtype=DataType.VARCHAR, max_length=text_max_len),
|
||||
FieldSchema(name="answer", dtype=DataType.VARCHAR, max_length=text_max_len),
|
||||
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=data_dim)
|
||||
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=data_dim),
|
||||
]
|
||||
schema = CollectionSchema(fields, "Neural Search Index")
|
||||
|
||||
|
||||
class VecToMilvus():
|
||||
|
||||
class VecToMilvus:
|
||||
def __init__(self):
|
||||
print(fmt.format("start connecting to Milvus"))
|
||||
connections.connect("default", host=MILVUS_HOST, port=MILVUS_PORT)
|
||||
@@ -61,9 +54,7 @@ class VecToMilvus():
|
||||
def creat_collection(self, collection_name):
|
||||
try:
|
||||
print(fmt.format("Create collection {}".format(collection_name)))
|
||||
self.collection = Collection(collection_name,
|
||||
schema,
|
||||
consistency_level="Strong")
|
||||
self.collection = Collection(collection_name, schema, consistency_level="Strong")
|
||||
except Exception as e:
|
||||
print("Milvus create collection error:", e)
|
||||
|
||||
@@ -92,9 +83,9 @@ class VecToMilvus():
|
||||
def create_partition(self, partition_tag):
|
||||
try:
|
||||
self.collection.create_partition(partition_tag)
|
||||
print('create partition {} successfully'.format(partition_tag))
|
||||
print("create partition {} successfully".format(partition_tag))
|
||||
except Exception as e:
|
||||
print('Milvus create partition error: ', e)
|
||||
print("Milvus create partition error: ", e)
|
||||
|
||||
def insert(self, entities, collection_name, index_name, partition_tag=None):
|
||||
try:
|
||||
@@ -103,20 +94,16 @@ class VecToMilvus():
|
||||
self.create_index(index_name)
|
||||
else:
|
||||
self.collection = Collection(collection_name)
|
||||
if (partition_tag
|
||||
is not None) and (not self.has_partition(partition_tag)):
|
||||
if (partition_tag is not None) and (not self.has_partition(partition_tag)):
|
||||
self.create_partition(partition_tag)
|
||||
|
||||
self.collection.insert(entities, partition_name=partition_tag)
|
||||
print(
|
||||
f"Number of entities in Milvus: {self.collection.num_entities}"
|
||||
) # check the num_entites
|
||||
print(f"Number of entities in Milvus: {self.collection.num_entities}") # check the num_entites
|
||||
except Exception as e:
|
||||
print("Milvus insert error:", e)
|
||||
|
||||
|
||||
class RecallByMilvus():
|
||||
|
||||
class RecallByMilvus:
|
||||
def __init__(self):
|
||||
print(fmt.format("start connecting to Milvus"))
|
||||
connections.connect("default", host=MILVUS_HOST, port=MILVUS_PORT)
|
||||
@@ -129,55 +116,50 @@ class RecallByMilvus():
|
||||
except Exception as e:
|
||||
print("Milvus create collection error:", e)
|
||||
|
||||
def search(self,
|
||||
vectors,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[],
|
||||
output_fields=[]):
|
||||
def search(self, vectors, embedding_name, collection_name, partition_names=[], output_fields=[]):
|
||||
try:
|
||||
self.get_collection(collection_name)
|
||||
result = self.collection.search(vectors,
|
||||
embedding_name,
|
||||
search_params,
|
||||
limit=top_k,
|
||||
partition_names=partition_names,
|
||||
output_fields=output_fields)
|
||||
result = self.collection.search(
|
||||
vectors,
|
||||
embedding_name,
|
||||
search_params,
|
||||
limit=top_k,
|
||||
partition_names=partition_names,
|
||||
output_fields=output_fields,
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
print('Milvus recall error: ', e)
|
||||
print("Milvus recall error: ", e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
print(fmt.format("Start inserting entities"))
|
||||
rng = np.random.default_rng(seed=19530)
|
||||
num_entities = 3000
|
||||
entities = [
|
||||
# provide the pk field because `auto_id` is set to False
|
||||
[i for i in range(num_entities)],
|
||||
['第{}个样本'.format(i)
|
||||
for i in range(num_entities)], # field text, only supports list
|
||||
rng.random(
|
||||
(num_entities,
|
||||
data_dim)), # field embeddings, supports numpy.ndarray and list
|
||||
["第{}个样本".format(i) for i in range(num_entities)], # field text, only supports list
|
||||
rng.random((num_entities, data_dim)), # field embeddings, supports numpy.ndarray and list
|
||||
]
|
||||
print(entities[-1].shape)
|
||||
collection_name = 'test1'
|
||||
partition_tag = 'partition_1'
|
||||
embedding_name = 'embeddings'
|
||||
collection_name = "test1"
|
||||
partition_tag = "partition_1"
|
||||
embedding_name = "embeddings"
|
||||
client = VecToMilvus()
|
||||
client.insert(collection_name=collection_name,
|
||||
entities=entities,
|
||||
index_name=embedding_name,
|
||||
partition_tag=partition_tag)
|
||||
client.insert(
|
||||
collection_name=collection_name, entities=entities, index_name=embedding_name, partition_tag=partition_tag
|
||||
)
|
||||
print(fmt.format("Start searching entities"))
|
||||
vectors_to_search = entities[-1][-2:]
|
||||
recall_client = RecallByMilvus()
|
||||
result = recall_client.search(vectors_to_search,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'text'])
|
||||
result = recall_client.search(
|
||||
vectors_to_search,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=["pk", "text"],
|
||||
)
|
||||
for hits in result:
|
||||
for hit in hits:
|
||||
print(f"hit: {hit}, random field: {hit.entity.get('text')}")
|
||||
|
||||
@@ -25,13 +25,7 @@ import paddlenlp
|
||||
|
||||
|
||||
class SimCSE(nn.Layer):
|
||||
|
||||
def __init__(self,
|
||||
pretrained_model,
|
||||
dropout=None,
|
||||
margin=0.0,
|
||||
scale=20,
|
||||
output_emb_size=None):
|
||||
def __init__(self, pretrained_model, dropout=None, margin=0.0, scale=20, output_emb_size=None):
|
||||
|
||||
super().__init__()
|
||||
|
||||
@@ -43,11 +37,8 @@ class SimCSE(nn.Layer):
|
||||
# recall performance and efficiency
|
||||
self.output_emb_size = output_emb_size
|
||||
if output_emb_size > 0:
|
||||
weight_attr = paddle.ParamAttr(
|
||||
initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768,
|
||||
output_emb_size,
|
||||
weight_attr=weight_attr)
|
||||
weight_attr = paddle.ParamAttr(initializer=paddle.nn.initializer.TruncatedNormal(std=0.02))
|
||||
self.emb_reduce_linear = paddle.nn.Linear(768, output_emb_size, weight_attr=weight_attr)
|
||||
|
||||
self.margin = margin
|
||||
# Used scaling cosine similarity to ease converge
|
||||
@@ -55,20 +46,18 @@ class SimCSE(nn.Layer):
|
||||
self.classifier = nn.Linear(output_emb_size, 2)
|
||||
self.rdrop_loss = paddlenlp.losses.RDropLoss()
|
||||
|
||||
@paddle.jit.to_static(input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64'),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype='int64')
|
||||
])
|
||||
def get_pooled_embedding(self,
|
||||
input_ids,
|
||||
token_type_ids=None,
|
||||
position_ids=None,
|
||||
attention_mask=None,
|
||||
with_pooler=True):
|
||||
@paddle.jit.to_static(
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||||
]
|
||||
)
|
||||
def get_pooled_embedding(
|
||||
self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None, with_pooler=True
|
||||
):
|
||||
|
||||
# Note: cls_embedding is poolerd embedding with act tanh
|
||||
sequence_output, cls_embedding = self.ptm(input_ids, token_type_ids,
|
||||
position_ids, attention_mask)
|
||||
sequence_output, cls_embedding = self.ptm(input_ids, token_type_ids, position_ids, attention_mask)
|
||||
|
||||
if with_pooler == False:
|
||||
cls_embedding = sequence_output[:, 0, :]
|
||||
@@ -86,77 +75,71 @@ class SimCSE(nn.Layer):
|
||||
with paddle.no_grad():
|
||||
for batch_data in data_loader:
|
||||
input_ids, token_type_ids = batch_data
|
||||
text_embeddings = self.get_pooled_embedding(
|
||||
input_ids, token_type_ids=token_type_ids)
|
||||
text_embeddings = self.get_pooled_embedding(input_ids, token_type_ids=token_type_ids)
|
||||
|
||||
yield text_embeddings
|
||||
|
||||
def cosine_sim(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
with_pooler=True):
|
||||
def cosine_sim(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
with_pooler=True,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask,
|
||||
with_pooler=with_pooler)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask, with_pooler=with_pooler
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask,
|
||||
with_pooler=with_pooler)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask, with_pooler=with_pooler
|
||||
)
|
||||
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding,
|
||||
axis=-1)
|
||||
cosine_sim = paddle.sum(query_cls_embedding * title_cls_embedding, axis=-1)
|
||||
return cosine_sim
|
||||
|
||||
def forward(self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None):
|
||||
def forward(
|
||||
self,
|
||||
query_input_ids,
|
||||
title_input_ids,
|
||||
query_token_type_ids=None,
|
||||
query_position_ids=None,
|
||||
query_attention_mask=None,
|
||||
title_token_type_ids=None,
|
||||
title_position_ids=None,
|
||||
title_attention_mask=None,
|
||||
):
|
||||
|
||||
query_cls_embedding = self.get_pooled_embedding(query_input_ids,
|
||||
query_token_type_ids,
|
||||
query_position_ids,
|
||||
query_attention_mask)
|
||||
query_cls_embedding = self.get_pooled_embedding(
|
||||
query_input_ids, query_token_type_ids, query_position_ids, query_attention_mask
|
||||
)
|
||||
|
||||
title_cls_embedding = self.get_pooled_embedding(title_input_ids,
|
||||
title_token_type_ids,
|
||||
title_position_ids,
|
||||
title_attention_mask)
|
||||
title_cls_embedding = self.get_pooled_embedding(
|
||||
title_input_ids, title_token_type_ids, title_position_ids, title_attention_mask
|
||||
)
|
||||
|
||||
logits1 = self.classifier(query_cls_embedding)
|
||||
logits2 = self.classifier(title_cls_embedding)
|
||||
kl_loss = self.rdrop_loss(logits1, logits2)
|
||||
|
||||
cosine_sim = paddle.matmul(query_cls_embedding,
|
||||
title_cls_embedding,
|
||||
transpose_y=True)
|
||||
cosine_sim = paddle.matmul(query_cls_embedding, title_cls_embedding, transpose_y=True)
|
||||
|
||||
# substract margin from all positive samples cosine_sim()
|
||||
margin_diag = paddle.full(shape=[query_cls_embedding.shape[0]],
|
||||
fill_value=self.margin,
|
||||
dtype=paddle.get_default_dtype())
|
||||
margin_diag = paddle.full(
|
||||
shape=[query_cls_embedding.shape[0]], fill_value=self.margin, dtype=paddle.get_default_dtype()
|
||||
)
|
||||
|
||||
cosine_sim = cosine_sim - paddle.diag(margin_diag)
|
||||
|
||||
# scale cosine to ease training converge
|
||||
cosine_sim *= self.sacle
|
||||
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype='int64')
|
||||
labels = paddle.arange(0, query_cls_embedding.shape[0], dtype="int64")
|
||||
labels = paddle.reshape(labels, shape=[-1, 1])
|
||||
|
||||
loss = F.cross_entropy(input=cosine_sim, label=labels)
|
||||
|
||||
@@ -61,15 +61,11 @@ if __name__ == "__main__":
|
||||
paddle.distributed.init_parallel_env()
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path)
|
||||
|
||||
trans_func = partial(convert_example_test,
|
||||
tokenizer=tokenizer,
|
||||
max_seq_length=args.max_seq_length)
|
||||
trans_func = partial(convert_example_test, tokenizer=tokenizer, max_seq_length=args.max_seq_length)
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype='int64'
|
||||
), # text_segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # text_input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_type_id, dtype="int64"), # text_segment
|
||||
): [data for data in fn(samples)]
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained(args.model_name_or_path)
|
||||
@@ -83,8 +79,7 @@ if __name__ == "__main__":
|
||||
model.set_dict(state_dict)
|
||||
logger.info("Loaded parameters from %s" % args.params_path)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Please set --params_path with correct pretrained model file")
|
||||
raise ValueError("Please set --params_path with correct pretrained model file")
|
||||
|
||||
id2corpus = gen_id2corpus(args.corpus_file)
|
||||
|
||||
@@ -92,11 +87,9 @@ if __name__ == "__main__":
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
corpus_ds = MapDataset(corpus_list)
|
||||
|
||||
corpus_data_loader = create_dataloader(corpus_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
corpus_data_loader = create_dataloader(
|
||||
corpus_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
# Need better way to get inner model of DataParallel
|
||||
inner_model = model._layers
|
||||
@@ -107,29 +100,27 @@ if __name__ == "__main__":
|
||||
|
||||
query_ds = MapDataset(text_list)
|
||||
|
||||
query_data_loader = create_dataloader(query_ds,
|
||||
mode='predict',
|
||||
batch_size=args.batch_size,
|
||||
batchify_fn=batchify_fn,
|
||||
trans_fn=trans_func)
|
||||
query_data_loader = create_dataloader(
|
||||
query_ds, mode="predict", batch_size=args.batch_size, batchify_fn=batchify_fn, trans_fn=trans_func
|
||||
)
|
||||
|
||||
query_embedding = inner_model.get_semantic_embedding(query_data_loader)
|
||||
|
||||
if not os.path.exists(args.recall_result_dir):
|
||||
os.mkdir(args.recall_result_dir)
|
||||
|
||||
recall_result_file = os.path.join(args.recall_result_dir,
|
||||
args.recall_result_file)
|
||||
with open(recall_result_file, 'w', encoding='utf-8') as f:
|
||||
recall_result_file = os.path.join(args.recall_result_dir, args.recall_result_file)
|
||||
with open(recall_result_file, "w", encoding="utf-8") as f:
|
||||
for batch_index, batch_query_embedding in enumerate(query_embedding):
|
||||
recalled_idx, cosine_sims = final_index.knn_query(
|
||||
batch_query_embedding.numpy(), args.recall_num)
|
||||
recalled_idx, cosine_sims = final_index.knn_query(batch_query_embedding.numpy(), args.recall_num)
|
||||
|
||||
batch_size = len(cosine_sims)
|
||||
|
||||
for row_index in range(batch_size):
|
||||
text_index = args.batch_size * batch_index + row_index
|
||||
for idx, doc_idx in enumerate(recalled_idx[row_index]):
|
||||
f.write("{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx],
|
||||
1.0 - cosine_sims[row_index][idx]))
|
||||
f.write(
|
||||
"{}\t{}\t{}\n".format(
|
||||
text_list[text_index]["text"], id2corpus[doc_idx], 1.0 - cosine_sims[row_index][idx]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -29,15 +29,14 @@ from config import collection_name, partition_tag, embedding_name
|
||||
|
||||
def recall_result(list_data):
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8080'])
|
||||
client.connect(["127.0.0.1:8080"])
|
||||
feed = {}
|
||||
for i, item in enumerate(list_data):
|
||||
feed[str(i)] = item
|
||||
start_time = time.time()
|
||||
ret = client.predict(feed_dict=feed)
|
||||
end_time = time.time()
|
||||
print("Extract feature time to cost :{} seconds".format(end_time -
|
||||
start_time))
|
||||
print("Extract feature time to cost :{} seconds".format(end_time - start_time))
|
||||
result = np.array(eval(ret.value[0]))
|
||||
return result
|
||||
|
||||
@@ -45,26 +44,26 @@ def recall_result(list_data):
|
||||
def search_in_milvus(embeddings, query_text):
|
||||
recall_client = RecallByMilvus()
|
||||
start_time = time.time()
|
||||
results = recall_client.search(embeddings,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=['pk', 'question', 'answer'])
|
||||
results = recall_client.search(
|
||||
embeddings,
|
||||
embedding_name,
|
||||
collection_name,
|
||||
partition_names=[partition_tag],
|
||||
output_fields=["pk", "question", "answer"],
|
||||
)
|
||||
end_time = time.time()
|
||||
print('Search milvus time cost is {} seconds '.format(end_time -
|
||||
start_time))
|
||||
print("Search milvus time cost is {} seconds ".format(end_time - start_time))
|
||||
list_data = []
|
||||
for line in results:
|
||||
for item in line:
|
||||
idx = item.id
|
||||
distance = item.distance
|
||||
question = item.entity.get('question')
|
||||
answer = item.entity.get('answer')
|
||||
question = item.entity.get("question")
|
||||
answer = item.entity.get("answer")
|
||||
print(question, answer, distance)
|
||||
list_data.append([query_text, question, answer, distance])
|
||||
df = pd.DataFrame(list_data,
|
||||
columns=['query_text', 'question', 'answer', 'distance'])
|
||||
df.to_csv('faq_result.csv', index=False)
|
||||
df = pd.DataFrame(list_data, columns=["query_text", "question", "answer", "distance"])
|
||||
df.to_csv("faq_result.csv", index=False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -19,9 +19,7 @@ from paddlenlp.utils.log import logger
|
||||
|
||||
def build_index(args, data_loader, model):
|
||||
|
||||
index = hnswlib.Index(
|
||||
space='ip',
|
||||
dim=args.output_emb_size if args.output_emb_size > 0 else 768)
|
||||
index = hnswlib.Index(space="ip", dim=args.output_emb_size if args.output_emb_size > 0 else 768)
|
||||
|
||||
# Initializing index
|
||||
# max_elements - the maximum number of elements (capacity). Will throw an exception if exceeded
|
||||
@@ -32,9 +30,7 @@ def build_index(args, data_loader, model):
|
||||
#
|
||||
# M - is tightly connected with internal dimensionality of the data. Strongly affects memory consumption (~M)
|
||||
# Higher M leads to higher accuracy/run_time at fixed ef/efConstruction
|
||||
index.init_index(max_elements=args.hnsw_max_elements,
|
||||
ef_construction=args.hnsw_ef,
|
||||
M=args.hnsw_m)
|
||||
index.init_index(max_elements=args.hnsw_max_elements, ef_construction=args.hnsw_ef, M=args.hnsw_m)
|
||||
|
||||
# Controlling the recall by setting ef:
|
||||
# higher ef leads to better accuracy, but slower search
|
||||
|
||||
@@ -15,17 +15,13 @@
|
||||
import os
|
||||
from milvus import MetricType, IndexType
|
||||
|
||||
MILVUS_HOST = '10.21.226.173'
|
||||
MILVUS_HOST = "10.21.226.173"
|
||||
MILVUS_PORT = 8530
|
||||
|
||||
collection_param = {
|
||||
'dimension': 256,
|
||||
'index_file_size': 256,
|
||||
'metric_type': MetricType.L2
|
||||
}
|
||||
collection_param = {"dimension": 256, "index_file_size": 256, "metric_type": MetricType.L2}
|
||||
|
||||
index_type = IndexType.IVF_FLAT
|
||||
index_param = {'nlist': 1000}
|
||||
index_param = {"nlist": 1000}
|
||||
|
||||
top_k = 100
|
||||
search_param = {'nprobe': 20}
|
||||
search_param = {"nprobe": 20}
|
||||
|
||||
@@ -21,49 +21,38 @@ import paddle
|
||||
|
||||
def gen_id2corpus(corpus_file):
|
||||
id2corpus = {}
|
||||
with open(corpus_file, 'r', encoding='utf-8') as f:
|
||||
with open(corpus_file, "r", encoding="utf-8") as f:
|
||||
for idx, line in enumerate(f):
|
||||
id2corpus[idx] = line.rstrip()
|
||||
return id2corpus
|
||||
|
||||
|
||||
def create_dataloader(dataset,
|
||||
mode='train',
|
||||
batch_size=1,
|
||||
batchify_fn=None,
|
||||
trans_fn=None):
|
||||
def create_dataloader(dataset, mode="train", batch_size=1, batchify_fn=None, trans_fn=None):
|
||||
if trans_fn:
|
||||
dataset = dataset.map(trans_fn)
|
||||
|
||||
shuffle = True if mode == 'train' else False
|
||||
if mode == 'train':
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
shuffle = True if mode == "train" else False
|
||||
if mode == "train":
|
||||
batch_sampler = paddle.io.DistributedBatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
else:
|
||||
batch_sampler = paddle.io.BatchSampler(dataset,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle)
|
||||
batch_sampler = paddle.io.BatchSampler(dataset, batch_size=batch_size, shuffle=shuffle)
|
||||
|
||||
return paddle.io.DataLoader(dataset=dataset,
|
||||
batch_sampler=batch_sampler,
|
||||
collate_fn=batchify_fn,
|
||||
return_list=True)
|
||||
return paddle.io.DataLoader(dataset=dataset, batch_sampler=batch_sampler, collate_fn=batchify_fn, return_list=True)
|
||||
|
||||
|
||||
def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -75,9 +64,9 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
result = []
|
||||
|
||||
for key, text in example.items():
|
||||
if 'label' in key:
|
||||
if "label" in key:
|
||||
# do_evaluate
|
||||
result += [example['label']]
|
||||
result += [example["label"]]
|
||||
else:
|
||||
# do_train
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length)
|
||||
@@ -88,22 +77,19 @@ def convert_example(example, tokenizer, max_seq_length=512, do_evalute=False):
|
||||
return result
|
||||
|
||||
|
||||
def convert_example_test(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example_test(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -114,9 +100,7 @@ def convert_example_test(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -125,31 +109,31 @@ def convert_example_test(example,
|
||||
|
||||
def read_simcse_text(data_path):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip()
|
||||
yield {'text_a': data, 'text_b': data}
|
||||
yield {"text_a": data, "text_b": data}
|
||||
|
||||
|
||||
def read_text_pair(data_path, is_test=False):
|
||||
"""Reads data."""
|
||||
with open(data_path, 'r', encoding='utf-8') as f:
|
||||
with open(data_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
data = line.rstrip().split("\t")
|
||||
if is_test == False:
|
||||
if len(data) != 3:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1], 'label': data[2]}
|
||||
yield {"text_a": data[0], "text_b": data[1], "label": data[2]}
|
||||
else:
|
||||
if len(data) != 2:
|
||||
continue
|
||||
yield {'text_a': data[0], 'text_b': data[1]}
|
||||
yield {"text_a": data[0], "text_b": data[1]}
|
||||
|
||||
|
||||
def gen_text_file(similar_text_pair_file):
|
||||
text2similar_text = {}
|
||||
texts = []
|
||||
with open(similar_text_pair_file, 'r', encoding='utf-8') as f:
|
||||
with open(similar_text_pair_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
splited_line = line.rstrip().split("\t")
|
||||
if len(splited_line) != 2:
|
||||
@@ -179,11 +163,10 @@ def word_repetition(input_ids, token_type_ids, dup_rate=0.32):
|
||||
actual_len = np.count_nonzero(cur_input_id)
|
||||
dup_word_index = []
|
||||
# If sequence length is less than 5, skip it
|
||||
if (actual_len > 5):
|
||||
if actual_len > 5:
|
||||
dup_len = random.randint(a=0, b=max(2, int(dup_rate * actual_len)))
|
||||
# Skip cls and sep position
|
||||
dup_word_index = random.sample(list(range(1, actual_len - 1)),
|
||||
k=dup_len)
|
||||
dup_word_index = random.sample(list(range(1, actual_len - 1)), k=dup_len)
|
||||
|
||||
r_input_id = []
|
||||
r_token_type_id = []
|
||||
@@ -207,6 +190,6 @@ def word_repetition(input_ids, token_type_ids, dup_rate=0.32):
|
||||
repetitied_input_ids[batch_id] += [0] * pad_len
|
||||
repetitied_token_type_ids[batch_id] += [0] * pad_len
|
||||
|
||||
return paddle.to_tensor(repetitied_input_ids,
|
||||
dtype='int64'), paddle.to_tensor(
|
||||
repetitied_token_type_ids, dtype='int64')
|
||||
return paddle.to_tensor(repetitied_input_ids, dtype="int64"), paddle.to_tensor(
|
||||
repetitied_token_type_ids, dtype="int64"
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ import numpy as np
|
||||
from paddle_serving_server.pipeline import PipelineClient
|
||||
|
||||
client = PipelineClient()
|
||||
client.connect(['127.0.0.1:8080'])
|
||||
client.connect(["127.0.0.1:8080"])
|
||||
|
||||
list_data = ["湖北省为什么鼓励缴费人通过线上缴费渠道缴费?", "佛山市救助站有多少个救助床位"]
|
||||
feed = {}
|
||||
|
||||
@@ -18,15 +18,10 @@ import sys
|
||||
from paddle_serving_server.web_service import WebService, Op
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
result = []
|
||||
for text in example:
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -34,43 +29,38 @@ def convert_example(example,
|
||||
|
||||
|
||||
class ErnieOp(Op):
|
||||
|
||||
def init_op(self):
|
||||
from paddlenlp.transformers import AutoTokenizer
|
||||
self.tokenizer = AutoTokenizer.from_pretrained('ernie-3.0-medium-zh')
|
||||
|
||||
self.tokenizer = AutoTokenizer.from_pretrained("ernie-3.0-medium-zh")
|
||||
|
||||
def preprocess(self, input_dicts, data_id, log_id):
|
||||
from paddlenlp.data import Stack, Tuple, Pad
|
||||
|
||||
(_, input_dict), = input_dicts.items()
|
||||
((_, input_dict),) = input_dicts.items()
|
||||
print("input dict", input_dict)
|
||||
batch_size = len(input_dict.keys())
|
||||
examples = []
|
||||
for i in range(batch_size):
|
||||
input_ids, segment_ids = convert_example([input_dict[str(i)]],
|
||||
self.tokenizer)
|
||||
input_ids, segment_ids = convert_example([input_dict[str(i)]], self.tokenizer)
|
||||
examples.append((input_ids, segment_ids))
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=self.tokenizer.pad_token_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
feed_dict = {}
|
||||
feed_dict['input_ids'] = input_ids
|
||||
feed_dict['token_type_ids'] = segment_ids
|
||||
feed_dict["input_ids"] = input_ids
|
||||
feed_dict["token_type_ids"] = segment_ids
|
||||
return feed_dict, False, None, ""
|
||||
|
||||
def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
|
||||
new_dict = {}
|
||||
new_dict["output_embedding"] = str(
|
||||
fetch_dict["output_embedding"].tolist())
|
||||
new_dict["output_embedding"] = str(fetch_dict["output_embedding"].tolist())
|
||||
return new_dict, None, ""
|
||||
|
||||
|
||||
class ErnieService(WebService):
|
||||
|
||||
def get_pipeline_response(self, read_op):
|
||||
ernie_op = ErnieOp(name="ernie", input_ops=[read_op])
|
||||
return ernie_op
|
||||
|
||||
@@ -50,14 +50,14 @@ def recall(rs, N=10):
|
||||
|
||||
if __name__ == "__main__":
|
||||
text2similar = {}
|
||||
with open(args.similar_text_pair, 'r', encoding='utf-8') as f:
|
||||
with open(args.similar_text_pair, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
text, similar_text = line.rstrip().split("\t")
|
||||
text2similar[text] = similar_text
|
||||
|
||||
rs = []
|
||||
|
||||
with open(args.recall_result_file, 'r', encoding='utf-8') as f:
|
||||
with open(args.recall_result_file, "r", encoding="utf-8") as f:
|
||||
relevance_labels = []
|
||||
for index, line in enumerate(f):
|
||||
|
||||
@@ -72,13 +72,13 @@ if __name__ == "__main__":
|
||||
relevance_labels.append(0)
|
||||
recall_N = []
|
||||
recall_num = [1, 5, 10]
|
||||
result = open('result.tsv', 'a')
|
||||
result = open("result.tsv", "a")
|
||||
res = []
|
||||
for topN in recall_num:
|
||||
R = round(100 * recall(rs, N=topN), 3)
|
||||
recall_N.append(str(R))
|
||||
for key, val in zip(recall_num, recall_N):
|
||||
print('recall@{}={}'.format(key, val))
|
||||
print("recall@{}={}".format(key, val))
|
||||
res.append(str(val))
|
||||
result.write('\t'.join(res) + '\n')
|
||||
result.write("\t".join(res) + "\n")
|
||||
# print("\t".join(recall_N))
|
||||
|
||||
@@ -39,7 +39,7 @@ if __name__ == "__main__":
|
||||
|
||||
pretrained_model = AutoModel.from_pretrained("ernie-3.0-medium-zh")
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained('ernie-3.0-medium-zh')
|
||||
tokenizer = AutoTokenizer.from_pretrained("ernie-3.0-medium-zh")
|
||||
model = SimCSE(pretrained_model, output_emb_size=output_emb_size)
|
||||
|
||||
if args.params_path and os.path.isfile(args.params_path):
|
||||
@@ -52,11 +52,10 @@ if __name__ == "__main__":
|
||||
model = paddle.jit.to_static(
|
||||
model,
|
||||
input_spec=[
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None],
|
||||
dtype="int64") # segment_ids
|
||||
])
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # input_ids
|
||||
paddle.static.InputSpec(shape=[None, None], dtype="int64"), # segment_ids
|
||||
],
|
||||
)
|
||||
# Save in static graph model.
|
||||
save_path = os.path.join(args.output_path, "inference")
|
||||
paddle.jit.save(model, save_path)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import argparse
|
||||
import paddle_serving_client.io as serving_io
|
||||
|
||||
# yapf: disable
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dirname", type=str, required=True,
|
||||
@@ -44,4 +45,5 @@ if __name__ == "__main__":
|
||||
params_filename=args.params_filename,
|
||||
show_proto=args.show_proto,
|
||||
feed_alias_names=args.feed_alias_names,
|
||||
fetch_alias_names=args.fetch_alias_names)
|
||||
fetch_alias_names=args.fetch_alias_names,
|
||||
)
|
||||
|
||||
@@ -58,22 +58,19 @@ args = parser.parse_args()
|
||||
# yapf: enable
|
||||
|
||||
|
||||
def convert_example(example,
|
||||
tokenizer,
|
||||
max_seq_length=512,
|
||||
pad_to_max_seq_len=False):
|
||||
def convert_example(example, tokenizer, max_seq_length=512, pad_to_max_seq_len=False):
|
||||
"""
|
||||
Builds model inputs from a sequence.
|
||||
|
||||
|
||||
A BERT sequence has the following format:
|
||||
|
||||
- single sequence: ``[CLS] X [SEP]``
|
||||
|
||||
Args:
|
||||
example(obj:`list(str)`): The list of text to be converted to ids.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
|
||||
Sequences longer than this will be truncated, sequences shorter will be padded.
|
||||
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
|
||||
|
||||
@@ -84,9 +81,7 @@ def convert_example(example,
|
||||
|
||||
result = []
|
||||
for key, text in example.items():
|
||||
encoded_inputs = tokenizer(text=text,
|
||||
max_seq_len=max_seq_length,
|
||||
pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length, pad_to_max_seq_len=pad_to_max_seq_len)
|
||||
input_ids = encoded_inputs["input_ids"]
|
||||
token_type_ids = encoded_inputs["token_type_ids"]
|
||||
result += [input_ids, token_type_ids]
|
||||
@@ -94,16 +89,17 @@ def convert_example(example,
|
||||
|
||||
|
||||
class Predictor(object):
|
||||
|
||||
def __init__(self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False):
|
||||
def __init__(
|
||||
self,
|
||||
model_dir,
|
||||
device="gpu",
|
||||
max_seq_length=128,
|
||||
batch_size=32,
|
||||
use_tensorrt=False,
|
||||
precision="fp32",
|
||||
cpu_threads=10,
|
||||
enable_mkldnn=False,
|
||||
):
|
||||
self.max_seq_length = max_seq_length
|
||||
self.batch_size = batch_size
|
||||
|
||||
@@ -122,14 +118,14 @@ class Predictor(object):
|
||||
precision_map = {
|
||||
"fp16": inference.PrecisionType.Half,
|
||||
"fp32": inference.PrecisionType.Float32,
|
||||
"int8": inference.PrecisionType.Int8
|
||||
"int8": inference.PrecisionType.Int8,
|
||||
}
|
||||
precision_mode = precision_map[precision]
|
||||
|
||||
if args.use_tensorrt:
|
||||
config.enable_tensorrt_engine(max_batch_size=batch_size,
|
||||
min_subgraph_size=30,
|
||||
precision_mode=precision_mode)
|
||||
config.enable_tensorrt_engine(
|
||||
max_batch_size=batch_size, min_subgraph_size=30, precision_mode=precision_mode
|
||||
)
|
||||
elif device == "cpu":
|
||||
# set CPU configs accordingly,
|
||||
# such as enable_mkldnn, set_cpu_math_library_num_threads
|
||||
@@ -145,12 +141,8 @@ class Predictor(object):
|
||||
|
||||
config.switch_use_feed_fetch_ops(False)
|
||||
self.predictor = paddle.inference.create_predictor(config)
|
||||
self.input_handles = [
|
||||
self.predictor.get_input_handle(name)
|
||||
for name in self.predictor.get_input_names()
|
||||
]
|
||||
self.output_handle = self.predictor.get_output_handle(
|
||||
self.predictor.get_output_names()[0])
|
||||
self.input_handles = [self.predictor.get_input_handle(name) for name in self.predictor.get_input_names()]
|
||||
self.output_handle = self.predictor.get_output_handle(self.predictor.get_output_names()[0])
|
||||
|
||||
def predict(self, data, tokenizer):
|
||||
"""
|
||||
@@ -158,7 +150,7 @@ class Predictor(object):
|
||||
|
||||
Args:
|
||||
data (obj:`List(str)`): The batch data whose each element is a raw text.
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
|
||||
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
|
||||
|
||||
Returns:
|
||||
@@ -166,21 +158,18 @@ class Predictor(object):
|
||||
"""
|
||||
|
||||
batchify_fn = lambda samples, fn=Tuple(
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype='int64'
|
||||
), # segment
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # input
|
||||
Pad(axis=0, pad_val=tokenizer.pad_token_id, dtype="int64"), # segment
|
||||
): fn(samples)
|
||||
|
||||
all_embeddings = []
|
||||
examples = []
|
||||
for idx, text in enumerate(tqdm(data)):
|
||||
input_ids, segment_ids = convert_example(
|
||||
text,
|
||||
tokenizer,
|
||||
max_seq_length=self.max_seq_length,
|
||||
pad_to_max_seq_len=True)
|
||||
text, tokenizer, max_seq_length=self.max_seq_length, pad_to_max_seq_len=True
|
||||
)
|
||||
examples.append((input_ids, segment_ids))
|
||||
if (len(examples) >= self.batch_size):
|
||||
if len(examples) >= self.batch_size:
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(input_ids)
|
||||
self.input_handles[1].copy_from_cpu(segment_ids)
|
||||
@@ -189,7 +178,7 @@ class Predictor(object):
|
||||
all_embeddings.append(logits)
|
||||
examples = []
|
||||
|
||||
if (len(examples) > 0):
|
||||
if len(examples) > 0:
|
||||
input_ids, segment_ids = batchify_fn(examples)
|
||||
self.input_handles[0].copy_from_cpu(input_ids)
|
||||
self.input_handles[1].copy_from_cpu(segment_ids)
|
||||
@@ -198,7 +187,7 @@ class Predictor(object):
|
||||
all_embeddings.append(logits)
|
||||
|
||||
all_embeddings = np.concatenate(all_embeddings, axis=0)
|
||||
np.save('corpus_embedding', all_embeddings)
|
||||
np.save("corpus_embedding", all_embeddings)
|
||||
|
||||
|
||||
def read_text(file_path):
|
||||
@@ -210,11 +199,18 @@ def read_text(file_path):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
|
||||
args.batch_size, args.use_tensorrt, args.precision,
|
||||
args.cpu_threads, args.enable_mkldnn)
|
||||
predictor = Predictor(
|
||||
args.model_dir,
|
||||
args.device,
|
||||
args.max_seq_length,
|
||||
args.batch_size,
|
||||
args.use_tensorrt,
|
||||
args.precision,
|
||||
args.cpu_threads,
|
||||
args.enable_mkldnn,
|
||||
)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained('ernie-3.0-medium-zh')
|
||||
tokenizer = AutoTokenizer.from_pretrained("ernie-3.0-medium-zh")
|
||||
id2corpus = read_text(args.corpus_file)
|
||||
|
||||
corpus_list = [{idx: text} for idx, text in id2corpus.items()]
|
||||
|
||||
@@ -17,8 +17,7 @@ from config import MILVUS_HOST, MILVUS_PORT, collection_param, index_type, index
|
||||
from config import top_k, search_param
|
||||
|
||||
|
||||
class VecToMilvus():
|
||||
|
||||
class VecToMilvus:
|
||||
def __init__(self):
|
||||
self.client = Milvus(host=MILVUS_HOST, port=MILVUS_PORT)
|
||||
|
||||
@@ -31,7 +30,7 @@ class VecToMilvus():
|
||||
|
||||
def creat_collection(self, collection_name):
|
||||
try:
|
||||
collection_param['collection_name'] = collection_name
|
||||
collection_param["collection_name"] = collection_name
|
||||
status = self.client.create_collection(collection_param)
|
||||
print(status)
|
||||
return status
|
||||
@@ -40,8 +39,7 @@ class VecToMilvus():
|
||||
|
||||
def create_index(self, collection_name):
|
||||
try:
|
||||
status = self.client.create_index(collection_name, index_type,
|
||||
index_param)
|
||||
status = self.client.create_index(collection_name, index_type, index_param)
|
||||
print(status)
|
||||
return status
|
||||
except Exception as e:
|
||||
@@ -49,47 +47,42 @@ class VecToMilvus():
|
||||
|
||||
def has_partition(self, collection_name, partition_tag):
|
||||
try:
|
||||
status, ok = self.client.has_partition(collection_name,
|
||||
partition_tag)
|
||||
status, ok = self.client.has_partition(collection_name, partition_tag)
|
||||
return ok
|
||||
except Exception as e:
|
||||
print("Milvus has partition error: ", e)
|
||||
|
||||
def create_partition(self, collection_name, partition_tag):
|
||||
try:
|
||||
status = self.client.create_partition(collection_name,
|
||||
partition_tag)
|
||||
print('create partition {} successfully'.format(partition_tag))
|
||||
status = self.client.create_partition(collection_name, partition_tag)
|
||||
print("create partition {} successfully".format(partition_tag))
|
||||
return status
|
||||
except Exception as e:
|
||||
print('Milvus create partition error: ', e)
|
||||
print("Milvus create partition error: ", e)
|
||||
|
||||
def insert(self, vectors, collection_name, ids=None, partition_tag=None):
|
||||
try:
|
||||
if not self.has_collection(collection_name):
|
||||
self.creat_collection(collection_name)
|
||||
self.create_index(collection_name)
|
||||
print('collection info: {}'.format(
|
||||
self.client.get_collection_info(collection_name)[1]))
|
||||
if (partition_tag is not None) and (not self.has_partition(
|
||||
collection_name, partition_tag)):
|
||||
print("collection info: {}".format(self.client.get_collection_info(collection_name)[1]))
|
||||
if (partition_tag is not None) and (not self.has_partition(collection_name, partition_tag)):
|
||||
self.create_partition(collection_name, partition_tag)
|
||||
status, ids = self.client.insert(collection_name=collection_name,
|
||||
records=vectors,
|
||||
ids=ids,
|
||||
partition_tag=partition_tag)
|
||||
status, ids = self.client.insert(
|
||||
collection_name=collection_name, records=vectors, ids=ids, partition_tag=partition_tag
|
||||
)
|
||||
self.client.flush([collection_name])
|
||||
print(
|
||||
'Insert {} entities, there are {} entities after insert data.'.
|
||||
format(len(ids),
|
||||
self.client.count_entities(collection_name)[1]))
|
||||
"Insert {} entities, there are {} entities after insert data.".format(
|
||||
len(ids), self.client.count_entities(collection_name)[1]
|
||||
)
|
||||
)
|
||||
return status, ids
|
||||
except Exception as e:
|
||||
print("Milvus insert error:", e)
|
||||
|
||||
|
||||
class RecallByMilvus():
|
||||
|
||||
class RecallByMilvus:
|
||||
def __init__(self):
|
||||
self.client = Milvus(host=MILVUS_HOST, port=MILVUS_PORT)
|
||||
|
||||
@@ -100,7 +93,8 @@ class RecallByMilvus():
|
||||
query_records=vectors,
|
||||
top_k=top_k,
|
||||
params=search_param,
|
||||
partition_tag=partition_tag)
|
||||
partition_tag=partition_tag,
|
||||
)
|
||||
return status, results
|
||||
except Exception as e:
|
||||
print('Milvus recall error: ', e)
|
||||
print("Milvus recall error: ", e)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user