143 lines
4.9 KiB
Python
143 lines
4.9 KiB
Python
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import re
|
|
from io import BytesIO
|
|
|
|
import numpy as np
|
|
import paddle
|
|
from PIL import Image
|
|
|
|
from ..metrics import SpanEvaluator
|
|
from .image_utils import NormalizeImage, Permute, ResizeImage
|
|
|
|
resize_func = ResizeImage(target_size=224, interp=1)
|
|
norm_func = NormalizeImage(is_channel_first=False, mean=[123.675, 116.280, 103.530], std=[58.395, 57.120, 57.375])
|
|
permute_func = Permute(to_bgr=False)
|
|
|
|
|
|
def map_offset(ori_offset, offset_mapping):
|
|
"""
|
|
map ori offset to token offset
|
|
"""
|
|
for index, span in enumerate(offset_mapping):
|
|
if span[0] <= ori_offset < span[1]:
|
|
return index
|
|
return -1
|
|
|
|
|
|
def pad_image_data(image_data):
|
|
if not image_data:
|
|
image = np.zeros([3, 224, 224])
|
|
return image
|
|
# decode image
|
|
data = np.frombuffer(bytearray(image_data), dtype="uint8")
|
|
image = np.array(Image.open(BytesIO(data)).convert("RGB"))
|
|
sample = {"image": image}
|
|
# resize image
|
|
sample = resize_func(sample)
|
|
# norm image
|
|
sample = norm_func(sample)
|
|
# permute
|
|
sample = permute_func(sample)
|
|
return sample["image"]
|
|
|
|
|
|
def unify_prompt_name(prompt):
|
|
# The classification labels are shuffled during finetuning, so they need
|
|
# to be unified during evaluation.
|
|
if re.search(r"\[.*?\]$", prompt):
|
|
prompt_prefix = prompt[: prompt.find("[", 1)]
|
|
cls_options = re.search(r"\[.*?\]$", prompt).group()[1:-1].split(",")
|
|
cls_options = sorted(list(set(cls_options)))
|
|
cls_options = ",".join(cls_options)
|
|
prompt = prompt_prefix + "[" + cls_options + "]"
|
|
return prompt
|
|
return prompt
|
|
|
|
|
|
def get_relation_type_dict(relation_data, schema_lang="ch"):
|
|
def compare(a, b, schema_lang="ch"):
|
|
if schema_lang == "ch":
|
|
a = a[::-1]
|
|
b = b[::-1]
|
|
|
|
res = ""
|
|
for i in range(min(len(a), len(b))):
|
|
if a[i] == b[i]:
|
|
res += a[i]
|
|
else:
|
|
break
|
|
if res == "":
|
|
return res
|
|
if schema_lang == "ch" and res[::-1][0] == "的":
|
|
return res[::-1][1:]
|
|
elif schema_lang == "en" and res[-3:] == " of":
|
|
return res[:-3]
|
|
return ""
|
|
|
|
relation_type_dict = {}
|
|
added_list = []
|
|
for i in range(len(relation_data)):
|
|
added = False
|
|
if relation_data[i][0] not in added_list:
|
|
for j in range(i + 1, len(relation_data)):
|
|
match = compare(relation_data[i][0], relation_data[j][0], schema_lang=schema_lang)
|
|
if match != "":
|
|
match = unify_prompt_name(match)
|
|
if relation_data[i][0] not in added_list:
|
|
added_list.append(relation_data[i][0])
|
|
relation_type_dict.setdefault(match, []).append(relation_data[i][1])
|
|
added_list.append(relation_data[j][0])
|
|
relation_type_dict.setdefault(match, []).append(relation_data[j][1])
|
|
added = True
|
|
if not added:
|
|
added_list.append(relation_data[i][0])
|
|
if schema_lang == "ch":
|
|
suffix = relation_data[i][0].rsplit("的", 1)[1]
|
|
suffix = unify_prompt_name(suffix)
|
|
relation_type = suffix
|
|
else:
|
|
prefix = relation_data[i][0].split(" of ", 1)[0]
|
|
prefix = unify_prompt_name(prefix)
|
|
relation_type = prefix
|
|
relation_type_dict.setdefault(relation_type, []).append(relation_data[i][1])
|
|
return relation_type_dict
|
|
|
|
|
|
def uie_loss_func(outputs, labels):
|
|
criterion = paddle.nn.BCELoss()
|
|
start_ids, end_ids = labels
|
|
start_prob, end_prob = outputs
|
|
start_ids = paddle.cast(start_ids, "float32")
|
|
end_ids = paddle.cast(end_ids, "float32")
|
|
loss_start = criterion(start_prob, start_ids)
|
|
loss_end = criterion(end_prob, end_ids)
|
|
loss = (loss_start + loss_end) / 2.0
|
|
return loss
|
|
|
|
|
|
def compute_metrics(p):
|
|
metric = SpanEvaluator()
|
|
start_prob, end_prob = p.predictions
|
|
start_ids, end_ids = p.label_ids
|
|
metric.reset()
|
|
|
|
num_correct, num_infer, num_label = metric.compute(start_prob, end_prob, start_ids, end_ids)
|
|
metric.update(num_correct, num_infer, num_label)
|
|
precision, recall, f1 = metric.accumulate()
|
|
metric.reset()
|
|
|
|
return {"precision": precision, "recall": recall, "f1": f1}
|