AIGlasses OS Pro 自动化实践:利用Python脚本实现模型批量测试与报告生成

张开发
2026/4/4 8:50:56 15 分钟阅读
AIGlasses OS Pro 自动化实践:利用Python脚本实现模型批量测试与报告生成
AIGlasses OS Pro 自动化实践利用Python脚本实现模型批量测试与报告生成每次模型迭代你是不是也经历过这样的场景手里有一堆新版本的模型还有好几个不同的测试数据集要一个个手动跑测试、记录结果、画图对比整个过程繁琐又容易出错。特别是当测试图片有成百上千张时手动操作几乎成了不可能完成的任务。对于需要频繁评估模型性能的团队来说这种重复劳动不仅消耗大量时间还难以保证评估过程的一致性和客观性。不同人操作可能得出不同的结论手动记录也容易产生疏漏。这篇文章我就来分享一个我们团队内部一直在用的“自动化测试流水线”方案。核心思路很简单用Python写个脚本让它自动完成从调用模型推理、收集指标到生成可视化报告的全过程。这样一来每次模型有更新或者想在新数据集上试试效果只需要运行一下脚本喝杯咖啡的功夫一份详细的测试报告就摆在眼前了。下面我就手把手带你搭建这套系统。1. 为什么你需要自动化测试流水线在深入代码之前我们先聊聊为什么这件事值得做。你可能觉得手动测试虽然慢点但也能接受。然而当评估工作变成常态它的弊端就会非常明显。首先效率是最大的瓶颈。假设你有5个模型版本需要在3个数据集上测试每个数据集有500张图片。手动操作意味着你要重复调用接口、记录结果、整理数据至少7500次。这还不包括画图分析的时间。而自动化脚本可以把这些重复劳动压缩到几分钟内。其次人为误差难以避免。手动记录准确率、召回率或者从日志里提取推理时间很容易看错行、记错数。一旦某个环节的数据出错整个评估结论就可能跑偏。自动化脚本能确保每次执行的数据采集逻辑完全一致结果可复现。再者报告标准化和存档。团队协作时大家需要基于同一份格式清晰、内容完整的报告来讨论。自动化生成的报告无论是图表样式还是指标计算方式都是统一的方便横向对比不同模型的性能也便于将历史测试结果归档追踪模型的迭代轨迹。最后它解放了工程师的创造力。把时间从繁琐的重复操作中节省出来你可以更专注于分析报告背后的原因思考如何优化模型而不是被困在执行的细节里。2. 搭建你的自动化测试工具箱要实现自动化我们需要几个核心工具。别担心都是Python生态里非常常见和易用的库。核心武器Python脚本整个流水线的“大脑”。我们将用它来组织所有流程读取图片、调用API、计算指标、生成报告。与模型对话Requests库我们的模型部署在AIGlasses OS Pro上通常会提供HTTP API接口。requests库是Python中处理HTTP请求的瑞士军刀用它来发送图片数据并接收模型的推理结果非常简单。处理数据Pandas NumPy模型返回的原始数据比如分类标签、置信度、检测框坐标需要被整理和分析。pandas的DataFrame是处理表格数据的利器方便我们进行筛选、分组和统计。numpy则为数值计算提供基础支持。让数据说话Matplotlib Seaborn这是生成可视化报告的关键。matplotlib是绘图的基础库功能强大。seaborn基于matplotlib提供了更美观的统计图形样式和高级接口绘制PR曲线、混淆矩阵热力图、箱线图等非常方便。管理项目目录结构一个清晰的目录结构能让脚本更健壮管理测试资源也更轻松。我建议这样组织project_root/ ├── test_automation.py # 主脚本 ├── config.yaml # 配置文件API地址、模型参数等 ├── test_images/ # 存放所有测试图片 │ ├── dataset_a/ │ ├── dataset_b/ │ └── ... ├── results/ # 输出目录 │ ├── 20240515_test/ # 按时间或版本命名的结果文件夹 │ │ ├── raw_results.csv # 原始推理数据 │ │ ├── summary_report.html │ │ └── figures/ # 存放所有生成的图表 │ └── ... └── requirements.txt # 项目依赖把所有路径和配置参数如API的URL、模型ID写死在代码里是坏习惯。用一个config.yaml文件来管理它们未来要修改测试模型或更换数据集时只需改配置文件不用动代码。3. 编写核心自动化脚本接下来我们看看脚本具体怎么写。我会把关键代码拆解出来并解释每一步在做什么。你可以根据自己的模型输出格式稍作调整。3.1 第一步读取配置与准备数据脚本开始先加载配置并准备好待测试的图片列表。import os import yaml import pandas as pd from glob import glob # 1. 加载配置文件 with open(config.yaml, r) as f: config yaml.safe_load(f) api_url config[api][url] model_id config[api][model_id] test_image_root config[paths][test_image_root] output_dir config[paths][output_dir] # 按日期创建本次测试的结果文件夹 import datetime current_time datetime.datetime.now().strftime(%Y%m%d_%H%M%S) result_dir os.path.join(output_dir, ftest_{current_time}) os.makedirs(result_dir, exist_okTrue) os.makedirs(os.path.join(result_dir, figures), exist_okTrue) # 2. 遍历测试图片目录构建文件列表 # 假设test_images下每个子文件夹是一个数据集 datasets {} for dataset_name in os.listdir(test_image_root): dataset_path os.path.join(test_image_root, dataset_name) if os.path.isdir(dataset_path): image_files glob(os.path.join(dataset_path, *.jpg)) \ glob(os.path.join(dataset_path, *.png)) \ glob(os.path.join(dataset_path, *.jpeg)) if image_files: datasets[dataset_name] image_files print(f数据集 {dataset_name} 中找到 {len(image_files)} 张图片。) if not datasets: print(未在测试目录中找到任何图片请检查路径。) exit()3.2 第二步调用API进行批量推理这是核心环节。我们遍历所有图片调用模型API并把结果保存下来。这里以图像分类任务为例如果是检测或分割任务需要调整结果解析逻辑。import requests import json import time def call_model_api(image_path, api_url, model_id): 调用AIGlasses OS Pro模型API进行推理 with open(image_path, rb) as img_file: files {image: img_file} data {model_id: model_id} try: # 记录开始时间用于计算推理耗时 start_time time.time() response requests.post(api_url, filesfiles, datadata, timeout30) inference_time time.time() - start_time if response.status_code 200: result response.json() # 假设API返回格式为 {success: True, data: {class: cat, confidence: 0.95}} if result.get(success): return { status: success, prediction: result[data].get(class), confidence: result[data].get(confidence, 0), inference_time: inference_time, raw_response: result } else: return {status: api_error, message: result.get(message)} else: return {status: http_error, code: response.status_code} except Exception as e: return {status: exception, error: str(e)} # 3. 遍历所有数据集和图片收集结果 all_results [] for dataset_name, image_list in datasets.items(): print(f\n正在处理数据集: {dataset_name}) for idx, img_path in enumerate(image_list): print(f 处理中: {idx1}/{len(image_list)} - {os.path.basename(img_path)}, end\r) result call_model_api(img_path, api_url, model_id) result_record { dataset: dataset_name, image_file: os.path.basename(img_path), image_path: img_path, status: result[status] } if result[status] success: result_record.update({ predicted_class: result[prediction], confidence: result[confidence], inference_time_ms: round(result[inference_time] * 1000, 2) # 转为毫秒 }) # 这里需要你根据实际情况获取或标注真实标签ground truth # 例如可以从文件名或单独的标注文件中读取 result_record[true_class] extract_true_label(img_path) else: result_record[error_info] json.dumps(result) all_results.append(result_record) print() # 换行 # 4. 将原始结果保存为CSV方便后续核查 results_df pd.DataFrame(all_results) raw_results_path os.path.join(result_dir, raw_results.csv) results_df.to_csv(raw_results_path, indexFalse) print(f\n原始推理结果已保存至: {raw_results_path})3.3 第三步计算评估指标与生成报告有了原始数据我们就可以计算各项指标了。这里以分类任务为例展示如何计算准确率、召回率、F1分数并生成混淆矩阵和PR曲线。import matplotlib.pyplot as plt import seaborn as sns from sklearn.metrics import classification_report, confusion_matrix, precision_recall_curve, average_precision_score import numpy as np # 只分析成功推理且具有真实标签的数据 analysis_df results_df[(results_df[status]success) (results_df[true_class].notna())] if analysis_df.empty: print(没有足够的数据进行指标计算请检查数据标签。) else: # 准备数据 y_true analysis_df[true_class].tolist() y_pred analysis_df[predicted_class].tolist() classes sorted(list(set(y_true) | set(y_pred))) # 所有出现过的类别 # 5. 生成文本分类报告 print(\n *50) print(分类评估报告) print(*50) report_dict classification_report(y_true, y_pred, target_namesclasses, output_dictTrue) print(classification_report(y_true, y_pred, target_namesclasses)) # 将报告保存为DataFrame report_df pd.DataFrame(report_dict).transpose() report_df.to_csv(os.path.join(result_dir, classification_report.csv)) # 6. 绘制混淆矩阵热力图 plt.figure(figsize(10, 8)) cm confusion_matrix(y_true, y_pred, labelsclasses) cm_normalized cm.astype(float) / cm.sum(axis1)[:, np.newaxis] # 归一化 sns.heatmap(cm_normalized, annotTrue, fmt.2f, cmapBlues, xticklabelsclasses, yticklabelsclasses) plt.title(混淆矩阵 (归一化)) plt.ylabel(真实标签) plt.xlabel(预测标签) plt.tight_layout() cm_path os.path.join(result_dir, figures, confusion_matrix.png) plt.savefig(cm_path, dpi300) plt.close() print(f混淆矩阵已保存至: {cm_path}) # 7. 绘制PR曲线以二分类或多分类的宏观平均为例 # 注意这里需要模型的预测置信度来绘制PR曲线。我们简化处理展示宏观平均PR曲线。 # 对于多分类可以计算每个类别的one-vs-rest的PR曲线然后取平均。 from sklearn.preprocessing import label_binarize from sklearn.metrics import precision_recall_curve # 将标签二值化适用于多分类绘制宏观PR曲线 y_true_bin label_binarize(y_true, classesclasses) # 这里需要一个置信度矩阵我们简化用预测类别模拟。实际中应从模型获取每个类别的置信度。 # y_score ... # 应该是 shape (n_samples, n_classes) 的置信度矩阵 # 由于示例中未保存每个类别的置信度此处跳过详细PR曲线绘制。 # 实际应用中如果你的API返回每个类别的概率可以在这里计算并绘制。 # 8. 统计推理时间 time_stats analysis_df[inference_time_ms].describe() print(f\n推理时间统计 (毫秒):\n{time_stats}) # 绘制推理时间分布直方图 plt.figure(figsize(10, 6)) plt.hist(analysis_df[inference_time_ms], bins30, edgecolorblack, alpha0.7) plt.axvline(analysis_df[inference_time_ms].mean(), colorred, linestyledashed, linewidth2, labelf均值: {analysis_df[inference_time_ms].mean():.2f} ms) plt.xlabel(推理时间 (毫秒)) plt.ylabel(频数) plt.title(推理时间分布) plt.legend() plt.grid(True, alpha0.3) time_hist_path os.path.join(result_dir, figures, inference_time_dist.png) plt.savefig(time_hist_path, dpi300) plt.close() print(f推理时间分布图已保存至: {time_hist_path}) # 9. 生成HTML摘要报告 html_report f !DOCTYPE html html head title模型测试报告 - {current_time}/title style body {{ font-family: Arial, sans-serif; margin: 40px; }} h1 {{ color: #333; }} .section {{ margin-bottom: 30px; }} img {{ max-width: 100%; border: 1px solid #ddd; margin: 10px 0; }} table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }} th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }} th {{ background-color: #f2f2f2; }} /style /head body h1模型自动化测试报告/h1 pstrong测试时间:/strong {current_time}/p pstrong测试模型:/strong {model_id}/p pstrong总测试图片数:/strong {len(results_df)}/p pstrong成功推理数:/strong {len(analysis_df)}/p div classsection h21. 关键指标摘要/h2 pstrong平均准确率 (宏平均):/strong {report_dict[macro avg][precision]:.3f}/p pstrong平均召回率 (宏平均):/strong {report_dict[macro avg][recall]:.3f}/p pstrong平均F1分数 (宏平均):/strong {report_dict[macro avg][f1-score]:.3f}/p pstrong平均推理时间:/strong {analysis_df[inference_time_ms].mean():.2f} ms/p /div div classsection h22. 混淆矩阵/h2 img srcfigures/confusion_matrix.png alt混淆矩阵热力图 /div div classsection h23. 推理时间分布/h2 img srcfigures/inference_time_dist.png alt推理时间分布直方图 p详细统计: 均值{time_stats[mean]:.2f} ms, 标准差{time_stats[std]:.2f} ms, 最小值{time_stats[min]:.2f} ms, 最大值{time_stats[max]:.2f} ms/p /div div classsection h24. 详细分类报告 (前5行)/h2 {report_df.head().to_html()} pa hrefclassification_report.csv下载完整分类报告CSV/a/p /div div classsection h25. 原始数据/h2 pa hrefraw_results.csv下载原始推理结果CSV/a/p /div /body /html html_report_path os.path.join(result_dir, summary_report.html) with open(html_report_path, w, encodingutf-8) as f: f.write(html_report) print(f\nHTML摘要报告已生成: {html_report_path}) print(f所有结果文件保存在: {result_dir})4. 让流水线更智能一些进阶思路基础的流水线搭建好后你可以根据团队需求让它变得更强大、更智能。支持多种任务类型上面的例子主要针对图像分类。如果你的模型是做目标检测的那么评估指标就要换成mAP平均精度均值、IoU交并比报告里可以增加检测框的可视化样例。如果是分割任务则需要计算mIoU平均交并比等。脚本的核心框架不变只需要替换指标计算和可视化部分。集成到CI/CD流程对于追求高效迭代的团队可以把这套脚本集成到持续集成/持续部署CI/CD流水线中。比如每当有新的模型镜像被构建出来自动触发测试脚本在标准数据集上跑一遍如果关键指标如准确率低于阈值则自动阻止部署并通知开发人员。加入对比分析功能在results目录下保存每次测试的报告和数据。可以写一个额外的分析脚本读取多次测试的结果自动生成模型性能随时间变化的趋势图比如准确率曲线、推理时间下降图直观展示模型迭代的收益。错误处理与重试机制网络请求可能失败API可能暂时不可用。在生产环境中需要在call_model_api函数里加入更健壮的错误处理和重试逻辑例如使用retrying库并记录详细的错误日志方便排查问题。5. 总结回过头来看搭建这样一个自动化测试流水线初期确实需要投入一些时间编写和调试脚本。但一旦它运行起来所带来的长期收益是非常可观的。它把我们从重复、易错的手工操作中解放出来保证了评估过程的标准化和高效化让模型迭代的决策更加依赖于客观、一致的数据。你可以从本文提供的代码框架开始先跑通一个最简单的分类任务测试。然后再根据你的实际模型检测、分割等和业务需求逐步丰富指标计算和报告内容。最重要的是开始动手做哪怕先从自动化一个最小的测试集开始。当你第一次看到脚本自动运行并生成出那份完整的报告时你就会明白这种效率提升带来的快乐了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

更多文章