目前想要对SFT微调后的模型进行测试,看官方文档ms-swift中有eval的教程,但是从介绍来看,eval使用的是modelscope的评测内容。
评测
SWIFT支持了eval(评测)能力,用于对原始模型和训练后的模型给出标准化的评测指标。
能力介绍
SWIFT的eval能力使用了魔搭社区评测框架EvalScope,并进行了高级封装以支持各类模型的评测需求。
注意:EvalScope支持许多其他的复杂能力,例如模型的性能评测,请直接使用EvalScope框架。
目前我们支持了标准评测集 的评测流程,以及用户自定义 评测集的评测流程。其中标准评测集由三个评测后端提供支持:
下面展示所支持的数据集名称,若需了解数据集的详细信息,请参考所有支持的数据集
可以从上述内容中看到,评估起来比较麻烦,而且针对用户自定义的测评集,需要自己重新生成csv(选择题)或者jsonl(问答题)
问答题格式(QA)
适合用户是问答题的场景,评测指标是ROUGE
和BLEU
。
数据准备
准备一个问答题格式的jsonline文件,该目录包含了一个文件:
qa/
└── example.jsonl
该jsonline文件需要为下面的格式:
{"query": "中国的首都是哪里?", "response": "中国的首都是北京"}
{"query": "世界上最高的山是哪座山?", "response": "是珠穆朗玛峰"}
{"query": "为什么北极见不到企鹅?", "response": "因为企鹅大多生活在南极"}
启动评测
运行下面的命令:
CUDA_VISIBLE_DEVICES=0 \
swift eval \
--model Qwen/Qwen2.5-0.5B-Instruct \
--eval_backend Native \
--infer_backend pt \
--eval_dataset general_qa \
--dataset_args '{"general_qa": {"local_path": "/path/to/qa", "subset_list": ["example"]}}'
其中:
-
eval_dataset
需要设置为general_qa
-
dataset_args
是一个json字符串,需要设置:-
local_path
自定义数据集文件夹路径 -
subset_list
评测数据集名称,上述*.jsonl
中的*
-
总体上来说,评估起来比较麻烦,如果我们想要使用代码完成推理并且输出至某个文件中,可以使用swift库来实现,目前使用的swift版本为3.4.0,推理代码目前是封装的比较好的,下述的代码实现了流式推理。即可以从评测数据集中完成 先加载模型,后使用数据集中的单条数据进行推理,推理后可存储至指定文件中。
python
import os
from typing import List, Literal
from swift.llm import InferEngine, InferRequest, PtEngine, RequestConfig, load_dataset
from swift.plugin import InferStats
from PIL import Image # 处理图像输入(可选,根据模型要求)
os.environ['ASCEND_RT_VISIBLE_DEVICES'] = '0'
def infer_stream(engine: 'InferEngine', infer_request: 'InferRequest'):
"""流式推理函数(Pt后端)"""
request_config = RequestConfig(max_tokens=1024, temperature=1, stream=True)
metric = InferStats()
gen_list = engine.infer([infer_request], request_config, metrics=[metric])
return gen_list
query = infer_request.messages[0]['content']
#print(f"流式推理 - 查询: {query}\n响应: ", end='')
# for resp in gen_list[0]:
# if resp and resp.choices:
# print(resp.choices[0].delta.content, end='', flush=True)
# #print(f"\n性能指标: {metric.compute()}\n")
return result
# 获取推理结果
def build_image_message(image_path: str, query: str):
"""构建图像+文本输入消息(Pt后端兼容格式)"""
return {
'role': 'user',
'content': [
{'type': 'image', 'image': image_path}, # 支持本地路径/URL/Base64/PIL.Image
{'type': 'text', 'text': query}
]
}
infer_backend = 'pt' # 使用Pt后端
model = 'internvloutput/v3-20250507-190220/checkpoint-300-merged' # Qwen2-VL模型(可替换为本地路径)
image_url = "demo.jpg" # 示例图像URL
# ====================== 初始化Pt推理引擎 ======================
engine = PtEngine(
model_id_or_path=model,
max_batch_size=1, # 根据GPU显存调整(34B模型建议设为1-2)
device_map='auto' # 自动分配设备(支持多卡,但需确保模型支持)
)
with open('./test-2.jsonl', 'r', encoding='utf-8') as infile:
total_lines = sum(1 for _ in infile)
# 打开输入的txt文件和输出的log文件#../wsu-data/test/txt/PATH_DT_WSU_split_test_labels.txt
#../lung_colon_image_set/test-more.jsonl
with open('./test-2.jsonl', 'r', encoding='utf-8') as infile, open('output-gas-05091.log', 'w', encoding='utf-8') as outfile:
# 逐行读取txt文件
# for line in infile:
for i, line in enumerate(infile, 1):
try:
# print(i)
# 导入ast模块,用于将字符串转换为Python对象
import ast
# 将每行字符串转换为Python字典
data = ast.literal_eval(line.strip())
# 提取messages列表
messages = data.get('messages', [])
# 提取images列表
images = data.get('images', [])
content_count=0
# 遍历messages列表,提取每个message的content内容
for message in messages:
content = message.get('content', '')
if content_count == 0:
question=content
# print(question)
# 将content内容写入log文件
outfile.write(f"Content: {content}\n")
content_count=content_count+1
# 遍历images列表,提取每个image的路径
for image_path in images:
# 将image路径写入log文件
# image_path=image_path.replace('../images/', '../wsu-data/test/images/')
image_path=image_path.replace('gastric_image_set/', './gastric_image_set/')
# image_path=image_path.replace('wsu-data/', '../wsu-data/')
image1 = image_path
outfile.write(f"Image Path: {image_path}\n")
outfile.write("·" * 50 + "\n")
# conversation = [
# {
# "role": "User",
# "content": f"<image_placeholder>\n{question}",
# "images": [image1],
# },
# {"role": "Assistant", "content": ""},
# ]
# ====================== 构建推理请求 ======================
# 1. 单样本流式推理(图像+文本)
user_message = build_image_message(
image_path=image1,
query=question,
)
infer_request_stream = InferRequest(messages=[user_message])
gen_list = infer_stream(engine, infer_request_stream)
outfile.write("Answer:")
for resp in gen_list[0]:
if resp and resp.choices:
# print(resp.choices[0].delta.content, end='', flush=True)
outfile.write(resp.choices[0].delta.content)
outfile.write("\n")
# 每20行打印一次进度
if i % 20 == 0 or i == total_lines:
print(f"已处理 {i}/{total_lines} 行 ({i/total_lines:.1%})")
# 在每组数据之间添加分隔线
outfile.write("-" * 50 + "\n")
except (SyntaxError, ValueError):
# 处理转换过程中可能出现的语法错误或值错误
print(f"Error processing line: {line.strip()}")
上述代码即可实现swift的python 代码推理,从jsonl文件中读取测试数据,加载InternVL3进行推理,可直接修改代码中的数据集目录以及存储文件目录即可完成推理。
不足之处:尚未调试batch推理的代码,单条推理速度较低,下一步Todo :支持batch 推理