File size: 13,265 Bytes
60b4efc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# coding=utf-8
# Copyright (c) 2024, HUAWEI CORPORATION.  All rights reserved.
# Copyright (c) 2024, NVIDIA CORPORATION.  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 or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
批量测试推理脚本 - 支持中英文测试样例
用于测试0416和0422模型的各个checkpoint
"""

import sys
import time
import logging
import argparse

import torch
from torch import distributed as dist

logging.basicConfig(format="")
logging.getLogger().setLevel(logging.INFO)

# 中文测试样例
CHINESE_PROMPTS = [
    "你好",
    "介绍一下北京",
    "为什么天空是蓝色的",
    "你知道杭州么",
    # "如果今天下雨你需要",
    # "请用中文解释什么是人工智能。",
    # "中国的首都是",
    # "解释什么是机器学习",
    # "今天天气如何"
    # "请写一首关于春天的短诗。",
    # "翻译成英文:今天天气很好。",
    # "请用中文写一个简单的Python函数,计算两个数的和。",
    # "请解释牛顿第一定律。",
    # "请用中文描述一下北京的天气。",
    # "1+1等于多少?",
    # "以下是关于中国历史的单项选择题,请直接给出正确答案的选项。秦朝统一中国是在哪一年?A. 公元前221年B. 公元前206年  C. 公元前256年 D. 公元前230年 答案:",
    # "国务院今日召开新闻发布会,宣布新一轮经济刺激政策将",
    # "人类大脑包含约860亿个神经元,这些神经元之间通过",
    # "她打开信封,看到第一行字,双手开始颤抖,因为",
    # "所有的哺乳动物都是温血动物。鲸鱼是哺乳动物。因此,",
    # "法国的首都是巴黎。德国的首都是柏林。日本的首都是",
    # '你有什么特长?',
    '为什么天空是蓝色的',
    '请用Python写一个计算斐波那契数列的函数',
    '解释一下"光合作用"的基本过程',
    '如果明天下雨,我应该如何出门',
    '比较一下猫和狗作为宠物的优缺点',
    '解释什么是机器学习',
    '推荐一些中国的美食'
]

# 英文测试样例
temp = "The following is a question. " * 10
ENGLISH_PROMPTS = [
    # temp + "Hello, how are you today?",
    # temp + "What is the capital of the United States?",
    # temp + "Please write a short poem about the ocean.",
    # temp + "Translate to Chinese: Artificial Intelligence is changing the world.",
    # temp + "Please explain the concept of machine learning.",
    # temp + "If you could travel anywhere, where would you go?",
    # temp + "Write a simple Python function to check if a number is even.",
    # temp + "What is the difference between CPU and GPU?",
    # temp + "Please describe what a neural network is.",
    # temp + "What is 2 times 3?",
    "The president announced today that the new economic policy would",
    "The human brain contains approximately 86 billion neurons. These neurons",
    "She opened the letter and read the first line. Her hands began to tremble because",
    "All mammals are warm-blooded. Whales are mammals. Therefore,",
    "The capital of France is Paris. The capital of Germany is Berlin. The capital of Japan is"
]


def print_flush(prev_str, curr_str):
    difference = ''.join([char2 for char1, char2 in zip(prev_str, curr_str) if char1 != char2])

    if len(prev_str) < len(curr_str):
        difference += curr_str[len(prev_str):]

    sys.stdout.write(difference)


def task_factory(args, model):
    """测试任务工厂"""
    task_map = {
        "greedy": task_greedy_search,
        "do_sample": task_do_sample,
        "batch_test": task_batch_test,
        "chat": task_chat,
    }

    total_tasks = args.task

    if total_tasks is None:
        total_tasks = ["greedy"]

    for task in total_tasks:
        if task not in task_map.keys():
            raise ValueError(f"Task name incorrect: {task}")

        task_map.get(task)(args, model)


def task_greedy_search(args, model):
    """Greedy Search - 单条测试"""
    instruction = "你好,请介绍一下你自己。"

    t = time.time()
    output = model.generate(
        [instruction],
        do_sample=False,
        max_new_tokens=args.max_new_tokens,
        stream=False
    )

    if dist.get_rank() == 0:
        logging.info("\n=============== Greedy Search ================")
        logging.info("\n输入:\n%s\n\n模型输出:\n%s", instruction, output)
        logging.info("==============================================")
        logging.info("\n耗时: %ss", round(time.time() - t, 2))

    dist.barrier()


def task_do_sample(args, model):
    """Do Sample - 单条测试"""
    # instruction = "你好,请介绍一下你自己。"
    instruction = "The president announced today that the new economic policy would"

    t = time.time()
    output = model.generate(
        [instruction],
        do_sample=True,
        top_k=args.top_k if args.top_k else 50,
        top_p=args.top_p if args.top_p else 0.95,
        temperature=args.temperature if args.temperature else 0.7,
        max_new_tokens=args.max_new_tokens,
        stream=False
    )

    if dist.get_rank() == 0:
        logging.info("\n=============== Do Sample ================")
        logging.info("\n输入:\n%s\n\n模型输出:\n%s", instruction, output)
        logging.info("==========================================")
        logging.info("\n耗时: %ss", round(time.time() - t, 2))

    dist.barrier()


def task_batch_test(args, model):
    """批量测试 - 测试所有中英文样例"""
    all_prompts = CHINESE_PROMPTS + ENGLISH_PROMPTS 
    
    logging.info("\n" + "=" * 60)
    logging.info("批量测试开始 - 共 %d 条测试样例", len(all_prompts))
    logging.info("=" * 60)
    
    results = []
    
    for i, instruction in enumerate(all_prompts):
        lang = "中文" if i < len(CHINESE_PROMPTS) else "英文"
        
        t = time.time()
        # output = model.generate(
        #     [instruction],
        #     do_sample=False,
        #     max_new_tokens=args.max_new_tokens,
        #     stream=False,
        # )
        output = model.generate(
            [instruction],
            do_sample=True,
            top_k=args.top_k if args.top_k else 50,
            top_p=args.top_p if args.top_p else 0.95,
            temperature=args.temperature if args.temperature else 0.7,
            max_new_tokens=args.max_new_tokens,
            stream=False
        )

        elapsed = round(time.time() - t, 2)
        
        if dist.get_rank() == 0:
            logging.info("\n--- 测试 %d [%s] ---", i + 1, lang)
            logging.info("输入: %s", instruction)
            logging.info("输出: %s", output[0] if isinstance(output, list) else output)
            logging.info("耗时: %ss", elapsed)
            
            results.append({
                "id": i + 1,
                "language": lang,
                "prompt": instruction,
                "output": output[0] if isinstance(output, list) else output,
                "elapsed": elapsed
            })
        
        dist.barrier()
    
    if dist.get_rank() == 0:
        logging.info("\n" + "=" * 60)
        logging.info("批量测试完成")
        logging.info("=" * 60)
        
        # 打印结果汇总
        logging.info("\n=== 测试结果汇总 ===")
        for r in results:
            logging.info("[%d] %s: %s -> %s (耗时%s)", 
                        r["id"], r["language"], r["prompt"][:20], 
                        r["output"][:50] if r["output"] else "无输出", r["elapsed"])


def task_chat(args, model):
    """交互式对话模式"""
    histories_no_template = []
    histories_template = []
    instruction = None
    prompt = ""
    input_template = "\n\nYou >> "
    command_clear = ["clear"]

    while True:
        terminate_runs = torch.zeros(1, dtype=torch.int64, device=torch.cuda.current_device())

        if dist.get_rank() == 0:
            if not histories_no_template and not histories_template:
                logging.info("===========================================================")
                logging.info("1. 输入 q, quit, exit 退出")
                logging.info("2. 输入 clear, new 开始新对话")
                logging.info("===========================================================")

            prompt = input(input_template)
            prompt = prompt.encode('utf-8', errors='ignore').decode('utf-8')
            if prompt.strip() in ["q", "exit", "quit"]:
                terminate_runs += 1

            if prompt.strip() in ["clear", "new"]:
                subprocess.call(command_clear)
                histories_no_template = []
                histories_template = []
                continue

            if not prompt.strip():
                continue

        dist.all_reduce(terminate_runs)
        dist.barrier()
        if terminate_runs > 0:
            break

        if not instruction.strip():
            continue

        responses = model.generate(
            instruction,
            do_sample=True,
            top_k=args.top_k if args.top_k else 50,
            top_p=args.top_p if args.top_p else 0.95,
            temperature=args.temperature if args.temperature else 0.7,
            max_new_tokens=args.max_new_tokens,
            stream=True,
            broadcast=True
        )

        # 处理响应
        prev = ""
        curr = ""
        output = ""
        for response in responses:
            curr = response[0]
            print_flush(prev, curr)
            prev = curr
            output = curr

        histories_template.append({"role": "assistant", "content": output})
        histories_no_template.append((prompt, output))
        if len(histories_no_template) > 3:
            histories_no_template.pop()


def main():
    """主函数 - 需要在MindSpeed环境中调用"""
    from mindspeed_llm import megatron_adaptor
    from megatron.core.models.gpt.gpt_layer_specs import get_gpt_layer_with_transformer_engine_spec, get_gpt_layer_local_spec
    from megatron.core.transformer.spec_utils import import_module
    from megatron.training import get_args, print_rank_0
    from megatron.legacy.model import GPTModel
    from megatron.training.initialize import initialize_megatron
    from megatron.training.arguments import core_transformer_config_from_args
    from mindspeed_llm.tasks.inference.module import GPTModelInfer, MegatronModuleForCausalLM

    def model_provider(pre_process=True, post_process=True):
        args = get_args()
        use_te = args.transformer_impl == "transformer_engine"

        print_rank_0('building GPT model ...')
        
        if args.yaml_cfg is not None:
            from megatron.training.yaml_arguments import core_transformer_config_from_yaml
            config = core_transformer_config_from_yaml(args, "language_model")
        else:
            config = core_transformer_config_from_args(args)

        if args.use_mcore_models:
            if args.spec is not None:
                transformer_layer_spec = import_module(args.spec)
            else:
                if use_te:
                    transformer_layer_spec = get_gpt_layer_with_transformer_engine_spec(args.num_experts, args.moe_grouped_gemm)
                else:
                    transformer_layer_spec = get_gpt_layer_local_spec(args.num_experts, args.moe_grouped_gemm)

            model = GPTModelInfer(
                config=config,
                transformer_layer_spec=transformer_layer_spec,
                vocab_size=args.padded_vocab_size,
                max_sequence_length=args.max_position_embeddings,
                pre_process=pre_process,
                post_process=post_process,
                fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,
                parallel_output=True if args.sequence_parallel else False,
                share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,
                position_embedding_type=args.position_embedding_type,
                rotary_percent=args.rotary_percent,
                seq_len_interpolation_factor=args.rotary_seq_len_interpolation_factor
            )
        else:
            model = GPTModel(
                config,
                parallel_output=True if args.sequence_parallel else False,
                pre_process=pre_process,
                post_process=post_process
            )

        return model

    initialize_megatron(args_defaults={'no_load_rng': True, 'no_load_optim': True})
    args = get_args()

    model = MegatronModuleForCausalLM.from_pretrained(
        model_provider=model_provider,
        pretrained_model_name_or_path=args.load
    )

    task_factory(args, model)


if __name__ == "__main__":
    main()