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

1047 lines
42 KiB
Python

# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
# Copyright 2020 The HuggingFace Team. 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.
from __future__ import annotations
import copy
import inspect
import os
import random
import shutil
import subprocess
import tempfile
import time
import unittest
from typing import Optional, Tuple, Type
import numpy as np
import paddle
from paddle.distributed.utils.launch_utils import (
TrainerProc,
find_free_ports,
get_cluster,
watch_local_trainers,
)
from paddlenlp.taskflow.utils import static_mode_guard
from paddlenlp.transformers import AutoModelForCausalLM, AutoTokenizer
from paddlenlp.transformers.configuration_utils import PretrainedConfig
from paddlenlp.transformers.model_utils import PretrainedModel
from paddlenlp.utils.env import ( # MODEL_HOME,
CONFIG_NAME,
LEGACY_CONFIG_NAME,
PADDLE_INFERENCE_MODEL_SUFFIX,
PADDLE_INFERENCE_WEIGHTS_SUFFIX,
)
from ..testing_utils import slow
def _config_zero_init(config):
configs_no_init = copy.deepcopy(config)
for key in configs_no_init.__dict__.keys():
if "_range" in key or "_std" in key or "initializer_factor" in key or "layer_scale" in key:
setattr(configs_no_init, key, 1e-10)
return configs_no_init
def get_cluster_from_args(selected_gpus):
cluster_node_ips = "127.0.0.1"
node_ip = "127.0.0.1"
node_ips = [x.strip() for x in cluster_node_ips.split(",")]
node_ips.index(node_ip)
free_ports = None
free_ports = find_free_ports(len(selected_gpus))
if free_ports is not None:
free_ports = list(free_ports)
trainer_endpoints = []
for ip in node_ips:
trainer_endpoints.append(["%s:%d" % (ip, port) for port in free_ports])
return get_cluster(node_ips, node_ip, trainer_endpoints, selected_gpus)
def get_gpus(selected_gpus):
selected_gpus = [x.strip() for x in selected_gpus.split(",")]
return selected_gpus
def start_local_trainers_cpu(trainer_endpoints, training_script, training_script_args, log_dir=None):
current_env = copy.copy(os.environ.copy())
current_env.pop("http_proxy", None)
current_env.pop("https_proxy", None)
procs = []
n_rank = len(trainer_endpoints)
print(trainer_endpoints)
for rank_id, endpoint in enumerate(trainer_endpoints):
proc_env = {
"PADDLE_DISTRI_BACKEND": "gloo",
"PADDLE_TRAINER_ID": "%d" % rank_id,
"PADDLE_CURRENT_ENDPOINT": "%s" % endpoint,
"PADDLE_TRAINERS_NUM": "%d" % n_rank,
"PADDLE_TRAINER_ENDPOINTS": ",".join(trainer_endpoints),
}
current_env.update(proc_env)
print("trainer proc env:{}".format(current_env))
assert os.getenv("WITH_COVERAGE", "OFF") == "OFF", "Gloo don't support WITH_COVERAGE."
cmd = "python -u " + training_script
print("start trainer proc:{} env:{}".format(cmd, proc_env))
fn = None
proc = subprocess.Popen(cmd.split(" "), env=current_env)
tp = TrainerProc()
tp.proc = proc
tp.rank = rank_id
tp.log_fn = fn
tp.cmd = cmd
procs.append(tp)
return procs
def start_local_trainers(
cluster,
pod,
training_script,
training_script_args="",
eager_mode=True,
allocator_strategy="auto_growth",
log_dir=None,
without_http_proxy=True,
):
current_env = copy.copy(os.environ.copy())
# paddle broadcast ncclUniqueId use socket, and
# proxy maybe make trainers unreachable, so delete them.
# if we set them to "", grpc will log error message "bad uri"
# so just delete them.
# current_env.pop("http_proxy", None)
# current_env.pop("https_proxy", None)
# parse args
if isinstance(training_script_args, dict):
training_script_args = [f"--{k} {v}" for k, v in training_script_args.items()]
if isinstance(training_script_args, list):
training_script_args = " ".join(training_script_args)
procs = []
for t in pod.trainers:
proc_env = {
"FLAGS_selected_gpus": "%s" % ",".join([str(g) for g in t.gpus]),
"PADDLE_TRAINER_ID": "%d" % t.rank,
"PADDLE_CURRENT_ENDPOINT": "%s" % t.endpoint,
"PADDLE_TRAINERS_NUM": "%d" % cluster.trainers_nranks(),
"PADDLE_TRAINER_ENDPOINTS": ",".join(cluster.trainers_endpoints()),
}
proc_env["FLAGS_allocator_strategy"] = allocator_strategy
if allocator_strategy == "auto_growth":
proc_env["FLAGS_fraction_of_gpu_memory_to_use"] = "0.1"
current_env.update(proc_env)
if os.getenv("WITH_COVERAGE", "OFF") == "ON":
cmd = "python -m coverage run --branch -p " + training_script
else:
cmd = f"python -u {training_script} {training_script_args}"
print("start trainer proc:{} env:{}".format(cmd, proc_env))
fn = None
proc = subprocess.Popen(cmd.split(" "), env=current_env)
tp = TrainerProc()
tp.proc = proc
tp.rank = t.rank
tp.log_fn = fn
tp.cmd = cmd
procs.append(tp)
return procs
def ids_tensor(shape, vocab_size, dtype="int32"):
# Creates a random int32 tensor of the shape within the vocab size
return paddle.randint(low=1, high=vocab_size, dtype=dtype, shape=shape)
def random_attention_mask(shape, dtype="int32"):
attn_mask = ids_tensor(shape, vocab_size=2, dtype=dtype)
# make sure that at least one token is attended to for each batch
attn_mask[:, -1] = 1
return attn_mask
def floats_tensor(shape, scale=1.0):
"""Creates a random float32 tensor"""
return scale * paddle.randn(shape, dtype="float32")
def check_two_model_parameter(first_model: PretrainedModel, second_model: PretrainedModel):
assert len(set(first_model.state_dict().keys()) - set(second_model.state_dict().keys())) == 0
# random choice the keys to compare
key = random.choice(list(first_model.state_dict().keys()))
diff = first_model.state_dict()[key] - second_model.state_dict()[key]
assert diff.sum().item() == 0
class ModelTesterMixin:
model_tester = None
base_model_class: Optional[Type[PretrainedModel]] = None
all_model_classes: Tuple[Type[PretrainedModel]] = ()
all_generative_model_classes = ()
test_resize_embeddings = True
test_resize_position_embeddings = False
test_mismatched_shapes = True
test_missing_keys = True
test_model_compatibility_keys = True
test_tie_weights = False
use_test_inputs_embeds = False
use_test_model_name_list = True
is_encoder_decoder = False
has_attentions = True
model_split_percents = [0.5, 0.7, 0.9]
def _prepare_for_class(self, inputs_dict, model_class):
inputs_dict = copy.deepcopy(inputs_dict)
if model_class.__name__.endswith("ForMultipleChoice"):
inputs_dict = {
k: v.unsqueeze(1).expand(shape=[-1, self.model_tester.num_choices, -1])
if isinstance(v, paddle.Tensor) and v.ndim > 1
else v
for k, v in inputs_dict.items()
}
return inputs_dict
def _make_model_instance(self, config, model_class):
if isinstance(config, PretrainedConfig):
return model_class(config)
if model_class == self.base_model_class:
return model_class(**config)
return model_class(self.base_model_class(**config))
def test_save_load(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
def check_save_load(out1, out2):
# make sure we don't have nans
out_2 = out2.numpy()
out_2[np.isnan(out_2)] = 0
out_1 = out1.numpy()
out_1[np.isnan(out_1)] = 0
max_diff = np.amax(np.abs(out_1 - out_2))
self.assertLessEqual(max_diff, 1e-5)
for model_class in self.all_model_classes:
model = self._make_model_instance(config, model_class)
model.eval()
with paddle.no_grad():
first = model(**self._prepare_for_class(inputs_dict, model_class))[0]
with tempfile.TemporaryDirectory() as tmpdirname:
model.save_pretrained(tmpdirname)
model = model_class.from_pretrained(tmpdirname)
model.eval()
with paddle.no_grad():
second = model(**self._prepare_for_class(inputs_dict, model_class))[0]
# support tuple of tensor
if isinstance(first, tuple) and isinstance(second, tuple):
for tensor1, tensor2 in zip(first, second):
check_save_load(tensor1, tensor2)
else:
check_save_load(first, second)
def test_determinism(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
def check_determinism(first, second):
out_1 = first.numpy()
out_2 = second.numpy()
out_1 = out_1[~np.isnan(out_1)]
out_2 = out_2[~np.isnan(out_2)]
max_diff = np.amax(np.abs(out_1 - out_2))
self.assertLessEqual(max_diff, 1e-5)
for model_class in self.all_model_classes:
model = self._make_model_instance(config, model_class)
model.eval()
with paddle.no_grad():
first = model(**self._prepare_for_class(inputs_dict, model_class))[0]
second = model(**self._prepare_for_class(inputs_dict, model_class))[0]
if isinstance(first, tuple) and isinstance(second, tuple):
for tensor1, tensor2 in zip(first, second):
check_determinism(tensor1, tensor2)
else:
check_determinism(first, second)
def test_forward_signature(self):
config, _ = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
model = self._make_model_instance(config, model_class)
signature = inspect.signature(model.forward)
# signature.parameters is an OrderedDict => so arg_names order is deterministic
arg_names = [*signature.parameters.keys()]
expected_arg_names = ["input_ids"]
self.assertListEqual(arg_names[:1], expected_arg_names)
@unittest.skip("Not implemented yet")
def test_training(self):
# TODO(guosheng): add more tests for training if loss is implemented
pass
@unittest.skip("Not implemented yet")
def test_training_gradient_checkpointing(self):
pass
def test_attention_outputs(self):
if not self.has_attentions:
return
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
seq_len = getattr(self.model_tester, "seq_length", None)
decoder_seq_length = getattr(self.model_tester, "decoder_seq_length", seq_len)
encoder_seq_length = getattr(self.model_tester, "encoder_seq_length", seq_len)
decoder_key_length = getattr(self.model_tester, "decoder_key_length", decoder_seq_length)
encoder_key_length = getattr(self.model_tester, "key_length", encoder_seq_length)
chunk_length = getattr(self.model_tester, "chunk_length", None)
if chunk_length is not None and hasattr(self.model_tester, "num_hashes"):
encoder_seq_length = encoder_seq_length * self.model_tester.num_hashes
for model_class in self.all_model_classes:
signature = inspect.signature(model_class.forward)
# signature.parameters is an OrderedDict => so arg_names order is deterministic
arg_names = [*signature.parameters.keys()]
if not all(name in arg_names for name in ["output_attentions", "output_hidden_states", "return_dict"]):
continue
inputs_dict["output_attentions"] = True
inputs_dict["output_hidden_states"] = False
inputs_dict["return_dict"] = True
model = self._make_model_instance(config, model_class)
model.eval()
with paddle.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
attentions = outputs.encoder_attentions if self.is_encoder_decoder else outputs.attentions
self.assertEqual(len(attentions), self.model_tester.num_hidden_layers)
# TODO(guosheng): check that output_attentions also work using config
if chunk_length is not None:
self.assertListEqual(
list(attentions[0].shape[-4:]),
[self.model_tester.num_attention_heads, encoder_seq_length, chunk_length, encoder_key_length],
)
else:
self.assertListEqual(
list(attentions[0].shape[-3:]),
[self.model_tester.num_attention_heads, encoder_seq_length, encoder_key_length],
)
out_len = len(outputs)
if self.is_encoder_decoder:
correct_outlen = 5
# loss is at first position
if "labels" in inputs_dict:
correct_outlen += 1 # loss is added to beginning
# Question Answering model returns start_logits and end_logits
if model_class.__name__.endswith("ForQuestionAnswering"):
correct_outlen += 1 # start_logits and end_logits instead of only 1 output
if "past_key_values" in outputs:
correct_outlen += 1 # past_key_values have been returned
self.assertEqual(out_len, correct_outlen)
# decoder attentions
decoder_attentions = outputs.decoder_attentions
self.assertIsInstance(decoder_attentions, (list, tuple))
self.assertEqual(len(decoder_attentions), self.model_tester.num_hidden_layers)
self.assertListEqual(
list(decoder_attentions[0].shape[-3:]),
[self.model_tester.num_attention_heads, decoder_seq_length, decoder_key_length],
)
# cross attentions
cross_attentions = outputs.cross_attentions
self.assertIsInstance(cross_attentions, (list, tuple))
self.assertEqual(len(cross_attentions), self.model_tester.num_hidden_layers)
self.assertListEqual(
list(cross_attentions[0].shape[-3:]),
[
self.model_tester.num_attention_heads,
decoder_seq_length,
encoder_key_length,
],
)
# Check attention is always last and order is fine
inputs_dict["output_attentions"] = True
inputs_dict["output_hidden_states"] = True
model = self._make_model_instance(config, model_class)
model.eval()
with paddle.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
if hasattr(self.model_tester, "num_hidden_states_types"):
added_hidden_states = self.model_tester.num_hidden_states_types
elif self.is_encoder_decoder:
added_hidden_states = 2
else:
added_hidden_states = 1
self.assertEqual(out_len + added_hidden_states, len(outputs))
self_attentions = outputs.encoder_attentions if self.is_encoder_decoder else outputs.attentions
self.assertEqual(len(self_attentions), self.model_tester.num_hidden_layers)
if chunk_length is not None:
self.assertListEqual(
list(self_attentions[0].shape[-4:]),
[self.model_tester.num_attention_heads, encoder_seq_length, chunk_length, encoder_key_length],
)
else:
self.assertListEqual(
list(self_attentions[0].shape[-3:]),
[self.model_tester.num_attention_heads, encoder_seq_length, encoder_key_length],
)
def test_hidden_states_output(self):
def check_hidden_states_output(inputs_dict, config, model_class):
model = self._make_model_instance(config, model_class)
model.eval()
with paddle.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
hidden_states = outputs.encoder_hidden_states if self.is_encoder_decoder else outputs.hidden_states
expected_num_layers = getattr(
self.model_tester, "expected_num_hidden_layers", self.model_tester.num_hidden_layers + 1
)
self.assertEqual(len(hidden_states), expected_num_layers)
if hasattr(self.model_tester, "encoder_seq_length"):
seq_length = self.model_tester.encoder_seq_length
if hasattr(self.model_tester, "chunk_length") and self.model_tester.chunk_length > 1:
seq_length = seq_length * self.model_tester.chunk_length
else:
seq_length = self.model_tester.seq_length
self.assertListEqual(
list(hidden_states[0].shape[-2:]),
[seq_length, self.model_tester.hidden_size],
)
if self.is_encoder_decoder:
hidden_states = outputs.decoder_hidden_states
self.assertIsInstance(hidden_states, (list, tuple))
self.assertEqual(len(hidden_states), expected_num_layers)
seq_len = getattr(self.model_tester, "seq_length", None)
decoder_seq_length = getattr(self.model_tester, "decoder_seq_length", seq_len)
self.assertListEqual(
list(hidden_states[0].shape[-2:]),
[decoder_seq_length, self.model_tester.hidden_size],
)
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
inputs_dict["return_dict"] = True
for model_class in self.all_model_classes:
signature = inspect.signature(model_class.forward)
# signature.parameters is an OrderedDict => so arg_names order is deterministic
arg_names = [*signature.parameters.keys()]
if not all(name in arg_names for name in ["output_attentions", "output_hidden_states", "return_dict"]):
continue
inputs_dict["output_hidden_states"] = True
check_hidden_states_output(inputs_dict, config, model_class)
# TODO(guosheng): check that output_hidden_states also work using config
@unittest.skip("Not implemented")
def test_retain_grad_hidden_states_attentions(self):
pass
def test_resize_position_vector_embeddings(self):
if not self.test_resize_position_embeddings:
return
(
original_config,
inputs_dict,
) = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
config = copy.deepcopy(original_config)
model = self._make_model_instance(config, model_class)
if self.model_tester.is_training is False:
model.eval()
max_position_embeddings = config.max_position_embeddings
# Retrieve the embeddings and clone theme
if self.is_encoder_decoder:
encoder_model_embed, decoder_model_embed = model.get_position_embeddings()
encoder_cloned_embeddings = encoder_model_embed.weight.clone()
decoder_cloned_embeddings = decoder_model_embed.weight.clone()
else:
model_embed = model.get_position_embeddings()
cloned_embeddings = model_embed.weight.clone()
# Check that resizing the position embeddings with a larger max_position_embeddings increases
# the model's position embeddings size
model.resize_position_embeddings(max_position_embeddings + 10)
self.assertEqual(model.config.max_position_embeddings, max_position_embeddings + 10)
# Check that it actually resizes the embeddings matrix
if model.config.is_encoder_decoder:
encoder_model_embed, decoder_model_embed = model.get_position_embeddings()
self.assertEqual(encoder_model_embed.weight.shape[0], encoder_cloned_embeddings.shape[0] + 10)
self.assertEqual(decoder_model_embed.weight.shape[0], decoder_cloned_embeddings.shape[0] + 10)
else:
model_embed = model.get_position_embeddings()
self.assertEqual(model_embed.weight.shape[0], cloned_embeddings.shape[0] + 10)
# Check that the model can still do a forward pass successfully (every parameter should be resized)
model(**self._prepare_for_class(inputs_dict, model_class))
# Check that resizing the position embeddings with a smaller max_position_embeddings decreases
# the model's max_position_embeddings
model.resize_position_embeddings(max_position_embeddings - 5)
self.assertEqual(model.base_model.config["max_position_embeddings"], max_position_embeddings - 5)
# Check that it actually resizes the embeddings matrix
if self.is_encoder_decoder:
encoder_model_embed, decoder_model_embed = model.get_position_embeddings()
self.assertEqual(encoder_model_embed.weight.shape[0], encoder_cloned_embeddings.shape[0] - 5)
self.assertEqual(decoder_model_embed.weight.shape[0], decoder_cloned_embeddings.shape[0] - 5)
else:
model_embed = model.get_position_embeddings()
self.assertEqual(model_embed.weight.shape[0], cloned_embeddings.shape[0] - 5)
# Check that the model can still do a forward pass successfully (every parameter should be resized)
model(**self._prepare_for_class(inputs_dict, model_class))
# Check that adding and removing tokens has not modified the first part of the embedding matrix.
models_equal = True
if model.config.is_encoder_decoder:
for p1, p2 in zip(encoder_cloned_embeddings, encoder_model_embed.weight):
if p1.data.ne(p2.data).sum() > 0:
models_equal = False
for p1, p2 in zip(decoder_cloned_embeddings, decoder_model_embed.weight):
if p1.data.ne(p2.data).sum() > 0:
models_equal = False
else:
for p1, p2 in zip(cloned_embeddings, model_embed.weight):
if p1.data.ne(p2.data).sum() > 0:
models_equal = False
self.assertTrue(models_equal)
def test_resize_tokens_embeddings(self):
(
original_config,
inputs_dict,
) = self.model_tester.prepare_config_and_inputs_for_common()
if not self.test_resize_embeddings:
return
for model_class in self.all_model_classes:
config = copy.deepcopy(original_config)
model = self._make_model_instance(config, model_class)
if self.model_tester.is_training is False:
model.eval()
model_vocab_size = config.vocab_size
# Retrieve the embeddings and clone theme
model_embed = model.resize_token_embeddings(model_vocab_size)
cloned_embeddings = model_embed.weight.clone()
# Check that resizing the token embeddings with a larger vocab size increases the model's vocab size
model_embed = model.resize_token_embeddings(model_vocab_size + 10)
self.assertEqual(model.base_model.config.vocab_size, model_vocab_size + 10)
# Check that it actually resizes the embeddings matrix
self.assertEqual(model_embed.weight.shape[0], cloned_embeddings.shape[0] + 10)
# Check that the model can still do a forward pass successfully (every parameter should be resized)
model(**self._prepare_for_class(inputs_dict, model_class))
# Check that resizing the token embeddings with a smaller vocab size decreases the model's vocab size
model_embed = model.resize_token_embeddings(model_vocab_size - 15)
self.assertEqual(model.base_model.config.vocab_size, model_vocab_size - 15)
# Check that it actually resizes the embeddings matrix
self.assertEqual(model_embed.weight.shape[0], cloned_embeddings.shape[0] - 15)
# Check that the model can still do a forward pass successfully (every parameter should be resized)
# Input ids should be clamped to the maximum size of the vocabulary
inputs_dict["input_ids"] = paddle.clip(inputs_dict["input_ids"], max=model_vocab_size - 15 - 1)
# make sure that decoder_input_ids are resized as well
if "decoder_input_ids" in inputs_dict:
inputs_dict["decoder_input_ids"] = paddle.clip(
inputs_dict["decoder_input_ids"], max=model_vocab_size - 15 - 1
)
model(**self._prepare_for_class(inputs_dict, model_class))
# Check that adding and removing tokens has not modified the first part of the embedding matrix.
models_equal = True
for p1, p2 in zip(cloned_embeddings, model_embed.weight):
if not paddle.equal_all(p1, p2).item():
models_equal = False
break
self.assertTrue(models_equal)
def _compare_tensor(self, tensor1, tensor2, rtol=1e-04, atol=1e-04):
if tensor1.dtype != tensor2.dtype:
return False
if tensor1.dtype in [paddle.float32, paddle.float64]:
return paddle.allclose(tensor1, tensor2, rtol=rtol, atol=atol)
else:
return paddle.equal_all(tensor1, tensor2)
def test_inputs_embeds(self):
# pass the test if don't need to test inputs embeddings
if not self.use_test_inputs_embeds:
return
# get config for model and inputs_dict for model forward
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
# test all model classes
for model_class in self.all_model_classes:
model = self._make_model_instance(config, model_class)
model.eval()
inputs = copy.deepcopy(self._prepare_for_class(inputs_dict, model_class))
with paddle.no_grad():
ids_output = model(**inputs)
if not self.is_encoder_decoder:
input_ids = inputs["input_ids"]
del inputs["input_ids"]
else:
encoder_input_ids = inputs["input_ids"]
decoder_input_ids = inputs.get("decoder_input_ids", encoder_input_ids)
del inputs["input_ids"]
inputs.pop("decoder_input_ids", None)
wte = model.get_input_embeddings()
if not self.is_encoder_decoder:
inputs["inputs_embeds"] = wte(input_ids)
else:
inputs["inputs_embeds"] = wte(encoder_input_ids)
inputs["decoder_inputs_embeds"] = wte(decoder_input_ids)
with paddle.no_grad():
embeds_output = model(**inputs)
if isinstance(embeds_output, paddle.Tensor):
self.assertTrue(self._compare_tensor(ids_output, embeds_output))
else:
for ids_item, embeds_item in zip(ids_output, embeds_output):
self.assertTrue(self._compare_tensor(ids_item, embeds_item))
def test_model_name_list(self):
if not self.use_test_model_name_list:
return
config = self.model_tester.get_config()
if isinstance(config, PretrainedConfig):
model = self.base_model_class(config)
else:
model = self.base_model_class(**config)
self.assertTrue(len(model.model_name_list) != 0)
def test_pretrained_config_save_load(self):
if self.base_model_class is None or not self.base_model_class.constructed_from_pretrained_config():
return
config_class = self.base_model_class.config_class
with tempfile.TemporaryDirectory() as tempdir:
config = config_class()
config.save_pretrained(tempdir)
# check the file exist
self.assertFalse(os.path.exists(os.path.join(tempdir, LEGACY_CONFIG_NAME)))
self.assertTrue(os.path.exists(os.path.join(tempdir, CONFIG_NAME)))
# rename the CONFIG_NAME
shutil.move(os.path.join(tempdir, CONFIG_NAME), os.path.join(tempdir, LEGACY_CONFIG_NAME))
loaded_config = config.__class__.from_pretrained(tempdir)
for key in config.__dict__.keys():
if key == "paddlenlp_version" and config.paddlenlp_version is None:
continue
self.assertEqual(getattr(config, key), getattr(loaded_config, key))
def random_choice_pretrained_config_field(self) -> Optional[str]:
if self.base_model_class is None or not self.base_model_class.constructed_from_pretrained_config():
return None
config = self.base_model_class.config_class()
fields = [key for key, value in config.to_dict() if value]
return random.choice(fields)
def test_for_missed_attribute(self):
if not self.test_model_compatibility_keys:
self.skipTest(f"Do not test model_compatibility_keys on {self.base_model_class}")
return
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
if not model_class.constructed_from_pretrained_config():
continue
model = self._make_model_instance(config, model_class)
all_maps: dict = copy.deepcopy(model_class.config_class.attribute_map)
for old_attribute, new_attribute in all_maps.items():
old_value = getattr(model.config, old_attribute)
new_value = getattr(model.config, new_attribute)
# eg: dropout can be an instance of nn.Dropout, so we should check it attribute
if type(new_value) != type(old_value):
continue
self.assertEqual(old_value, new_value)
def test_tie_weight(self):
# test whether id of input_embeding equal id of output_embeding ?
if not self.test_tie_weights:
return
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
if "CausalLM" not in model_class.__name__ and "MaskedLM" not in model_class.__name__:
continue
model = self._make_model_instance(config, model_class)
if not model.config.tie_word_embeddings:
continue
if hasattr(model, "get_input_embeddings") and hasattr(model, "get_output_embeddings"):
try:
input_embeddings = model.get_input_embeddings()
except NotImplementedError:
continue
try:
output_embeddings = model.get_output_embeddings()
except NotImplementedError:
continue
if input_embeddings is not None and output_embeddings is not None:
if hasattr(output_embeddings, "weight"):
output_embeddings_weight = output_embeddings.weight
else:
output_embeddings_weight = output_embeddings
if hasattr(input_embeddings, "weight"):
input_embeddings_weight = input_embeddings.weight
else:
input_embeddings_weight = input_embeddings
print(
input_embeddings_weight,
output_embeddings_weight,
)
print(
"model name :{},id is{},{}".format(
model_class, id(output_embeddings_weight), id(input_embeddings_weight)
)
)
self.assertEqual(id(output_embeddings_weight), id(input_embeddings_weight))
class ModelTesterPretrainedMixin:
base_model_class: PretrainedModel = None
hf_remote_test_model_path: str = None
paddlehub_remote_test_model_path: str = None
# Download from HF doesn't work in CI yet
@slow
def test_model_from_pretrained_hf_hub(self):
if self.hf_remote_test_model_path is None or self.base_model_class is None:
return
model = self.base_model_class.from_pretrained(self.hf_remote_test_model_path, from_hf_hub=True)
self.assertIsNotNone(model)
def test_model_from_pretrained_paddle_hub(self):
if self.paddlehub_remote_test_model_path is None or self.base_model_class is None:
return
model = self.base_model_class.from_pretrained(self.paddlehub_remote_test_model_path)
self.assertIsNotNone(model)
def test_model_from_config_paddle_hub(self):
if self.paddlehub_remote_test_model_path is None or self.base_model_class is None:
return
config = self.base_model_class.config_class.from_pretrained(self.paddlehub_remote_test_model_path)
model = self.base_model_class.from_config(config)
self.assertIsNotNone(model)
@slow
def test_model_from_pretrained_with_cache_dir(self):
for model_name in list(self.base_model_class.pretrained_init_configuration)[:1]:
with tempfile.TemporaryDirectory() as tempdir:
tempdir = str(tempdir)
model = self.base_model_class.from_pretrained(model_name, cache_dir=tempdir)
self.assertIsNotNone(model)
self.assertTrue(
os.path.isfile(
os.path.join(tempdir, model_name, self.base_model_class.resource_files_names["model_state"])
)
)
self.assertTrue(
os.path.isfile(os.path.join(tempdir, model_name, self.base_model_class.model_config_file))
)
@slow
def test_pretrained_save_and_load(self):
"""test the pretrained model save and load with two different ways: url-file-name & model_state name
eg: `bert-base-uncased.pdparams` and `model_state.pdparams`
"""
for model_name in list(self.base_model_class.pretrained_init_configuration)[:1]:
model = self.base_model_class.from_pretrained(model_name)
self.assertIsNotNone(model)
# 1. save and load
with tempfile.TemporaryDirectory() as tempdir:
tempdirname = str(tempdir)
model.save_pretrained(tempdirname)
loaded_model = self.base_model_class.from_pretrained(tempdirname)
check_two_model_parameter(model, loaded_model)
class DistributedTest(unittest.TestCase):
def setUp(self) -> None:
self.gpus = "0,1"
def get_world_size(self):
return len(self.gpus.split(","))
def run_on_gpu(
self,
training_script,
training_script_args=None,
gpus: str = "0,1",
eager_mode=True,
allocator_strategy="auto_growth",
):
if not paddle.framework.core.is_compiled_with_cuda() or paddle.framework.core.get_cuda_device_count() == 0:
return
cluster = None
pod = None
cluster, pod = get_cluster_from_args(get_gpus(gpus))
procs = start_local_trainers(
cluster,
pod,
eager_mode=eager_mode,
allocator_strategy=allocator_strategy,
training_script=training_script,
training_script_args=training_script_args,
)
while True:
alive = watch_local_trainers(procs, cluster.trainers_endpoints())
if not alive:
print("Local procs complete, POD info:{}".format(pod))
break
time.sleep(3)
class GenerationD2STestMixin:
article = """Justin Timberlake and Jessica Biel, welcome to parenthood."""
internal_testing_model = None
TokenizerClass = AutoTokenizer
CausalLMClass = AutoModelForCausalLM
max_new_tokens = 20
def setUp(self):
paddle.disable_static()
super().setUp()
def tearDown(self):
paddle.disable_static()
super().setUp()
@unittest.skip("Paddle enable PIR API in Python")
def test_to_static_use_top_k(self):
tokenizer = self.TokenizerClass.from_pretrained(self.internal_testing_model)
if tokenizer.__class__.__name__ == "LlamaTokenizer":
tokenizer.pad_token = tokenizer.eos_token if tokenizer.eos_token else "<pad>"
model = self.CausalLMClass.from_pretrained(self.internal_testing_model)
model_kwargs = tokenizer(
self.article,
max_length=self.max_new_tokens,
truncation=True,
truncation_side="left",
return_tensors="pd",
padding=True,
add_special_tokens=True,
)
model.is_encoder_decoder = False
model.eval()
model_kwargs["use_cache"] = True
model_kwargs["max_length"] = self.max_new_tokens + model_kwargs["input_ids"].shape[-1]
decoded_ids = model.greedy_search(
logits_processors=None,
bos_token_id=model.config.bos_token_id,
pad_token_id=model.config.pad_token_id,
eos_token_id=model.config.eos_token_id,
**model_kwargs,
)[0]
dygraph_decoded_ids = decoded_ids.tolist()
with static_mode_guard():
with tempfile.TemporaryDirectory() as tempdir:
path = os.path.join(tempdir, "model")
model.to_static(
path,
config=dict(
use_top_p=False,
),
)
model_path = os.path.join(tempdir, f"model{PADDLE_INFERENCE_MODEL_SUFFIX}")
params_path = os.path.join(tempdir, f"model{PADDLE_INFERENCE_WEIGHTS_SUFFIX}")
config = paddle.inference.Config(model_path, params_path)
config.disable_gpu()
config.disable_glog_info()
predictor = paddle.inference.create_predictor(config)
model_kwargs["top_k"] = 1
model_kwargs["max_new_tokens"] = self.max_new_tokens
# create input
for key in model_kwargs.keys():
if paddle.is_tensor(model_kwargs[key]):
model_kwargs[key] = model_kwargs[key].numpy()
elif isinstance(model_kwargs[key], float):
model_kwargs[key] = np.array(model_kwargs[key], dtype="float32")
else:
model_kwargs[key] = np.array(model_kwargs[key], dtype="int64")
input_handles = {}
for name in predictor.get_input_names():
input_handles[name] = predictor.get_input_handle(name)
input_handles[name].copy_from_cpu(model_kwargs[name])
predictor.run()
output_names = predictor.get_output_names()
output_handle = predictor.get_output_handle(output_names[0])
results = output_handle.copy_to_cpu()
static_decoded_ids = results.tolist()
self.assertEqual(len(dygraph_decoded_ids[0]), self.max_new_tokens)
self.assertEqual(len(static_decoded_ids[0]), self.max_new_tokens)
self.assertEqual(dygraph_decoded_ids, static_decoded_ids)
@unittest.skip("Paddle enable PIR API in Python")
def test_to_static_use_top_p(self):
tokenizer = self.TokenizerClass.from_pretrained(self.internal_testing_model)
if tokenizer.__class__.__name__ == "LlamaTokenizer":
tokenizer.pad_token = tokenizer.eos_token if tokenizer.eos_token else "<pad>"
model = self.CausalLMClass.from_pretrained(self.internal_testing_model)
model_kwargs = tokenizer(
self.article,
max_length=self.max_new_tokens,
truncation=True,
truncation_side="left",
return_tensors="pd",
padding=True,
add_special_tokens=True,
)
model.eval()
model_kwargs["use_cache"] = True
model_kwargs["max_new_tokens"] = self.max_new_tokens
with static_mode_guard():
with tempfile.TemporaryDirectory() as tempdir:
path = os.path.join(tempdir, "model")
model.to_static(
path,
config=dict(
use_top_p=False,
),
)
model_path = os.path.join(tempdir, f"model{PADDLE_INFERENCE_MODEL_SUFFIX}")
params_path = os.path.join(tempdir, f"model{PADDLE_INFERENCE_WEIGHTS_SUFFIX}")
config = paddle.inference.Config(model_path, params_path)
config.disable_gpu()
config.disable_glog_info()
predictor = paddle.inference.create_predictor(config)
model_kwargs["top_k"] = 1
model_kwargs["max_new_tokens"] = self.max_new_tokens
# create input
for key in model_kwargs.keys():
if paddle.is_tensor(model_kwargs[key]):
model_kwargs[key] = model_kwargs[key].numpy()
else:
model_kwargs[key] = np.array(model_kwargs[key])
input_handles = {}
for name in predictor.get_input_names():
input_handles[name] = predictor.get_input_handle(name)
input_handles[name].copy_from_cpu(model_kwargs[name])
predictor.run()
output_names = predictor.get_output_names()
output_handle = predictor.get_output_handle(output_names[0])
results = output_handle.copy_to_cpu()
self.assertEqual(len(results.tolist()[0]), self.max_new_tokens)
self.assertIsNotNone(results)