Skip to content

Commit ebc2b1b

Browse files
authored
update ernie text cls ci (#823)
* add ernie text cls ci * mv ernie_text_cls_params.txt to ernie_text_cls directory
1 parent af62459 commit ebc2b1b

File tree

4 files changed

+580
-9
lines changed

4 files changed

+580
-9
lines changed

tests/ernie_text_cls_params.txt renamed to tests/ernie_text_cls/ernie_text_cls_params.txt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
model_name:ernie_text_cls
33
python:python
44
gpu_list:0|0,1
5-
Global.use_gpu:null
6-
Global.auto_cast:null
5+
null:null
6+
null:null
77
--epoch:1
88
--save_dir:./output/
99
--batch_size:32
10-
Global.pretrained_model:null
11-
train_model_name:null
12-
train_infer_img_dir:null
10+
null:null
11+
null:null
12+
null:null
1313
null:null
1414
##
1515
trainer:norm
16-
norm_train:../examples/text_classification/pretrained_models/train.py
16+
norm_train:./ernie_text_cls/train.py
1717
pact_train:null
1818
fpgm_train:null
1919
distill_train:null
@@ -27,14 +27,17 @@ null:null
2727
===========================infer_params===========================
2828
--output_path:./output
2929
--params_path: ./output/model_100/model_state.pdparams
30-
norm_export:../examples/text_classification/pretrained_models/export_model.py
30+
norm_export:./ernie_text_cls/export_model.py
3131
quant_export:null
3232
fpgm_export:null
3333
distill_export:null
3434
null:null
3535
null:null
3636
##
37-
inference:../examples/text_classification/pretrained_models/deploy/python/predict.py
37+
infer_model:null
38+
infer_export:null
39+
infer_quant:null
40+
inference:./ernie_text_cls/predict.py
3841
--device:cpu|gpu
3942
--enable_mkldnn:True|False
4043
--cpu_threads:1|6
@@ -45,4 +48,4 @@ inference:../examples/text_classification/pretrained_models/deploy/python/predic
4548
--image_dir:null
4649
--save_log_path:null
4750
--benchmark:True
48-
null:nul
51+
null:nul
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import argparse
16+
import os
17+
from functools import partial
18+
19+
import numpy as np
20+
import paddle
21+
import paddle.nn.functional as F
22+
import paddlenlp as ppnlp
23+
from paddlenlp.data import Stack, Tuple, Pad
24+
25+
# yapf: disable
26+
parser = argparse.ArgumentParser()
27+
parser.add_argument("--params_path", type=str, required=True, default='./checkpoint/model_900/model_state.pdparams', help="The path to model parameters to be loaded.")
28+
parser.add_argument("--output_path", type=str, default='./output', help="The path of model parameter in static graph to be saved.")
29+
args = parser.parse_args()
30+
# yapf: enable
31+
32+
if __name__ == "__main__":
33+
# The number of labels should be in accordance with the training dataset.
34+
label_map = {0: 'negative', 1: 'positive'}
35+
model = ppnlp.transformers.ErnieForSequenceClassification.from_pretrained(
36+
"ernie-tiny", num_classes=len(label_map))
37+
38+
if args.params_path and os.path.isfile(args.params_path):
39+
state_dict = paddle.load(args.params_path)
40+
model.set_dict(state_dict)
41+
print("Loaded parameters from %s" % args.params_path)
42+
model.eval()
43+
44+
# Convert to static graph with specific input description
45+
model = paddle.jit.to_static(
46+
model,
47+
input_spec=[
48+
paddle.static.InputSpec(
49+
shape=[None, None], dtype="int64"), # input_ids
50+
paddle.static.InputSpec(
51+
shape=[None, None], dtype="int64") # segment_ids
52+
])
53+
# Save in static graph model.
54+
save_path = os.path.join(args.output_path, "inference")
55+
paddle.jit.save(model, save_path)

tests/ernie_text_cls/predict.py

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import argparse
16+
import os
17+
18+
import numpy as np
19+
import paddle
20+
import paddlenlp as ppnlp
21+
from scipy.special import softmax
22+
from paddle import inference
23+
from paddlenlp.data import Stack, Tuple, Pad
24+
from paddlenlp.datasets import load_dataset
25+
from paddlenlp.utils.log import logger
26+
27+
# yapf: disable
28+
parser = argparse.ArgumentParser()
29+
parser.add_argument("--model_dir", type=str, required=True,
30+
help="The directory to static model.")
31+
32+
parser.add_argument("--max_seq_length", default=128, type=int,
33+
help="The maximum total input sequence length after tokenization. Sequences "
34+
"longer than this will be truncated, sequences shorter will be padded.")
35+
parser.add_argument("--batch_size", default=2, type=int,
36+
help="Batch size per GPU/CPU for training.")
37+
parser.add_argument('--device', choices=['cpu', 'gpu', 'xpu'], default="gpu",
38+
help="Select which device to train model, defaults to gpu.")
39+
40+
parser.add_argument('--use_tensorrt', default=False, type=eval, choices=[True, False],
41+
help='Enable to use tensorrt to speed up.')
42+
parser.add_argument("--precision", default="fp32", type=str, choices=["fp32", "fp16", "int8"],
43+
help='The tensorrt precision.')
44+
45+
parser.add_argument('--cpu_threads', default=10, type=int,
46+
help='Number of threads to predict when using cpu.')
47+
parser.add_argument('--enable_mkldnn', default=False, type=eval, choices=[True, False],
48+
help='Enable to use mkldnn to speed up when using cpu.')
49+
50+
parser.add_argument("--benchmark", type=eval, default=False,
51+
help="To log some information about environment and running.")
52+
parser.add_argument("--save_log_path", type=str, default="./log_output/",
53+
help="The file path to save log.")
54+
args = parser.parse_args()
55+
# yapf: enable
56+
57+
58+
def convert_example(example,
59+
tokenizer,
60+
label_list,
61+
max_seq_length=512,
62+
is_test=False):
63+
"""
64+
Builds model inputs from a sequence or a pair of sequence for sequence classification tasks
65+
by concatenating and adding special tokens. And creates a mask from the two sequences passed
66+
to be used in a sequence-pair classification task.
67+
68+
A BERT sequence has the following format:
69+
70+
- single sequence: ``[CLS] X [SEP]``
71+
- pair of sequences: ``[CLS] A [SEP] B [SEP]``
72+
73+
A BERT sequence pair mask has the following format:
74+
::
75+
0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
76+
| first sequence | second sequence |
77+
78+
If only one sequence, only returns the first portion of the mask (0's).
79+
80+
81+
Args:
82+
example(obj:`list[str]`): List of input data, containing text and label if it have label.
83+
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
84+
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
85+
label_list(obj:`list[str]`): All the labels that the data has.
86+
max_seq_len(obj:`int`): The maximum total input sequence length after tokenization.
87+
Sequences longer than this will be truncated, sequences shorter will be padded.
88+
is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
89+
90+
Returns:
91+
input_ids(obj:`list[int]`): The list of token ids.
92+
segment_ids(obj: `list[int]`): List of sequence pair mask.
93+
label(obj:`numpy.array`, data type of int64, optional): The input label if not is_test.
94+
"""
95+
text = example
96+
encoded_inputs = tokenizer(text=text, max_seq_len=max_seq_length)
97+
input_ids = encoded_inputs["input_ids"]
98+
segment_ids = encoded_inputs["token_type_ids"]
99+
100+
if not is_test:
101+
# create label maps
102+
label_map = {}
103+
for (i, l) in enumerate(label_list):
104+
label_map[l] = i
105+
106+
label = label_map[label]
107+
label = np.array([label], dtype="int64")
108+
return input_ids, segment_ids, label
109+
else:
110+
return input_ids, segment_ids
111+
112+
113+
class Predictor(object):
114+
def __init__(self,
115+
model_dir,
116+
device="gpu",
117+
max_seq_length=128,
118+
batch_size=32,
119+
use_tensorrt=False,
120+
precision="fp32",
121+
cpu_threads=10,
122+
enable_mkldnn=False):
123+
self.max_seq_length = max_seq_length
124+
self.batch_size = batch_size
125+
126+
model_file = model_dir + "/inference.pdmodel"
127+
params_file = model_dir + "/inference.pdiparams"
128+
if not os.path.exists(model_file):
129+
raise ValueError("not find model file path {}".format(model_file))
130+
if not os.path.exists(params_file):
131+
raise ValueError("not find params file path {}".format(params_file))
132+
config = paddle.inference.Config(model_file, params_file)
133+
134+
if device == "gpu":
135+
# set GPU configs accordingly
136+
# such as intialize the gpu memory, enable tensorrt
137+
config.enable_use_gpu(100, 0)
138+
precision_map = {
139+
"fp16": inference.PrecisionType.Half,
140+
"fp32": inference.PrecisionType.Float32,
141+
"int8": inference.PrecisionType.Int8
142+
}
143+
precision_mode = precision_map[precision]
144+
145+
if args.use_tensorrt:
146+
config.enable_tensorrt_engine(
147+
max_batch_size=batch_size,
148+
min_subgraph_size=30,
149+
precision_mode=precision_mode)
150+
elif device == "cpu":
151+
# set CPU configs accordingly,
152+
# such as enable_mkldnn, set_cpu_math_library_num_threads
153+
config.disable_gpu()
154+
if args.enable_mkldnn:
155+
# cache 10 different shapes for mkldnn to avoid memory leak
156+
config.set_mkldnn_cache_capacity(10)
157+
config.enable_mkldnn()
158+
config.set_cpu_math_library_num_threads(args.cpu_threads)
159+
elif device == "xpu":
160+
# set XPU configs accordingly
161+
config.enable_xpu(100)
162+
163+
config.switch_use_feed_fetch_ops(False)
164+
self.predictor = paddle.inference.create_predictor(config)
165+
self.input_handles = [
166+
self.predictor.get_input_handle(name)
167+
for name in self.predictor.get_input_names()
168+
]
169+
self.output_handle = self.predictor.get_output_handle(
170+
self.predictor.get_output_names()[0])
171+
172+
if args.benchmark:
173+
import auto_log
174+
pid = os.getpid()
175+
self.autolog = auto_log.AutoLogger(
176+
model_name="ernie-tiny",
177+
model_precision=precision,
178+
batch_size=self.batch_size,
179+
data_shape="dynamic",
180+
save_path=args.save_log_path,
181+
inference_config=config,
182+
pids=pid,
183+
process_name=None,
184+
gpu_ids=0,
185+
time_keys=[
186+
'preprocess_time', 'inference_time', 'postprocess_time'
187+
],
188+
warmup=0,
189+
logger=logger)
190+
191+
def predict(self, data, tokenizer, label_map):
192+
"""
193+
Predicts the data labels.
194+
195+
Args:
196+
data (obj:`List(str)`): The batch data whose each element is a raw text.
197+
tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer`
198+
which contains most of the methods. Users should refer to the superclass for more information regarding methods.
199+
label_map(obj:`dict`): The label id (key) to label str (value) map.
200+
201+
Returns:
202+
results(obj:`dict`): All the predictions labels.
203+
"""
204+
if args.benchmark:
205+
self.autolog.times.start()
206+
207+
examples = []
208+
for text in data:
209+
input_ids, segment_ids = convert_example(
210+
text,
211+
tokenizer,
212+
label_list=label_map.values(),
213+
max_seq_length=self.max_seq_length,
214+
is_test=True)
215+
examples.append((input_ids, segment_ids))
216+
217+
batchify_fn = lambda samples, fn=Tuple(
218+
Pad(axis=0, pad_val=tokenizer.pad_token_id), # input
219+
Pad(axis=0, pad_val=tokenizer.pad_token_id), # segment
220+
): fn(samples)
221+
222+
if args.benchmark:
223+
self.autolog.times.stamp()
224+
225+
input_ids, segment_ids = batchify_fn(examples)
226+
self.input_handles[0].copy_from_cpu(input_ids)
227+
self.input_handles[1].copy_from_cpu(segment_ids)
228+
self.predictor.run()
229+
logits = self.output_handle.copy_to_cpu()
230+
if args.benchmark:
231+
self.autolog.times.stamp()
232+
233+
probs = softmax(logits, axis=1)
234+
idx = np.argmax(probs, axis=1)
235+
idx = idx.tolist()
236+
labels = [label_map[i] for i in idx]
237+
238+
if args.benchmark:
239+
self.autolog.times.end(stamp=True)
240+
241+
return labels
242+
243+
244+
if __name__ == "__main__":
245+
# Define predictor to do prediction.
246+
predictor = Predictor(args.model_dir, args.device, args.max_seq_length,
247+
args.batch_size, args.use_tensorrt, args.precision,
248+
args.cpu_threads, args.enable_mkldnn)
249+
250+
# ErnieTinyTokenizer is special for ernie-tiny pretained model.
251+
tokenizer = ppnlp.transformers.ErnieTinyTokenizer.from_pretrained(
252+
'ernie-tiny')
253+
test_ds = load_dataset("chnsenticorp", splits=["test"])
254+
data = [d["text"] for d in test_ds]
255+
batches = [
256+
data[idx:idx + args.batch_size]
257+
for idx in range(0, len(data), args.batch_size)
258+
]
259+
label_map = {0: 'negative', 1: 'positive'}
260+
261+
results = []
262+
for batch_data in batches:
263+
results.extend(predictor.predict(batch_data, tokenizer, label_map))
264+
for idx, text in enumerate(data):
265+
print('Data: {} \t Label: {}'.format(text, results[idx]))
266+
if args.benchmark:
267+
predictor.autolog.report()

0 commit comments

Comments
 (0)