Files
wehub-resource-sync 2aaeece67c
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
Pipelines-Test / Pipelines-Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

204 lines
9.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 unittest
import numpy as np
import paddle
from parameterized import parameterized
from paddlenlp.prompt import AutoTemplate, ManualTemplate, PrefixTemplate, SoftTemplate
from paddlenlp.transformers import AutoModelForMaskedLM, AutoTokenizer
class TemplateTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.tokenizer = AutoTokenizer.from_pretrained("__internal_testing__/tiny-random-ernie")
cls.model = AutoModelForMaskedLM.from_pretrained("__internal_testing__/tiny-random-ernie")
cls.example = {"text_a": "天气晴朗", "text_b": "下雪了", "choices": ["不", "很"], "labels": 0}
cls.max_length = 20
cls.tokenizer.add_special_tokens({"additional_special_tokens": ["[O-MASK]"]})
cls.model.resize_token_embeddings(len(cls.tokenizer))
def test_initialization(self):
with self.assertRaises(ValueError):
prompt = "非AutoTemplate模板中必须定义`text`"
ManualTemplate(prompt, self.tokenizer, self.max_length)
with self.assertRaises(ValueError):
prompt = "{'text': 'text_a'} SoftTemplate必须定义`soft`"
SoftTemplate(prompt, self.tokenizer, self.max_length, self.model.get_input_embeddings())
with self.assertRaises(ValueError):
prompt = "{'text': 'text_a'} PrefixTemplate只定义`prefix`。{'soft'}"
PrefixTemplate(prompt, self.tokenizer, self.max_length, self.model)
with self.assertRaises(ValueError):
prompt = "{'text': 'text_a'}{'prefix': None, 'length':3}PrefixTemplate中`prefix`只能位于句首。"
PrefixTemplate(prompt, self.tokenizer, self.max_length, self.model)
@parameterized.expand(
[
(
"{'text': 'text_a'}说明天气{'mask'}好。",
"[CLS]天气晴朗说明天气[MASK]好。[SEP]",
),
(
"{'text': 'text_a'}{'hard': '说明天气'}{'mask'}{'hard': '好。'}",
"[CLS]天气晴朗说明天气[MASK]好。[SEP]",
),
(
"下边两句话意思一样吗?{'text':'text_a'}{'sep'}{'text':'text_b'}",
"[CLS]下边两句话意思一样吗?天气晴[SEP]下雪了[SEP]",
),
(
"{'options':'choices','add_omask':True,'add_prompt':'[OPT]好。'}天气如何?{'text': 'text_a'}",
"[CLS][O-MASK]不好。[O-MASK]很好。天气如何?天气晴朗[SEP]",
),
(
"{'text': 'text_a'}{'text': 'text_b', 'truncate': False}这是一个很长的提示,要截断",
"[CLS]天气下雪了这是一个很长的提示,要截断[SEP]",
),
("{'text':'text_a'}说明天气{'mask': None, 'length': 3}", "[CLS]天气晴朗说明天气[MASK][MASK][MASK][SEP]"),
]
)
def test_manual_template(self, prompt, expected_ans):
template = ManualTemplate(prompt, self.tokenizer, self.max_length)
encoded_ids = template(self.example)["input_ids"]
encoded_tokens = self.tokenizer.decode(encoded_ids).replace(" ", "")
self.assertEqual(encoded_tokens, expected_ans)
@parameterized.expand(
[
(
"{'text':'text_a', 'position': 4}",
[0, 4, 5, 6, 7, 0],
),
(
"{'options':'choices','add_omask':True,'add_prompt':'[OPT]好。'}天气如何?{'text': 'text_a'}",
[0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0],
),
]
)
def test_position(self, prompt, expected_ans):
template = ManualTemplate(prompt, self.tokenizer, self.max_length)
encoded_positions = template(self.example)["position_ids"]
self.assertEqual(encoded_positions, expected_ans)
def test_token_type(self):
prompt = "{'text': 'text_a'}{'sep': None, 'token_type': 1}{'text': 'text_b'}之间的关系是什么?"
template = ManualTemplate(prompt, self.tokenizer, self.max_length)
encoded_token_types = template(self.example)["token_type_ids"]
self.assertEqual(encoded_token_types, [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0])
def test_attention_mask(self):
expected_att = np.zeros([15, 15])
expected_att[1:5, 5:9] = -1e4
expected_att[5:9, 1:5] = -1e4
prompt = "{'options':'choices','add_omask':True,'add_prompt':'[OPT]好。'}{'sep'}{'text': 'text_a'}"
template = ManualTemplate(prompt, self.tokenizer, self.max_length)
encoded_att = template(self.example)["attention_mask"]
self.assertListEqual(encoded_att.tolist(), expected_att.tolist())
@parameterized.expand(
[
(
"{'soft'}{'text': 'text_a'}{'sep'}{'text': 'text_b'}",
"[CLS][CLS]天气晴朗[SEP]下雪了[SEP]",
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
),
(
"{'text': 'text_a'}{'soft': '请判断', 'length': 5}{'mask'}",
"[CLS]天气晴朗[CLS][SEP][MASK],的[MASK][SEP]",
[0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0],
),
]
)
def test_soft_template(self, prompt, expected_token_ids, expected_soft_ids):
template = SoftTemplate(prompt, self.tokenizer, self.max_length, self.model.get_input_embeddings())
encoded = template(self.example)
self.assertEqual(self.tokenizer.decode(encoded["input_ids"]).replace(" ", ""), expected_token_ids)
self.assertEqual(encoded["soft_token_ids"], expected_soft_ids)
def test_soft_initialization(self):
prompt = "{'text': 'text_a'}{'soft': '分类'}"
template = SoftTemplate(prompt, self.tokenizer, self.max_length, self.model.get_input_embeddings())
expected_tokens = self.tokenizer("分类", add_special_tokens=False)["input_ids"]
expected_embeds = self.model.get_input_embeddings()(paddle.to_tensor(expected_tokens))
init_embeds = template.soft_embeddings.weight[1:]
self.assertTrue(paddle.allclose(init_embeds, expected_embeds, atol=1e-6))
def test_soft_encoder(self):
prompt = "{'text': 'text_a'}{'soft': '天气', 'encoder': 'lstm', 'hidden_size': 32}{'soft': None, 'length': 2, 'encoder': 'mlp'}"
template = SoftTemplate(prompt, self.tokenizer, self.max_length, self.model.get_input_embeddings())
encoded = template(self.example)
encoded_tokens = self.tokenizer.decode(encoded["input_ids"]).replace(" ", "")
encoded_encoder = encoded["encoder_ids"]
expected_tokens = "[CLS]天气晴朗[CLS][SEP][MASK][SEP]"
expected_encoder = [0, 0, 0, 0, 0, 1, 1, 2, 2, 0]
self.assertEqual(encoded_tokens, expected_tokens)
self.assertEqual(encoded_encoder, expected_encoder)
@parameterized.expand(
[
(
"{'prefix': '新闻类别', 'length': 10, 'encoder': 'lstm'}{'text': 'text_a'}",
"[CLS][CLS][SEP][MASK],的、一人有是天气晴朗[SEP]",
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0],
)
]
)
def test_prefix_template(self, prompt, expected_tokens, expected_soft_tokens):
template = PrefixTemplate(prompt, self.tokenizer, self.max_length, self.model)
encoded = template(self.example)
encoded_tokens = self.tokenizer.decode(encoded["input_ids"]).replace(" ", "")
self.assertEqual(encoded_tokens, expected_tokens)
self.assertEqual(encoded["soft_token_ids"], expected_soft_tokens)
@parameterized.expand(
[
(
"{'text': 'text_a'}说明天气{'mask'}好。",
"[CLS]天气晴朗说明天气[MASK]好。[SEP]",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
),
(
"{'text': 'text_a'}{'hard': '说明天气'}{'mask'}{'hard': '好。'}",
"[CLS]天气晴朗说明天气[MASK]好。[SEP]",
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
),
(
"{'text': 'text_a'}{'soft': '请判断', 'length': 5}{'mask'}",
"[CLS]天气晴朗[CLS][SEP][MASK],的[MASK][SEP]",
[0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0],
),
(
"{'prefix': '新闻类别', 'length': 10, 'encoder': 'lstm'}{'text': 'text_a'}",
"[CLS][CLS][SEP][MASK],的、一人有是天气晴朗[SEP]",
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0],
),
]
)
def test_auto_template(self, prompt, expected_tokens, expected_soft_tokens):
template = AutoTemplate.create_from(prompt, self.tokenizer, self.max_length, self.model)
encoded = template(self.example)
encoded_tokens = self.tokenizer.decode(encoded["input_ids"]).replace(" ", "")
self.assertEqual(encoded_tokens, expected_tokens)
self.assertEqual(encoded["soft_token_ids"], expected_soft_tokens)
if __name__ == "__main__":
unittest.main()