别再只画单模型曲线了!用Python+Matplotlib搞定YOLOv5全系列(n/s/m/l/x)模型对比可视化 YOLOv5全系列模型对比可视化从数据整合到出版级图表实战在目标检测和实例分割领域YOLOv5因其卓越的性能和灵活的架构选择成为研究热点。当我们完成n/s/m/l/x全系列模型的训练后如何将五个量级模型的训练过程指标和最终性能以专业、直观的方式呈现成为论文写作和工程汇报中的关键挑战。本文将分享一套完整的PythonMatplotlib解决方案帮助您从杂乱的结果文件中提炼出具有学术价值的对比图表。1. 数据预处理与多模型结果整合处理多模型结果的第一步是建立统一的数据结构。假设我们已经训练了YOLOv5n/YOLOv5s/YOLOv5m/YOLOv5l/YOLOv5x五个模型每个模型目录下都有标准的results.csv文件import pandas as pd import numpy as np from pathlib import Path # 定义模型类型和路径 model_types [n, s, m, l, x] results_files [Path(fyolov5{model_type}/results.csv) for model_type in model_types] # 创建统一的数据容器 metrics_data { train_loss: [], val_loss: [], mAP_0.5: [], mAP_0.5:0.95: [], precision: [], recall: [], f1: [] } # 读取并解析每个模型的结果 for model_type, file in zip(model_types, results_files): df pd.read_csv(file) metrics_data[train_loss].append(df[train/box_loss].values) metrics_data[val_loss].append(df[val/box_loss].values) metrics_data[mAP_0.5].append(df[metrics/mAP_0.5(B)].values) metrics_data[mAP_0.5:0.95].append(df[metrics/mAP_0.5:0.95(B)].values) metrics_data[precision].append(df[metrics/precision(B)].values) metrics_data[recall].append(df[metrics/recall(B)].values) metrics_data[f1].append(2 * (metrics_data[precision][-1] * metrics_data[recall][-1]) / (metrics_data[precision][-1] metrics_data[recall][-1] 1e-16))提示对于实例分割任务只需将(B)替换为(M)即可获取分割相关指标。实际应用中建议同时保留检测和分割指标形成更全面的对比。2. 专业级对比图表设计原则学术图表的核心是信息密度和可读性的平衡。以下是设计对比图表时的关键考量色彩系统为每个模型分配专属颜色保持全图表一致性线型区分实线代表训练指标虚线代表验证指标标注策略关键拐点和最终值需要明确标注比例协调y轴范围应根据数据动态调整避免过度压缩曲线特征import matplotlib.pyplot as plt from matplotlib.ticker import MaxNLocator # 设置全局样式 plt.style.use(seaborn) plt.rcParams.update({ font.family: Arial, font.size: 10, axes.titlesize: 12, axes.labelsize: 10, xtick.labelsize: 8, ytick.labelsize: 8, legend.fontsize: 9, figure.dpi: 300, savefig.dpi: 300, figure.figsize: (8, 6) }) # 定义模型颜色映射 model_colors { n: #1f77b4, # 蓝色 s: #ff7f0e, # 橙色 m: #2ca02c, # 绿色 l: #d62728, # 红色 x: #9467bd # 紫色 }3. 核心指标对比可视化实现3.1 训练过程对比Loss曲线Loss曲线是观察模型收敛情况的最直接窗口。多模型对比时需要特别关注收敛速度差异最终收敛位置过拟合迹象def plot_multi_model_loss(metrics_data, model_types, save_pathloss_comparison.png): fig, ax plt.subplots(1, 1, figsize(10, 6)) for i, model_type in enumerate(model_types): epochs np.arange(1, len(metrics_data[train_loss][i]) 1) ax.plot(epochs, metrics_data[train_loss][i], colormodel_colors[model_type], linewidth1.5, labelfYOLOv5{model_type} Train) ax.plot(epochs, metrics_data[val_loss][i], colormodel_colors[model_type], linestyle--, linewidth1.2, labelfYOLOv5{model_type} Val) ax.set_xlabel(Epoch, fontweightbold) ax.set_ylabel(Loss Value, fontweightbold) ax.set_title(Training Validation Loss Comparison Across YOLOv5 Models, pad15) ax.xaxis.set_major_locator(MaxNLocator(integerTrue)) ax.grid(True, alpha0.3) ax.legend(bbox_to_anchor(1.05, 1), locupper left) plt.tight_layout() plt.savefig(save_path, bbox_inchestight, dpi300) plt.close()3.2 性能指标对比mAP曲线mAP是目标检测的核心评估指标对比时需要展示不同IoU阈值下的表现模型间的相对性能差距训练过程中的稳定性def plot_multi_model_map(metrics_data, model_types, save_pathmap_comparison.png): fig, (ax1, ax2) plt.subplots(2, 1, figsize(10, 10), sharexTrue) # mAP0.5 for i, model_type in enumerate(model_types): epochs np.arange(1, len(metrics_data[mAP_0.5][i]) 1) ax1.plot(epochs, metrics_data[mAP_0.5][i], colormodel_colors[model_type], linewidth1.8, labelfYOLOv5{model_type}) # 标注最终值 last_val metrics_data[mAP_0.5][i][-1] ax1.annotate(f{last_val:.3f}, xy(epochs[-1], last_val), xytext(5, 0), textcoordsoffset points, colormodel_colors[model_type], fontsize8) ax1.set_ylabel(mAP0.5, fontweightbold) ax1.set_title(mAP0.5 Comparison Across YOLOv5 Models, pad10) ax1.grid(True, alpha0.3) ax1.legend() # mAP0.5:0.95 for i, model_type in enumerate(model_types): epochs np.arange(1, len(metrics_data[mAP_0.5:0.95][i]) 1) ax2.plot(epochs, metrics_data[mAP_0.5:0.95][i], colormodel_colors[model_type], linewidth1.8, labelfYOLOv5{model_type}) # 标注最终值 last_val metrics_data[mAP_0.5:0.95][i][-1] ax2.annotate(f{last_val:.3f}, xy(epochs[-1], last_val), xytext(5, 0), textcoordsoffset points, colormodel_colors[model_type], fontsize8) ax2.set_xlabel(Epoch, fontweightbold) ax2.set_ylabel(mAP0.5:0.95, fontweightbold) ax2.grid(True, alpha0.3) plt.tight_layout() plt.savefig(save_path, bbox_inchestight, dpi300) plt.close()4. 综合性能雷达图展示除了训练过程曲线我们还需要一种直观展示模型综合性能的方式。雷达图非常适合这种多维度对比def plot_radar_comparison(metrics_data, model_types, save_pathradar_comparison.png): # 准备雷达图数据 categories [Precision, Recall, F1, mAP0.5, mAP0.5:0.95] num_vars len(categories) # 计算每个模型的最终指标值 values [] for i in range(len(model_types)): model_values [ metrics_data[precision][i][-1], metrics_data[recall][i][-1], metrics_data[f1][i][-1], metrics_data[mAP_0.5][i][-1], metrics_data[mAP_0.5:0.95][i][-1] ] values.append(model_values) # 雷达图角度计算 angles np.linspace(0, 2 * np.pi, num_vars, endpointFalse).tolist() angles angles[:1] # 闭合图形 fig, ax plt.subplots(figsize(8, 8), subplot_kwdict(polarTrue)) # 绘制每个模型的数据 for i, model_type in enumerate(model_types): data values[i] data data[:1] # 闭合图形 ax.plot(angles, data, colormodel_colors[model_type], linewidth2, labelfYOLOv5{model_type}) ax.fill(angles, data, colormodel_colors[model_type], alpha0.1) # 设置坐标轴 ax.set_theta_offset(np.pi / 2) ax.set_theta_direction(-1) ax.set_rlabel_position(0) # 设置刻度标签 ax.set_xticks(angles[:-1]) ax.set_xticklabels(categories) ax.set_ylim(0, 1) # 添加标题和图例 plt.title(Comprehensive Performance Comparison, pad20) ax.legend(bbox_to_anchor(1.1, 1.1)) plt.tight_layout() plt.savefig(save_path, bbox_inchestight, dpi300) plt.close()5. 高级技巧动态性能-参数量分析对于学术论文展示模型性能与参数量/计算量的关系至关重要。我们可以从模型配置文件中提取参数量信息def plot_performance_vs_size(metrics_data, model_types, save_pathperformance_vs_size.png): # 假设我们已经获取了各模型的参数量(M) params { n: 1.9, s: 7.2, m: 21.2, l: 46.5, x: 86.7 } # 准备数据 x [params[mt] for mt in model_types] y_map50 [metrics_data[mAP_0.5][i][-1] for i in range(len(model_types))] y_map9595 [metrics_data[mAP_0.5:0.95][i][-1] for i in range(len(model_types))] fig, ax plt.subplots(figsize(8, 6)) # 绘制散点图 for i, model_type in enumerate(model_types): ax.scatter(x[i], y_map50[i], colormodel_colors[model_type], s150, labelfYOLOv5{model_type} mAP0.5, markero) ax.scatter(x[i], y_map9595[i], colormodel_colors[model_type], s150, labelfYOLOv5{model_type} mAP0.5:0.95, marker^) # 添加趋势线 z np.polyfit(x, y_map50, 1) p np.poly1d(z) ax.plot(x, p(x), --, colorgray, alpha0.5) z np.polyfit(x, y_map9595, 1) p np.poly1d(z) ax.plot(x, p(x), --, colorgray, alpha0.5) # 设置坐标轴和标签 ax.set_xlabel(Parameters (M), fontweightbold) ax.set_ylabel(mAP Value, fontweightbold) ax.set_title(Performance vs Model Size, pad15) ax.grid(True, alpha0.3) # 自定义图例 from matplotlib.lines import Line2D legend_elements [ Line2D([0], [0], markero, colorw, labelmAP0.5, markerfacecolorgray, markersize8), Line2D([0], [0], marker^, colorw, labelmAP0.5:0.95, markerfacecolorgray, markersize8) ] ax.legend(handleslegend_elements, loclower right) # 添加模型类型标注 for i, model_type in enumerate(model_types): ax.annotate(fv5{model_type}, (x[i], (y_map50[i] y_map9595[i])/2), textcoordsoffset points, xytext(0,10), hacenter, colormodel_colors[model_type]) plt.tight_layout() plt.savefig(save_path, bbox_inchestight, dpi300) plt.close()6. 出版级图表优化与导出学术图表需要满足出版质量要求我们最后进行专业优化def save_publication_quality(fig, filename, widthsingle): 保存出版级质量的图片 :param fig: matplotlib figure对象 :param filename: 保存文件名 :param width: single (8cm) 或 double (16cm) 栏宽 # 设置尺寸 (单位: cm) if width single: fig.set_size_inches(8/2.54, 6/2.54) # 8cm宽6cm高 else: fig.set_size_inches(16/2.54, 8/2.54) # 16cm宽8cm高 # 设置字体 plt.rcParams.update({ font.sans-serif: Arial, font.size: 8, axes.labelsize: 8, axes.titlesize: 9, xtick.labelsize: 7, ytick.labelsize: 7, legend.fontsize: 7, figure.titlesize: 9 }) # 调整边距 plt.tight_layout(pad0.5) # 保存为多种格式 fig.savefig(f{filename}.png, dpi600, bbox_inchestight) fig.savefig(f{filename}.pdf, bbox_inchestight, transparentTrue) fig.savefig(f{filename}.eps, formateps, bbox_inchestight) # 关闭图形 plt.close(fig)注意实际投稿前应查阅期刊/会议的图表格式要求包括字体大小、线宽、颜色模式(CMYK/RGB)等细节。多数期刊推荐使用矢量格式(如PDF/EPS)提交图表。