华为云用户手册

  • 精度测试 benchmark工具用于精度验证,主要工作原理是:固定模型的输入,通过benchmark工具进行推理,并将推理得到的输出与标杆数据进行相似度度量(余弦相似度和平均相对误差),得到模型转换后的精度偏差信息。使用benchmark进行精度比对的基本流程如下: 将模型输入保存二进制文件。 # 数据读取,预处理 image = img_preprocess(image_path) image = np.array(image, dtype=np.float32) image = np.frombuffer(image.tobytes(), np.float32) # 保存网络输入为二进制文件 image.tofile("input_data.bin") 将基准模型的输出保存到文本文件。 本例中输出节点名称为output_node_name,输出节点的shape为“(1, 1000)”,因此一共有两维,对应的输出文件为“output_node_name 2 1 1000”,再加上输出的值即可。 # 基于原始pth模型前向推理 output = model_inference(input_data) # 保存网络输出节点名称、维度、shape及输出到本地文件 with open("output_data.txt", "w") as f: f.write("output_node_name 2 1 1000\n") f.write(" ".join([str(i) for i in output])) 使用benchmark工具进行精度对比。 #shell benchmark --modelFile=model.mindir --inputShapes=1,3,224,224 --inDataFile=input_data.bin --device=Ascend --benchmarkDataFile=output_data.txt --accuracyThreshold=5 --cosineDistanceThreshold=0.99 其中,--accuracyThreshold=5表示平均绝对误差的容忍度最大为5%,--cosineDistanceThreshold =0.99表示余弦相似度至少为99%,--inputShapes可将模型放入到netron官网中查看。 图1 benchmark对接结果输出示例图 为了简化用户使用,ModelArts提供了Tailor工具便于用户进行Benchmark精度测试,具体使用方式参考Tailor指导文档。
  • 约束限制 创建在线服务时,每秒服务流量限制默认为100次,若静态benchmark的并发数(parallel-num参数)或动态benchmark的请求频率(request-rate参数)较高,会触发推理平台的流控,请在ModelArts Standard“在线服务”详情页修改服务流量限制。 同步请求时,平台每次请求预测的时间不能超过60秒。例如输出数据比较大的调用请求(例如输出大于1k),请求预测会超过60秒导致调用失败,可提交工单设置请求超时时间。
  • benchmark方法介绍 性能benchmark包括两部分。 静态性能测试:评估在固定输入、固定输出和固定并发下,模型的吞吐与首token延迟。该方式实现简单,能比较清楚的看出模型的性能和输入输出长度、以及并发的关系。 动态性能测试:评估在请求并发在一定范围内波动,且输入输出长度也在一定范围内变化时,模型的延迟和吞吐。该场景能模拟实际业务下动态的发送不同长度请求,能评估推理框架在实际业务中能支持的并发数。 性能benchmark验证使用到的脚本存放在代码包AscendCloud-LLM-x.x.x.zip的llm_evaluation目录下。 代码目录如下: benchmark_tools ├── benchmark_parallel.py # 评测静态性能脚本 ├── benchmark_serving.py # 评测动态性能脚本 ├── generate_dataset.py # 生成自定义数据集的脚本 ├── benchmark_utils.py # 工具函数集 ├── benchmark.py # 执行静态,动态性能评测脚本 执行性能测试脚本前,需先安装相关依赖。 pip install -r requirements.txt
  • 静态benchmark 运行静态benchmark验证脚本benchmark_parallel.py,具体操作命令如下,可以根据参数说明修改参数。 Notebook中进行测试: cd benchmark_tools python benchmark_parallel.py --backend vllm --host 127.0.0.1 --port 8080 --tokenizer /path/to/tokenizer --epochs 10 --parallel-num 1 2 4 8 --output-tokens 256 256 --prompt-tokens 1024 2048 --benchmark-csv benchmark_parallel.csv 生产环境中进行测试: python benchmark_parallel.py --backend vllm --url xxx --app-code xxx --tokenizer /path/to/tokenizer --epochs 10 --parallel-num 1 2 4 8 --output-tokens 256 256 --prompt-tokens 1024 2048 --benchmark-csv benchmark_parallel.csv 参数说明: --backend:服务类型,支持tgi、vllm、mindspore、openai等。本文档使用的推理接口是vllm。 --host:服务IP地址,如127.0.0.1。 --port:服务端口,和推理服务端口8080。 --url:若以vllm接口方式启动服务,API接口公网地址与"/generate"拼接而成;若以openai接口方式启动服务,API接口公网地址与"/v1/completions"拼接而成。部署成功后的在线服务详情页中可查看API接口公网地址。 图1 API接口公网地址 --app-code:获取方式见访问在线服务(APP认证)。 --tokenizer:tokenizer路径,HuggingFace的权重路径。若服务部署在Notebook中,该参数为Notebook中权重路径;若服务部署在生产环境中,该参数为本地模型权重路径。 --served-model-name:仅在以openai接口启动服务时需要该参数。若服务部署在Notebook中,该参数为Notebook中权重路径;若服务部署在生产环境中,该参数为服务启动脚本run_vllm.sh中的${model_path}。 --epochs:测试轮数,默认取值为5。 --parallel-num:每轮并发数,支持多个,如 1 4 8 16 32。 --prompt-tokens:输入长度,支持多个,如 128 128 2048 2048,数量需和--output-tokens的数量对应。 --output-tokens:输出长度,支持多个,如 128 2048 128 2048,数量需和--prompt-tokens的数量对应。 脚本运行完成后,测试结果保存在benchmark_parallel.csv中,示例如下图所示。 图2 静态benchmark测试结果(示意图)
  • 动态benchmark 获取测试数据集。 动态benchmark需要使用数据集进行测试,可以使用公开数据集,例如Alpaca、ShareGPT。也可以根据业务实际情况,使用generate_datasets.py脚本生成和业务数据分布接近的数据集。 公开数据集下载地址: ShareGPT: https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json Alpaca: https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json 使用generate_datasets.py脚本生成数据集方法: generate_datasets.py脚本通过指定输入输出长度的均值和标准差,生成一定数量的正态分布的数据。具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python generate_datasets.py --datasets custom_datasets.json --tokenizer /path/to/tokenizer \ --min-input 100 --max-input 3600 --avg-input 1800 --std-input 500 \ --min-output 40 --max-output 256 --avg-output 160 --std-output 30 --num-requests 1000 generate_datasets.py脚本执行参数说明如下: --datasets:数据集保存路径,如custom_datasets.json。 --tokenizer:tokenizer路径,可以是HuggingFace的权重路径。 --min-input:输入tokens最小长度,可以根据实际需求设置。 --max-input:输入tokens最大长度,可以根据实际需求设置。 --avg-input:输入tokens长度平均值,可以根据实际需求设置。 --std-input:输入tokens长度方差,可以根据实际需求设置。 --min-output:最小输出tokens长度,可以根据实际需求设置。 --max-output:最大输出tokens长度,可以根据实际需求设置。 --avg-output:输出tokens长度平均值,可以根据实际需求设置。 --std-output:输出tokens长度标准差,可以根据实际需求设置。 --num-requests:输出数据集的数量,可以根据实际需求设置。 执行脚本benchmark_serving.py测试动态benchmark。具体操作命令如下,可以根据参数说明修改参数。 Notebook中进行测试: cd benchmark_tools python benchmark_serving.py --backend vllm --host 127.0.0.1 --port 8080 --dataset custom_dataset.json --dataset-type custom --tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 --max-tokens 4096 --max-prompt-tokens 3768 --benchmark-csv benchmark_serving.csv 生产环境中进行测试: python benchmark_serving.py --backend vllm --url xxx --app-code xxx --dataset custom_dataset.json --dataset-type custom --tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 --max-tokens 4096 --max-prompt-tokens 3768 --benchmark-csv benchmark_serving.csv --backend:服务类型,支持tgi、vllm、mindspore、openai等。本文档使用的推理接口是vllm。 --host:服务IP地址,如127.0.0.1。 --port:服务端口。 --url:若以vllm接口方式启动服务,API接口公网地址与"/generate"拼接而成;若以openai接口方式启动服务,API接口公网地址与"/v1/completions"拼接而成。部署成功后的在线服务详情页中可查看API接口公网地址。 图3 API接口公网地址 --app-code:获取方式见访问在线服务(APP认证)。 --datasets:数据集路径。 --datasets-type:支持三种 "alpaca","sharegpt","custom"。custom为自定义数据集。 --tokenizer:tokenizer路径,可以是huggingface的权重路径。若服务部署在Notebook中,该参数为Notebook中权重路径;若服务部署在生产环境中,该参数为本地模型权重路径。 --served-model-name:仅在以openai接口启动服务时需要该参数。若服务部署在Notebook中,该参数为Notebook中权重路径;若服务部署在生产环境中,该参数为服务启动脚本run_vllm.sh中的${model_path}。 --request-rate:请求频率,支持多个,如 0.1 1 2。实际测试时,会根据request-rate为均值的指数分布来发送请求以模拟真实业务场景。 --num-prompts:某个频率下请求数,支持多个,如 10 100 100,数量需和--request-rate的数量对应。 --max-tokens:输入+输出限制的最大长度,模型启动参数--max-input-length值需要大于该值。 --max-prompt-tokens:输入限制的最大长度,推理时最大输入tokens数量,模型启动参数--max-total-tokens值需要大于该值,tokenizer建议带tokenizer.json的FastTokenizer。 --benchmark-csv:结果保存路径,如benchmark_serving.csv。 脚本运行完后,测试结果保存在benchmark_serving.csv中,示例如下图所示。 图4 动态benchmark测试结果(示意图)
  • benchmark方法介绍 性能benchmark包括两部分。 静态性能测试:评估在固定输入、固定输出和固定并发下,模型的吞吐与首token延迟。该方式实现简单,能比较清楚的看出模型的性能和输入输出长度、以及并发的关系。 动态性能测试:评估在请求并发在一定范围内波动,且输入输出长度也在一定范围内变化时,模型的延迟和吞吐。该场景能模拟实际业务下动态的发送不同长度请求,能评估推理框架在实际业务中能支持的并发数。 性能benchmark验证使用到的脚本存放在代码包AscendCloud-3rdLLM-x.x.x.zip的llm_evaluation目录下。 代码目录如下: benchmark_tools ├── benchmark_parallel.py # 评测静态性能脚本 ├── benchmark_serving.py # 评测动态性能脚本 ├── generate_dataset.py # 生成自定义数据集的脚本 ├── benchmark_utils.py # 工具函数集 ├── benchmark.py # 执行静态,动态性能评测脚本 执行性能测试脚本前,需先安装相关依赖。 pip install -r requirements.txt
  • 静态benchmark 运行静态benchmark验证脚本benchmark_parallel.py,具体操作命令如下,可以根据参数说明修改参数。 notebook中进行测试: cd benchmark_tools python benchmark_parallel.py --backend vllm --host 127.0.0.1 --port 8080 --tokenizer /path/to/tokenizer --epochs 10 --parallel-num 1 2 4 8 --output-tokens 256 256 --prompt-tokens 1024 2048 --benchmark-csv benchmark_parallel.csv 生产环境中进行测试: python benchmark_parallel.py --backend vllm --url xxx --app-code xxx --tokenizer /path/to/tokenizer --epochs 10 --parallel-num 1 2 4 8 --output-tokens 256 256 --prompt-tokens 1024 2048 --benchmark-csv benchmark_parallel.csv 参数说明: --backend:服务类型,支持tgi、vllm、mindspore等。本文档使用的推理接口是vllm。 --host:服务IP地址,如127.0.0.1。 --port:服务端口,和推理服务端口8080。 --url:API接口公网地址与"/v1/completions"拼接而成,部署成功后的在线服务详情页中可查看API接口公网地址。 图1 API接口公网地址 --app-code:获取方式见访问在线服务(APP认证)。 --tokenizer:tokenizer路径,HuggingFace的权重路径。若服务部署在notebook中,该参数为notebook中权重路径;若服务部署在生产环境中,该参数为服务启动脚本run_vllm.sh中${model_path}。 --epochs:测试轮数,默认取值为5。 --parallel-num:每轮并发数,支持多个,如 1 4 8 16 32。 --prompt-tokens:输入长度,支持多个,如 128 128 2048 2048,数量需和--output-tokens的数量对应。 --output-tokens:输出长度,支持多个,如 128 2048 128 2048,数量需和--prompt-tokens的数量对应。 脚本运行完成后,测试结果保存在benchmark_parallel.csv中,示例如下图所示。 图2 静态benchmark测试结果(示意图)
  • 动态benchmark 获取测试数据集。 动态benchmark需要使用数据集进行测试,可以使用公开数据集,例如Alpaca、ShareGPT。也可以根据业务实际情况,使用generate_datasets.py脚本生成和业务数据分布接近的数据集。 公开数据集下载地址: ShareGPT: https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json Alpaca: https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json 使用generate_datasets.py脚本生成数据集方法: generate_datasets.py脚本通过指定输入输出长度的均值和标准差,生成一定数量的正态分布的数据。具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python generate_datasets.py --datasets custom_datasets.json --tokenizer /path/to/tokenizer \ --min-input 100 --max-input 3600 --avg-input 1800 --std-input 500 \ --min-output 40 --max-output 256 --avg-output 160 --std-output 30 --num-requests 1000 generate_datasets.py脚本执行参数说明如下: --datasets:数据集保存路径,如custom_datasets.json。 --tokenizer:tokenizer路径,可以是HuggingFace的权重路径。 --min-input:输入tokens最小长度,可以根据实际需求设置。 --max-input:输入tokens最大长度,可以根据实际需求设置。 --avg-input:输入tokens长度平均值,可以根据实际需求设置。 --std-input:输入tokens长度方差,可以根据实际需求设置。 --min-output:最小输出tokens长度,可以根据实际需求设置。 --max-output:最大输出tokens长度,可以根据实际需求设置。 --avg-output:输出tokens长度平均值,可以根据实际需求设置。 --std-output:输出tokens长度标准差,可以根据实际需求设置。 --num-requests:输出数据集的数量,可以根据实际需求设置。 执行脚本benchmark_serving.py测试动态benchmark。具体操作命令如下,可以根据参数说明修改参数。 notebook中进行测试: cd benchmark_tools python benchmark_serving.py --backend vllm --host 127.0.0.1 --port 8080 --dataset custom_dataset.json --dataset-type custom --tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 --max-tokens 4096 --max-prompt-tokens 3768 --benchmark-csv benchmark_serving.csv 生产环境中进行测试: python benchmark_serving.py --backend vllm --url xxx --app-code xxx --dataset custom_dataset.json --dataset-type custom --tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 --max-tokens 4096 --max-prompt-tokens 3768 --benchmark-csv benchmark_serving.csv --backend:服务类型,支持tgi、vllm、mindspore等。本文档使用的推理接口是vllm。 --host:服务IP地址,如127.0.0.1。 --port:服务端口。 --url:API接口公网地址与"/v1/completions"拼接而成,部署成功后的在线服务详情页中可查看API接口公网地址。 图3 API接口公网地址 --app-code:获取方式见访问在线服务(APP认证)。 --datasets:数据集路径。 --datasets-type:支持三种 "alpaca","sharegpt","custom"。custom为自定义数据集。 --tokenizer:tokenizer路径,可以是huggingface的权重路径。若服务部署在notebook中,该参数为notebook中权重路径;若服务部署在生产环境中,该参数为服务启动脚本run_vllm.sh中${model_path}。 --request-rate:请求频率,支持多个,如 0.1 1 2。实际测试时,会根据request-rate为均值的指数分布来发送请求以模拟真实业务场景。 --num-prompts:某个频率下请求数,支持多个,如 10 100 100,数量需和--request-rate的数量对应。 --max-tokens:输入+输出限制的最大长度,模型启动参数--max-input-length值需要大于该值。 --max-prompt-tokens:输入限制的最大长度,推理时最大输入tokens数量,模型启动参数--max-total-tokens值需要大于该值,tokenizer建议带tokenizer.json的FastTokenizer。 --benchmark-csv:结果保存路径,如benchmark_serving.csv。 脚本运行完后,测试结果保存在benchmark_serving.csv中,示例如下图所示。 图4 动态benchmark测试结果(示意图)
  • 推理应用适配 MindSpore Lite提供了JAVA/C++/Python API,进行推理业务的适配,并且在构建模型时,通过上下文的参数来确定运行时的具体配置,例如运行后端的配置等。下文以Python接口为例。 使用MindSpore Lite推理框架执行推理并使用昇腾后端主要包括以下步骤: 创建运行上下文:创建Context,保存需要的一些基本配置参数,用于指导模型编译和模型执行,在昇腾迁移时需要特别指定target为“Ascend”,以及对应的deivce_id。 context = mslite.Context() context.target = ["ascend"] context.ascend.device_id = 0 模型加载与编译:执行推理之前,需要调用Model的build_from_file接口进行模型加载和模型编译。模型加载阶段将文件缓存解析成运行时的模型。模型编译阶段会耗费较多时间所以建议Model创建一次,编译一次,多次推理。 model = mslite.Model() model.build_from_file("./resnet50.mindir", mslite.ModelType.MINDIR, context) 输入数据:编译后的模型提供了predict接口用户执行模型推理任务,Inputs输入为List Tensor,这里的Tensor是MSLite的概念,具体的列表长度和tensor类型由转换时的InputShape来确定,由于后端指定了ascend,这些tensor都是在昇腾设备的显存中,用户需要在对应的tensor中填入数据,这些数据也会被搬移到显存中,进一步对于Inputs输入的内容进行处理。 data = convert_img(input_image) in_data = [np.array(data)] inputs = model.get_inputs() for i, _input in enumerate(inputs): _input.set_data_from_numpy(in_data[i]) 执行推理:使用Model的predict进行模型推理,返回值为Outputs,也是List Tensor类型,具体的长度和类别由模型定义,对应的Tensor数据由于指定了ascend后端,Output的内容在显存中,通过tesnor的get_data_to_numpy方法来获取,并将数据读取到内存中使用。 outputs = model.predict(inputs) outputs = [output.get_data_to_numpy() for output in outputs] 更多Python接口的高级用法与示例,请参考Python API。
  • 模型转换 在ModelArts开发环境中,通过对应的转换预置镜像,直接执行对应的转换过程,对应的转换和评估工具都已经预置了最新版本,详细介绍请见使用说明。inputShape查看方法请见转换关键参数准备。 !converter_lite --modelFile=resnet50.onnx --fmk=ONNX --outputFile=resnet50 --saveType=MINDIR --inputShape="input.1:1,3,224,224" --device=Ascend
  • 模型准备 MindSpore Lite提供的模型convertor工具可以支持主流的模型格式到MindIR的格式转换,用户需要导出对应的模型文件,推荐导出为ONNX格式。 如何导出ONNX模型 PyTorch转ONNX,操作指导请见此处。 PyTorch导出ONNX模型样例如下: import torch import torchvision model = torchvision.models.resnet50(pretrained=True) # 保存模型为ONNX格式 torch.onnx.export(model, torch.randn(1, 3, 224, 224), "resnet50.onnx") TensorFlow导出ONNX模型,操作指导请见此处。 如何导出PTH模型 PyTorch模型导出时需要包含模型的结构信息,需要利用jit.trace方式完成模型的导出与保存。 # If you are instantiating the model with *from_pretrained* you can also easily set the TorchScript flag model = BertModel.from_pretrained("bert-base-uncased", torchscript=True) # Creating the trace traced_model = torch.jit.trace(model, [tokens_tensor, segments_tensors]) torch.jit.save(traced_model, "traced_bert.pt")
  • 转换关键参数准备 对应的模型转换成MindIR格式,通过后端绑定的编译形式来运行以达到更好的性能(类似静态图的运行模式),所以需要提前准备以下几个重点参数。 输入的inputShape,包含batch信息。 MSLite涉及到编译优化的过程,不支持完全动态的权重模式,需要在转换时确定对应的inputShape,用于模型的格式的编译与转换,可以在netron官网进行查看,或者对于模型结构中的输入进行shape的打印,并明确输入的batch。 一般来说,推理时指定的inputShape是和用户的业务及推理场景是紧密相关的,可以通过原始模型推理脚本或者网络模型进行判断。需要把Notebook中的模型下载到本地后,再放入netron官网中,查看其inputShape。 如果netron中没有显示inputShape,可能由于使用了动态shape模型导致,请确保使用的是静态shape模型,静态shape模型文件导出方法请参考模型准备。 图1 netron中查看inputShape 精度选择。 精度选择需要在模型转换阶段进行配置,执行converter_lite命令式通过--configFile参数指定配置文件路径,配置文件通过precision_mode参数指定精度模式。可选的参数有“enforce_fp32”,“preferred_fp32”,“enforce_fp16”,“enforce_origin”或者“preferred_optimal”,默认为“enforce_fp16”。 [ascend_context] precision_mode= preferred_fp32
  • 静态benchmark验证 本章节介绍如何进行静态benchmark验证。 已经上传benchmark验证脚本到推理容器中。如果在Step5 进入容器安装推理依赖软件步骤中已经上传过AscendCloud-3rdLLM-x.x.x.zip并解压,无需重复执行。 进入benchmark_tools目录下,执行如下命令安装性能测试的关依赖。 pip install -r requirements.txt 运行静态benchmark验证脚本benchmark_parallel.py,具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python benchmark_parallel.py --backend vllm --host ${docker_ip} --port 8080 --tokenizer /path/to/tokenizer --epochs 5 \ --parallel-num 1 4 8 16 32 --prompt-tokens 1024 2048 --output-tokens 128 256 --benchmark-csv benchmark_parallel.csv 参数说明 --backend:服务类型,支持tgi、vllm、mindspore、openai等。本文档使用的推理接口是vllm。 --host ${docker_ip}:服务部署的IP地址,${docker_ip}替换为宿主机实际的IP地址。 --port:推理服务端口8080。 --tokenizer:tokenizer路径,HuggingFace的权重路径。 --epochs:测试轮数,默认取值为5 --parallel-num:每轮并发数,支持多个,如 1 4 8 16 32。 --prompt-tokens:输入长度,支持多个,如 128 128 2048 2048,数量需和--output-tokens的数量对应。 --output-tokens:输出长度,支持多个,如 128 2048 128 2048,数量需和--prompt-tokens的数量对应。 --benchmark-csv:结果保存路径,如benchmark_parallel.csv。 脚本运行完成后,测试结果保存在benchmark_parallel.csv中,示例如下图所示。 图1 静态benchmark测试结果(示意图)
  • benchmark方法介绍 性能benchmark包括两部分。 静态性能测试:评估在固定输入、固定输出和固定并发下,模型的吞吐与首token延迟。该方式实现简单,能比较清楚的看出模型的性能和输入输出长度、以及并发的关系。 动态性能测试:评估在请求并发在一定范围内波动,且输入输出长度也在一定范围内变化时,模型的延迟和吞吐。该场景能模拟实际业务下动态的发送不同长度请求,能评估推理框架在实际业务中能支持的并发数。 性能benchmark验证使用到的脚本存放在代码包AscendCloud-3rdLLM-xxx.zip的llm_tools/llm_evaluation(6.3.905版本)目录中。 代码目录如下: benchmark_tools ├── benchmark_parallel.py # 评测静态性能脚本 ├── benchmark_serving.py # 评测动态性能脚本 ├── generate_dataset.py # 生成自定义数据集的脚本 ├── benchmark_utils.py # 工具函数集 ├── benchmark.py # 执行静态,动态性能评测脚本、 ├── requirements.txt # 第三方依赖
  • 动态benchmark 本章节介绍如何进行动态benchmark验证。 获取数据集。动态benchmark需要使用数据集进行测试,可以使用公开数据集,例如Alpaca、ShareGPT。也可以根据业务实际情况,使用generate_datasets.py脚本生成和业务数据分布接近的数据集。 方法一:使用公开数据集 ShareGPT下载地址: https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json Alpaca下载地址: https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json 方法二:使用generate_dataset.py脚本生成数据集方法: generate_dataset.py脚本通过指定输入输出长度的均值和标准差,生成一定数量的正态分布的数据。具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python generate_dataset.py --dataset custom_datasets.json --tokenizer /path/to/tokenizer \ --min-input 100 --max-input 3600 --avg-input 1800 --std-input 500 \ --min-output 40 --max-output 256 --avg-output 160 --std-output 30 --num-requests 1000 generate_dataset.py脚本执行参数说明如下: --dataset:数据集保存路径,如custom_datasets.json --tokenizer:tokenizer路径,可以是HuggingFace的权重路径 --min-input:输入tokens最小长度,可以根据实际需求设置。 --max-input:输入tokens最大长度,可以根据实际需求设置。 --avg-input:输入tokens长度平均值,可以根据实际需求设置。 --std-input:输入tokens长度方差,可以根据实际需求设置。 --min-output:最小输出tokens长度,可以根据实际需求设置。 --max-output:最大输出tokens长度,可以根据实际需求设置。 --avg-output:输出tokens长度平均值,可以根据实际需求设置。 --std-output:输出tokens长度标准差,可以根据实际需求设置。 --num-requests:输出数据集的数量,可以根据实际需求设置。 执行脚本benchmark_serving.py测试动态benchmark。具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python benchmark_serving.py --backend vllm --host${docker_ip} --port 8085 --dataset custom_datasets.json --dataset-type custom \ --tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 \ --max-tokens 4096 --max-prompt-tokens 3768 --benchmark-csv benchmark_serving.csv --backend:服务类型,如"tgi",vllm","mindspore" --host ${docker_ip}:服务部署的IP地址,${docker_ip}替换为宿主机实际的IP地址。 --port:服务端口 --dataset:数据集路径 --dataset-type:支持三种 "alpaca","sharegpt","custom"。custom为自定义数据集。 --tokenizer:tokenizer路径,可以是huggingface的权重路径 --request-rate:请求频率,支持多个,如 0.1 1 2。实际测试时,会根据request-rate为均值的指数分布来发送请求以模拟真实业务场景。 --num-prompts:某个频率下请求数,支持多个,如 10 100 100,数量需和--request-rate的数量对应 --max-tokens:输入+输出限制的最大长度,模型启动参数--max-input-length值需要大于该值 --max-prompt-tokens:输入限制的最大长度,推理时最大输入tokens数量,模型启动参数--max-total-tokens值需要大于该值,tokenizer建议带tokenizer.json的FastTokenizer --benchmark-csv:结果保存路径,如benchmark_serving.csv 脚本运行完后,测试结果保存在benchmark_serving.csv中,示例如下图所示。 图2 动态benchmark测试结果(示意图)
  • 动态benchmark 本章节介绍如何进行动态benchmark验证。 获取数据集。动态benchmark需要使用数据集进行测试,可以使用公开数据集,例如Alpaca、ShareGPT。也可以根据业务实际情况,使用generate_datasets.py脚本生成和业务数据分布接近的数据集。 方法一:使用公开数据集 ShareGPT下载地址: https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json Alpaca下载地址: https://github.com/tatsu-lab/stanford_alpaca/blob/main/alpaca_data.json 方法二:使用generate_dataset.py脚本生成数据集方法: generate_dataset.py脚本通过指定输入输出长度的均值和标准差,生成一定数量的正态分布的数据。具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python generate_dataset.py --dataset custom_datasets.json --tokenizer /path/to/tokenizer \ --min-input 100 --max-input 3600 --avg-input 1800 --std-input 500 \ --min-output 40 --max-output 256 --avg-output 160 --std-output 30 --num-requests 1000 generate_dataset.py脚本执行参数说明如下: --dataset:数据集保存路径,如custom_datasets.json --tokenizer:tokenizer路径,可以是HuggingFace的权重路径。 --min-input:输入tokens最小长度,可以根据实际需求设置。 --max-input:输入tokens最大长度,可以根据实际需求设置。 --avg-input:输入tokens长度平均值,可以根据实际需求设置。 --std-input:输入tokens长度方差,可以根据实际需求设置。 --min-output:最小输出tokens长度,可以根据实际需求设置。 --max-output:最大输出tokens长度,可以根据实际需求设置。 --avg-output:输出tokens长度平均值,可以根据实际需求设置。 --std-output:输出tokens长度标准差,可以根据实际需求设置。 --num-requests:输出数据集的数量,可以根据实际需求设置。 执行脚本benchmark_serving.py测试动态benchmark。具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python benchmark_serving.py --backend vllm --host ${docker_ip} --port 8080 --dataset custom_datasets.json --dataset-type custom \ --tokenizer /path/to/tokenizer --request-rate 0.01 1 2 4 8 10 20 --num-prompts 10 1000 1000 1000 1000 1000 1000 \ --max-tokens 4096 --max-prompt-tokens 3768 --benchmark-csv benchmark_serving.csv --backend:服务类型,如tgi,vllm,mindspore,openai。 --host ${docker_ip}:服务部署的IP地址,${docker_ip}替换为宿主机实际的IP地址。 --port:推理服务端口。 --dataset:数据集路径。 --dataset-type:支持三种 "alpaca","sharegpt","custom"。custom为自定义数据集。 --tokenizer:tokenizer路径,可以是huggingface的权重路径。backend取值是openai时,tokenizer路径需要和推理服务启动时--model路径保持一致,比如--model /data/nfs/model/llama_7b, --tokenizer也需要为/data/nfs/model/llama_7b,两者要完全一致。 --request-rate:请求频率,支持多个,如 0.1 1 2。实际测试时,会根据request-rate为均值的指数分布来发送请求以模拟真实业务场景。 --num-prompts:某个频率下请求数,支持多个,如 10 100 100,数量需和--request-rate的数量对应。 --max-tokens:输入+输出限制的最大长度,模型启动参数--max-input-length值需要大于该值。 --max-prompt-tokens:输入限制的最大长度,推理时最大输入tokens数量,模型启动参数--max-total-tokens值需要大于该值,tokenizer建议带tokenizer.json的FastTokenizer。 --benchmark-csv:结果保存路径,如benchmark_serving.csv。 脚本运行完后,测试结果保存在benchmark_serving.csv中,示例如下图所示。 图2 动态benchmark测试结果(示意图)
  • 静态benchmark验证 本章节介绍如何进行静态benchmark验证。 已经上传benchmark验证脚本到推理容器中。如果在Step5 进入容器安装推理依赖软件步骤中已经上传过AscendCloud-LLM-x.x.x.zip并解压,无需重复执行。 进入benchmark_tools目录下,切换一个conda环境,执行如下命令安装性能测试的关依赖。 conda activate python-3.9.10 pip install -r requirements.txt 运行静态benchmark验证脚本benchmark_parallel.py,具体操作命令如下,可以根据参数说明修改参数。 cd benchmark_tools python benchmark_parallel.py --backend vllm --host ${docker_ip} --port 8080 --tokenizer /path/to/tokenizer --epochs 5 \ --parallel-num 1 4 8 16 32 --prompt-tokens 1024 2048 --output-tokens 128 256 --benchmark-csv benchmark_parallel.csv 参数说明 --backend:服务类型,支持tgi、vllm、mindspore、openai等。上面命令中使用vllm举例。 --host ${docker_ip}:服务部署的IP,${docker_ip}替换为宿主机实际的IP地址。 --port:推理服务端口8080。 --tokenizer:tokenizer路径,HuggingFace的权重路径。 --epochs:测试轮数,默认取值为5 --parallel-num:每轮并发数,支持多个,如 1 4 8 16 32。 --prompt-tokens:输入长度,支持多个,如 128 128 2048 2048,数量需和--output-tokens的数量对应。 --output-tokens:输出长度,支持多个,如 128 2048 128 2048,数量需和--prompt-tokens的数量对应。 --benchmark-csv:结果保存文件,如benchmark_parallel.csv。 脚本运行完成后,测试结果保存在benchmark_parallel.csv中,示例如下图所示。 图1 静态benchmark测试结果(示意图)
  • benchmark方法介绍 性能benchmark包括两部分。 静态性能测试:评估在固定输入、固定输出和固定并发下,模型的吞吐与首token延迟。该方式实现简单,能比较清楚的看出模型的性能和输入输出长度、以及并发的关系。 动态性能测试:评估在请求并发在一定范围内波动,且输入输出长度也在一定范围内变化时,模型的延迟和吞吐。该场景能模拟实际业务下动态的发送不同长度请求,能评估推理框架在实际业务中能支持的并发数。 性能benchmark验证使用到的脚本存放在代码包AscendCloud-LLM-xxx.zip的llm_tools/llm_evaluation目录下。 代码目录如下: benchmark_tools ├── benchmark_parallel.py # 评测静态性能脚本 ├── benchmark_serving.py # 评测动态性能脚本 ├── generate_dataset.py # 生成自定义数据集的脚本 ├── benchmark_utils.py # 工具函数集 ├── benchmark.py # 执行静态、动态性能评测脚本 ├── requirements.txt # 第三方依赖
  • Step1 在Notebook中修改训练超参配置 以llama2-13b SFT微调为例,执行脚本 0_pl_sft_13b.sh 。 修改模型训练脚本中的超参配置,必须修改的参数如表1所示。其他超参均有默认值,可以参考表1按照实际需求修改。 表1 必须修改的训练超参配置 参数 示例值 参数说明 ORIGINAL_TRAIN_DATA_PATH /home/ma-user/work/training_data/alpaca_gpt4_data.json 必须修改。训练时指定的输入数据路径。请根据实际规划修改。 ORIGINAL_HF_WEIGHT /home/ma-user/work/model/llama-2-13b-chat-hf 必须修改。加载tokenizer与Hugging Face权重时,对应的存放地址。请根据实际规划修改。 对于ChatGLMv3-6B和Qwen系列模型,还需要手动修改tokenizer文件,具体请参见训练tokenizer文件说明。
  • Step2 创建SFT全参微调训练任务 创建训练作业,并自定义名称、描述等信息。选择自定义算法,启动方式自定义,以及上传的镜像。训练脚本中会自动执行训练前的权重转换操作和数据处理操作。 图1 选择镜像 训练作业启动命令中输入: cd /home/ma-user/work/llm_train/AscendSpeed; sh ./scripts/install.sh; sh ./scripts/llama2/0_pl_sft_13b.sh
  • 步骤6:运行工作流 项目完成创建之后,会自动跳转到新版自动学习的运行总览页面。同时您的工作流会自动从数据标注节点开始运行。您需要做的是: 观察数据标注节点,待数据标注节点变为橙色即为“等待操作”状态。双击数据标注节点,打开数据标注节点的运行详情页面,单击“继续运行”。 在弹出的窗口中,单击“确定”,工作流会开始继续运行。当工作流运行到“服务部署”节点,状态会变为“等待输入”,您需要填写以下两个输入参数,其他参数保持默认。 计算节点规格:根据您的实际需求选择相应的规格,不同规格的配置费用不同,选择好规格后,配置费用处会显示相应的费用。 是否自动停止:为了避免资源浪费,建议您打开该开关,根据您的需求,选择自动停止时间,也可以自定义自动停止的时间。 图5 选择计算节点规格 图6 设置自动停止 参数填写完毕之后,单击运行状况右边的“继续运行”,单击确认弹窗中的“确定”即可继续完成工作流的运行。
  • 步骤1:准备工作 注册华为账号 并开通华为云、实名认证 注册华为账号并开通华为云 进行实名认证 配置委托访问授权 ModelArts使用过程中涉及到OBS、SWR、IEF等服务交互,首次使用ModelArts需要用户配置委托授权,允许访问这些依赖服务。 使用华为云账号登录ModelArts管理控制台,在左侧导航栏单击“全局配置”,进入“全局配置”页面,单击“添加授权”。 在弹出的“访问授权”窗口中,授权对象类型选“所有用户”,委托选择选“新增委托”,权限配置选择“普通用户”,并勾选“我已经详细阅读并同意《ModelArts服务声明》”,然后单击“创建”。 完成配置后,在ModelArts控制台的全局配置列表,可查看到此账号的委托配置信息。
  • 步骤2:创建OBS桶 登录OBS管理控制台,在桶列表页面右上角单击“创建桶”,创建OBS桶。例如,创建名称为“dataset-exeml”的OBS桶。 图1 创建桶 创建桶的区域需要与ModelArts所在的区域一致。例如:当前ModelArts在华北-北京四区域,在 对象存储服务 创建桶时,请选择华北-北京四。请参考查看OBS桶与ModelArts是否在同一区域检查您的OBS桶区域与ModelArts区域是否一致。 请勿开启桶加密,ModelArts不支持加密的OBS桶,会导致ModelArts读取OBS中的数据失败。 在桶列表页面,单击桶名称,进入该桶的概览页面。 图2 桶列表 单击左侧导航的“对象”,在对象页面单击“新建文件夹”,创建OBS文件夹。具体请参见新建文件夹章节。 图3 新建文件夹
  • 步骤5:创建新版自动学习图像分类项目 确保数据集创建完成且可正常使用后,在ModelArts控制台,左侧导航栏选择“自动学习”,进入自动学习总览页面。 单击选择“图像分类”创建项目。完成参数填写。 计费模式:按需计费。 名称:自定义您的项目名称。 描述:自定义描述您的项目详情,例如垃圾分类。 数据集:下拉选择已下载的数据集(步骤2中已成功导入的数据集,默认为下拉数据集列表中的第一个数据集)。 输出路径:选择您步骤1创建好的OBS文件夹下的路径,用来存储训练模型等相关文件。 训练规格:根据您的实际需要选择对应的训练规格。 参数填写完成,单击“创建项目”。
  • 步骤3:准备训练数据集 单击8类常见生活垃圾图片数据集,进入AI Gallery数据集详情页,单击右侧“下载”。 选择对应的云服务区域例如:华北-北京四,需要确保您选择的区域与您的管理控制台所在的区域一致。 进入“下载详情”页面,填写以下参数。 下载方式:ModelArts数据集。 目标区域:华北-北京四。 数据类型:系统会根据您的数据集,匹配到相应的数据类型。例如本案例使用的数据集,系统匹配为“图片”类型。 数据集输入位置:用来存放源数据集信息,例如本案例中从Gallery下载的数据集。单击图标选择您的OBS桶下的任意一处目录,但不能与输出位置为同一目录。 数据集输出位置:用来存放输出的数据标注的相关信息,或版本发布生成的Manifest文件等。单击图标选择OBS桶下的空目录,且此目录不能与输入位置一致,也不能为输入位置的子目录。 图4 下载详情 完成参数填写,单击“确定”,自动跳转至AI Gallery个人中心“我的下载”页签,单击按钮,查看下载进度,等待5分钟左右下载完成,单击展开下载详情,可以查看该数据集的“目标位置”。
  • 自动诊断工具MA-Advisor简介 MA-Advisor是一款昇腾迁移性能问题自动诊断工具,当前支持如下场景的自动诊断: 推理场景下的子图数据调优分析,给出对应融合算子的调优建议。 推理、训练场景下对Profiling timeline单卡数据进行调优分析,给出相关亲和API替换的调优建议。 推理、训练场景下对Profiling单卡数据进行调优分析,给出AICPU相关调优建议。 推理、训练场景下对Profiling单卡数据进行调优分析,给出block dim、operator no bound相关AOE配置以及调优建议。 支持对昇腾训练、推理环境进行预检,完成相关依赖配置项的提前检查,并在检测出问题时给出相关修复建议。 自动诊断工具可以有效减少人工分析profiling的耗时,降低性能调优的门槛,帮助客户快速识别性能瓶颈点并完成性能优化。推荐用户在采集profiling分析后使用自动诊断工具进行初步性能调优。更进一步的性能调优再使用Ascend-Insight工具进行 数据可视化 并人工分析瓶颈点。 父主题: 自动诊断工具MA-Advisor使用指导
  • 多卡分布式执行 PyTorch框架下常见的多卡分布式执行主要包括DataParallel(DP) 和Distributed Data Parallel (DDP)。torch_npu环境下针对DDP场景的多卡训练有提供支持,具体请参见迁移单卡脚本为多卡脚本。此外,针对deepspeed环境,昇腾有专门的适配环境deepspeed-npu。在此提供一种基于deepspeed的多卡训练脚本,内容如下: # ds_run_npu.sh LR=1e-4 TRAIN_FILE=${HOME}/YeungNLPfirefly-train-1.1M/firefly-train-1.1M.jsonl PER_DEVICE_TRAIN_BATCH_SIZE=4 GRADIENT_ACCUMULATION_STEPS=32 MODEL_DIR=${HOME}/chatglm OUTPUT_DIR=${HOME}/ChatGLM-6B-main/ptuning/output DS_CONFIG=${HOME}/ChatGLM-6B-main/ptuning/ds_config.json APP_SCRIPT=${HOME}/ChatGLM-6B-main/ptuning/main.py MASTER_PORT=$(shuf -n 1 -i 10000-65535) deepspeed --num_gpus=8 --master_port $MASTER_PORT ${APP_SCRIPT} \ --deepspeed ${DS_CONFIG} \ --log_level debug \ --model_name_or_path ${MODEL_DIR} \ --train_file ${TRAIN_FILE} \ --prompt_column input \ --response_column target \ --max_source_length 512 \ --max_target_length 512 \ --output_dir ${OUTPUT_DIR}/chatglm-6b-${LR} \ --per_device_train_batch_size ${PER_DEVICE_TRAIN_BATCH_SIZE} \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps ${GRADIENT_ACCUMULATION_STEPS} \ --gradient_checkpointing False \ --num_train_epochs 1 \ --predict_with_generate \ --logging_steps 10 \ --save_strategy "steps" \ --save_total_limit 3 \ --learning_rate $LR \ --dataloader_num_workers 60 \ --preprocessing_num_workers 60 \ --do_train \ --overwrite_output_dir \ --max_steps 100 \ --fp16 LR、PER_DEVICE_TRAIN_BATCH_SIZE、GRADIENT_ACCUMULATION_STEPS分别代表学习率、单个设备训练批次大小、梯度累计步数,作为超参数可以调优获得较好模型。同样,${HOME} 需要根据数据集模型等路径做对应替换,这里脚本适配的数据集是Firefly,其中deepspeed使用了zero 1显存优化方式,配置方式如下: { "fp16": { "enabled": "auto", "loss_scale": 0, "loss_scale_window": 1000, "initial_scale_power": 16, "hysteresis": 2, "min_loss_scale": 1 }, "bf16": { "enabled": "auto" }, "optimizer": { "type": "AdamW", "params": { "lr": "auto", "betas": "auto", "eps": "auto", "weight_decay": "auto" } }, "scheduler": { "type": "WarmupLR", "params": { "warmup_min_lr": "auto", "warmup_max_lr": "auto", "warmup_num_steps": "auto" } }, "zero_optimization": { "stage": 1, "offload_optimizer": { "device": "cpu", "pin_memory": true }, "contiguous_gradients": true, "overlap_comm": true, "allgather_partitions": true, "reduce_scatter": true, "allgather_bucket_size": 2e8, "reduce_bucket_size": 4e8 }, "flops_profiler":{ "enabled": true, "profile_step": 1, "module_path": -1, "top_modules": 1, "detailed": false, "output_file": null }, "zero_allow_untested_optimizer": "true", "gradient_clipping": "auto", "gradient_accumulation_steps": "auto", "train_batch_size": "auto", "train_micro_batch_size_per_gpu": "auto", "wall_clock_breakdown": false }
  • 自动迁移适配 修改“ptuning/main.py”,添加deepspeed_npu、torch_npu、transfer_to_npu依赖库,如下图所示。 # 导入deepspeed_npu和torch_npu import deepspeed_npu import torch_npu # 导入一键迁移接口 from torch_npu.contrib import transfer_to_npu 图1 自动迁移适配
  • 单卡方式训练 单卡执行脚本如下: # ptuning/run_npu_1d.sh export ASCEND_RT_VISIBLE_DEVI CES =0 # 指定 0 号卡对当前进程可见 PRE_SEQ_LEN=128 LR=2e-2 python3 ptuning/main.py \ --do_train \ --train_file ${HOME}/AdvertiseGen/train.json \ --validation_file ${HOME}/AdvertiseGen/dev.json \ --prompt_column content \ --response_column summary \ --overwrite_cache \ --model_name_or_path ${HOME}/chatglm \ --output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \ --overwrite_output_dir \ --max_source_length 64 \ --max_target_length 64 \ --per_device_train_batch_size 4 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 1 \ --predict_with_generate \ --max_steps 3000 \ --logging_steps 10 \ --save_steps 1000 \ --learning_rate $LR \ --pre_seq_len $PRE_SEQ_LEN \ --local_rank -1 通过设定ASCEND_RT_VISIBLE_DEVICES环境变量为0,控制0号卡对当前进程可见,PRE_SEQ_LEN和LR分别是soft prompt长度和训练的学习率,可以进行调节以取得最佳的效果。此外,这里去掉了int 4量化默认为FP16精度。${HOME} 目录需要根据读者实际数据集及模型路径匹配,适配的数据集是ADGEN数据集,如果需要读者也可以使用自定义的数据集训练,具体请参考使用自己数据集。另外通过指定local_rank为-1为单卡模式,多卡模式下无需指定,会默认启动DistributedDataParallel(DDP) 多卡并行模式,具体详情见常见问题1。GPU环境单卡执行同样需要指定local_rank为 -1。
  • 克隆 MRS 集群作业 本章节介绍如何克隆作业列表中的作业。 用户每次只能克隆1个作业,单击克隆后的作业信息不再区分显示运行程序参数和执行程序参数,而是合并显示为命令参考。 DistCp、SQL类(SparkSQL、HiveSQL等)作业类型无法克隆。 该功能暂时仅在北京四region开放,如需体验,请联系运维人员。 登录MRS管理控制台。 选择“现有集群”,选中一个运行中的集群并单击集群名称,进入集群信息页面。 选择“作业管理”。 在需要克隆作业的对应的“操作”列中,单击“克隆”,弹出“克隆作业”对话框。 配置克隆参数。 若无参数修改,无需执行本步骤。 若有参数修改,根据实际情况填写参数,单击“确定”下发克隆作业。 命令参考(由添加作业时的“运行程序参数”与“执行程序参数”组成):在原有的命令后,按“, {新参数}”的格式继续新增参数。 增加新的运行程序参数:新的命令参考是“运行程序参数, {新的运行程序参数}, 执行程序参数”。 增加新的执行程序参数:新的命令参考是“运行程序参数, 执行程序参数, {新的执行程序参数}”。 比如原有的命令参考为: -D, 10, -F, 12, abc ,增加新的运行程序参数时,则新的命令参考为:-D, 10, -F, 12, -G, 18, abc;增加新的执行程序参数时,则新的命令参考为:-D, 10, -F, 12, abc, efg。用户根据实际需求按照该规则(, 新参数)追加新的参数。 服务配置参数:在原有的参数后,按“, {key}={value}”的格式添加新的服务配置参数。比如原有参数为appender.out.strategy.max=10,则新的服务参数为:appender.out.strategy.max=10, appender.err.strategy.max=15。用户根据实际需求按照该规则(, {key}={value})追加新的参数。 克隆作业时,逗号+空格的格式只能在两个参数间存在;若存在于参数中,作业可能执行失败。 在原有参数后继续添加参数,逗号后需要有空格,否则作业可能执行失败。 克隆的作业返回参数不含有fs.obs.access.key、fs.obs.secret.key,若需要fs.obs.access.key、fs.obs.secret.key,需在“服务配置参数”中添加。 单击“确定”下发克隆作业。 作业克隆成功后,作业状态为“已完成”状态。 父主题: 管理MRS集群作业
共100000条