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

206 lines
7.5 KiB
Python

# Copyright (c) 2021 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 argparse
import json
import math
import os
import paddle
from paddleslim.nas.ofa import OFA, utils
from paddleslim.nas.ofa.convert_super import Convert, supernet
from paddlenlp.transformers import (
BertForSequenceClassification,
BertModel,
BertTokenizer,
)
MODEL_CLASSES = {
"bert": (BertForSequenceClassification, BertTokenizer),
}
def bert_forward(
self, input_ids, token_type_ids=None, position_ids=None, attention_mask=None, output_hidden_states=False
):
wtype = self.pooler.dense.fn.weight.dtype if hasattr(self.pooler.dense, "fn") else self.pooler.dense.weight.dtype
if attention_mask is None:
attention_mask = paddle.unsqueeze((input_ids == self.pad_token_id).astype(wtype) * -1e9, axis=[1, 2])
else:
if attention_mask.ndim == 2:
# attention_mask [batch_size, sequence_length] -> [batch_size, 1, 1, sequence_length]
attention_mask = attention_mask.unsqueeze(axis=[1, 2])
embedding_output = self.embeddings(input_ids=input_ids, position_ids=position_ids, token_type_ids=token_type_ids)
if output_hidden_states:
output = embedding_output
encoder_outputs = []
for mod in self.encoder.layers:
output = mod(output, src_mask=attention_mask)
encoder_outputs.append(output)
if self.encoder.norm is not None:
encoder_outputs[-1] = self.encoder.norm(encoder_outputs[-1])
pooled_output = self.pooler(encoder_outputs[-1])
else:
sequence_output = self.encoder(embedding_output, attention_mask)
pooled_output = self.pooler(sequence_output)
if output_hidden_states:
return encoder_outputs, pooled_output
else:
return sequence_output, pooled_output
BertModel.forward = bert_forward
def parse_args():
parser = argparse.ArgumentParser()
# Required parameters
parser.add_argument(
"--model_type",
default=None,
type=str,
required=True,
help="Model type selected in the list: " + ", ".join(MODEL_CLASSES.keys()),
)
parser.add_argument(
"--model_name_or_path",
default=None,
type=str,
required=True,
help="Path to pre-trained model or shortcut name selected in the list: "
+ ", ".join(
sum([list(classes[-1].pretrained_init_configuration.keys()) for classes in MODEL_CLASSES.values()], [])
),
)
parser.add_argument(
"--sub_model_output_dir",
default=None,
type=str,
required=True,
help="The output directory where the sub model predictions and checkpoints will be written.",
)
parser.add_argument(
"--static_sub_model",
default=None,
type=str,
help="The output directory where the sub static model will be written. If set to None, not export static model",
)
parser.add_argument(
"--max_seq_length",
default=128,
type=int,
help="The maximum total input sequence length after tokenization. Sequences longer "
"than this will be truncated, sequences shorter will be padded.",
)
parser.add_argument("--n_gpu", type=int, default=1, help="number of gpus to use, 0 for cpu.")
parser.add_argument("--width_mult", type=float, default=1.0, help="width mult you want to export")
parser.add_argument("--depth_mult", type=float, default=1.0, help="depth mult you want to export")
args = parser.parse_args()
return args
def export_static_model(model, model_path, max_seq_length):
input_shape = [
paddle.static.InputSpec(shape=[None, max_seq_length], dtype="int64"),
paddle.static.InputSpec(shape=[None, max_seq_length], dtype="int64"),
]
net = paddle.jit.to_static(model, input_spec=input_shape)
paddle.jit.save(net, model_path)
def do_train(args):
paddle.set_device("gpu" if args.n_gpu else "cpu")
args.model_type = args.model_type.lower()
model_class, tokenizer_class = MODEL_CLASSES[args.model_type]
config_path = os.path.join(args.model_name_or_path, "model_config.json")
cfg_dict = dict(json.loads(open(config_path).read()))
kept_layers_index = {}
if args.depth_mult < 1.0:
depth = round(cfg_dict["init_args"][0]["num_hidden_layers"] * args.depth_mult)
cfg_dict["init_args"][0]["num_hidden_layers"] = depth
for idx, i in enumerate(range(1, depth + 1)):
kept_layers_index[idx] = math.floor(i / args.depth_mult) - 1
os.rename(config_path, config_path + "_bak")
with open(config_path, "w", encoding="utf-8") as f:
f.write(json.dumps(cfg_dict, ensure_ascii=False))
num_labels = cfg_dict["num_classes"]
model = model_class.from_pretrained(args.model_name_or_path, num_classes=num_labels)
origin_model = model_class.from_pretrained(args.model_name_or_path, num_classes=num_labels)
os.rename(config_path + "_bak", config_path)
sp_config = supernet(expand_ratio=[1.0, args.width_mult])
model = Convert(sp_config).convert(model)
ofa_model = OFA(model)
sd = paddle.load(os.path.join(args.model_name_or_path, "model_state.pdparams"))
if len(kept_layers_index) == 0:
ofa_model.model.set_state_dict(sd)
else:
for name, params in ofa_model.model.named_parameters():
if "encoder" not in name:
params.set_value(sd[name])
else:
idx = int(name.strip().split(".")[3])
mapping_name = name.replace("." + str(idx) + ".", "." + str(kept_layers_index[idx]) + ".")
params.set_value(sd[mapping_name])
best_config = utils.dynabert_config(ofa_model, args.width_mult)
for name, sublayer in ofa_model.model.named_sublayers():
if isinstance(sublayer, paddle.nn.MultiHeadAttention):
sublayer.num_heads = int(args.width_mult * sublayer.num_heads)
ofa_model.export(
best_config,
input_shapes=[[1, args.max_seq_length], [1, args.max_seq_length]],
input_dtypes=["int64", "int64"],
origin_model=origin_model,
)
for name, sublayer in origin_model.named_sublayers():
if isinstance(sublayer, paddle.nn.MultiHeadAttention):
sublayer.num_heads = int(args.width_mult * sublayer.num_heads)
output_dir = os.path.join(args.sub_model_output_dir, "model_width_%.5f" % args.width_mult)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
model_to_save = origin_model
model_to_save.save_pretrained(output_dir)
if args.static_sub_model is not None:
export_static_model(origin_model, args.static_sub_model, args.max_seq_length)
def print_arguments(args):
"""print arguments"""
print("----------- Configuration Arguments -----------")
for arg, value in sorted(vars(args).items()):
print("%s: %s" % (arg, value))
print("------------------------------------------------")
if __name__ == "__main__":
args = parse_args()
print_arguments(args)
do_train(args)