Files
Test_AI/visualize_batch_results.py
2026-01-20 11:14:10 +08:00

365 lines
12 KiB
Python

#!/usr/bin/env python3
"""
批次性能测试结果可视化
生成批次大小 vs 性能指标的对比图表
"""
import json
import matplotlib.pyplot as plt
import numpy as np
import os
from datetime import datetime
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
def load_results(json_file):
"""加载测试结果"""
with open(json_file, 'r', encoding='utf-8') as f:
return json.load(f)
def create_throughput_chart(results, output_dir):
"""创建吞吐量对比图表"""
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# 提取成功的测试数据
batch_sizes = []
throughputs = []
latencies = []
for test in results['batch_tests']:
if test['success']:
batch_sizes.append(test['batch_size'])
throughputs.append(test['avg_throughput'])
latencies.append(test['avg_latency_ms'])
if not batch_sizes:
print("⚠️ 没有成功的测试数据")
return
# 吞吐量图表
ax1.plot(batch_sizes, throughputs, 'o-', color='#4ECDC4',
linewidth=2, markersize=10, label='吞吐量')
ax1.set_title('批次大小 vs 吞吐量', fontsize=14, fontweight='bold')
ax1.set_xlabel('批次大小', fontsize=12)
ax1.set_ylabel('吞吐量 (FPS)', fontsize=12)
ax1.grid(True, alpha=0.3)
ax1.legend()
# 添加数值标签
for x, y in zip(batch_sizes, throughputs):
ax1.text(x, y + max(throughputs)*0.02, f'{y:.1f}',
ha='center', va='bottom', fontweight='bold')
# 找到最佳批次大小
best_idx = np.argmax(throughputs)
ax1.scatter([batch_sizes[best_idx]], [throughputs[best_idx]],
color='red', s=200, marker='*', zorder=5,
label=f'最佳: Batch {batch_sizes[best_idx]}')
ax1.legend()
# 延迟图表
ax2.plot(batch_sizes, latencies, 'o-', color='#FF6B6B',
linewidth=2, markersize=10, label='延迟')
ax2.set_title('批次大小 vs 延迟', fontsize=14, fontweight='bold')
ax2.set_xlabel('批次大小', fontsize=12)
ax2.set_ylabel('延迟 (ms)', fontsize=12)
ax2.grid(True, alpha=0.3)
ax2.legend()
# 添加数值标签
for x, y in zip(batch_sizes, latencies):
ax2.text(x, y + max(latencies)*0.02, f'{y:.1f}',
ha='center', va='bottom', fontweight='bold')
# 找到最低延迟
best_latency_idx = np.argmin(latencies)
ax2.scatter([batch_sizes[best_latency_idx]], [latencies[best_latency_idx]],
color='green', s=200, marker='*', zorder=5,
label=f'最低: Batch {batch_sizes[best_latency_idx]}')
ax2.legend()
plt.tight_layout()
plt.savefig(os.path.join(output_dir, 'batch_throughput_latency.png'),
dpi=300, bbox_inches='tight')
plt.show()
print(f"✅ 生成图表: batch_throughput_latency.png")
def create_gpu_utilization_chart(results, output_dir):
"""创建 GPU 利用率和内存使用图表"""
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# 提取数据
batch_sizes = []
gpu_utils = []
gpu_memories = []
for test in results['batch_tests']:
if test['success']:
batch_sizes.append(test['batch_size'])
gpu_utils.append(test['avg_gpu_util'])
gpu_memories.append(test['avg_gpu_memory_mb'])
if not batch_sizes:
return
# GPU 利用率图表
ax1.bar(batch_sizes, gpu_utils, color='#95E1D3', alpha=0.8, edgecolor='black')
ax1.set_title('批次大小 vs GPU 利用率', fontsize=14, fontweight='bold')
ax1.set_xlabel('批次大小', fontsize=12)
ax1.set_ylabel('GPU 利用率 (%)', fontsize=12)
ax1.grid(True, alpha=0.3, axis='y')
# 添加数值标签
for x, y in zip(batch_sizes, gpu_utils):
ax1.text(x, y + max(gpu_utils)*0.02, f'{y:.1f}%',
ha='center', va='bottom', fontweight='bold')
# GPU 内存使用图表
ax2.bar(batch_sizes, gpu_memories, color='#F38181', alpha=0.8, edgecolor='black')
ax2.set_title('批次大小 vs GPU 内存使用', fontsize=14, fontweight='bold')
ax2.set_xlabel('批次大小', fontsize=12)
ax2.set_ylabel('GPU 内存 (MB)', fontsize=12)
ax2.grid(True, alpha=0.3, axis='y')
# 添加数值标签
for x, y in zip(batch_sizes, gpu_memories):
ax2.text(x, y + max(gpu_memories)*0.02, f'{y:.0f}',
ha='center', va='bottom', fontweight='bold')
plt.tight_layout()
plt.savefig(os.path.join(output_dir, 'batch_gpu_metrics.png'),
dpi=300, bbox_inches='tight')
plt.show()
print(f"✅ 生成图表: batch_gpu_metrics.png")
def create_efficiency_chart(results, output_dir):
"""创建效率分析图表"""
fig, ax = plt.subplots(1, 1, figsize=(10, 6))
# 提取数据
batch_sizes = []
efficiencies = [] # FPS per GPU utilization
for test in results['batch_tests']:
if test['success'] and test['avg_gpu_util'] > 0:
batch_sizes.append(test['batch_size'])
efficiency = test['avg_throughput'] / test['avg_gpu_util']
efficiencies.append(efficiency)
if not batch_sizes:
return
# 效率图表
ax.plot(batch_sizes, efficiencies, 'o-', color='#AA96DA',
linewidth=2, markersize=10, label='效率 (FPS/GPU%)')
ax.set_title('批次大小 vs 性能效率', fontsize=14, fontweight='bold')
ax.set_xlabel('批次大小', fontsize=12)
ax.set_ylabel('效率 (FPS / GPU利用率%)', fontsize=12)
ax.grid(True, alpha=0.3)
ax.legend()
# 添加数值标签
for x, y in zip(batch_sizes, efficiencies):
ax.text(x, y + max(efficiencies)*0.02, f'{y:.2f}',
ha='center', va='bottom', fontweight='bold')
# 找到最高效率
best_idx = np.argmax(efficiencies)
ax.scatter([batch_sizes[best_idx]], [efficiencies[best_idx]],
color='gold', s=200, marker='*', zorder=5,
label=f'最高效率: Batch {batch_sizes[best_idx]}')
ax.legend()
plt.tight_layout()
plt.savefig(os.path.join(output_dir, 'batch_efficiency.png'),
dpi=300, bbox_inches='tight')
plt.show()
print(f"✅ 生成图表: batch_efficiency.png")
def create_comprehensive_table(results, output_dir):
"""创建综合性能对比表格"""
fig, ax = plt.subplots(figsize=(14, 8))
ax.axis('tight')
ax.axis('off')
# 准备表格数据
headers = ['批次大小', '吞吐量\n(FPS)', '延迟\n(ms)', 'GPU利用率\n(%)',
'GPU内存\n(MB)', '测试时长\n(s)', '总帧数']
table_data = []
for test in results['batch_tests']:
if test['success']:
row = [
test['batch_size'],
f"{test['avg_throughput']:.1f}",
f"{test['avg_latency_ms']:.1f}",
f"{test['avg_gpu_util']:.1f}",
f"{test['avg_gpu_memory_mb']:.0f}",
f"{test['test_duration']:.1f}",
test['total_frames']
]
table_data.append(row)
else:
row = [test['batch_size'], '失败', '-', '-', '-', '-', '-']
table_data.append(row)
# 创建表格
table = ax.table(cellText=table_data, colLabels=headers,
cellLoc='center', loc='center',
colWidths=[0.12, 0.15, 0.12, 0.15, 0.15, 0.15, 0.16])
table.auto_set_font_size(False)
table.set_fontsize(10)
table.scale(1, 2)
# 设置表头样式
for i in range(len(headers)):
table[(0, i)].set_facecolor('#4ECDC4')
table[(0, i)].set_text_props(weight='bold', color='white')
# 设置行颜色
for i in range(1, len(table_data) + 1):
for j in range(len(headers)):
if i % 2 == 0:
table[(i, j)].set_facecolor('#F0F0F0')
else:
table[(i, j)].set_facecolor('white')
plt.title('批次性能测试综合对比表', fontsize=16, fontweight='bold', pad=20)
plt.savefig(os.path.join(output_dir, 'batch_performance_table.png'),
dpi=300, bbox_inches='tight')
plt.show()
print(f"✅ 生成图表: batch_performance_table.png")
def generate_summary_report(results, output_dir):
"""生成总结报告"""
report = f"""
动态批次 TensorRT 性能测试总结报告
{'='*60}
测试时间: {results['timestamp']}
引擎路径: {results['engine_path']}
"""
if 'summary' in results and results['summary']:
summary = results['summary']
report += f"""测试概况:
{'='*60}
总测试数: {summary['total_tests']}
成功测试: {summary['successful_tests']}
失败测试: {summary['failed_tests']}
"""
if 'best_throughput' in summary:
report += f"""最佳吞吐量配置:
批次大小: {summary['best_throughput']['batch_size']}
吞吐量: {summary['best_throughput']['fps']:.1f} FPS
"""
if 'best_latency' in summary:
report += f"""最低延迟配置:
批次大小: {summary['best_latency']['batch_size']}
延迟: {summary['best_latency']['latency_ms']:.1f}ms
"""
report += f"""详细测试结果:
{'='*60}
"""
for test in results['batch_tests']:
if test['success']:
report += f"""
批次大小: {test['batch_size']}
吞吐量: {test['avg_throughput']:.1f} FPS
延迟: {test['avg_latency_ms']:.1f}ms
GPU 利用率: {test['avg_gpu_util']:.1f}%
GPU 内存: {test['avg_gpu_memory_mb']:.0f}MB (峰值: {test['max_gpu_memory_mb']:.0f}MB)
测试时长: {test['test_duration']:.1f}s
总帧数: {test['total_frames']}
"""
else:
report += f"""
批次大小: {test['batch_size']} - 测试失败
错误信息: {test.get('error_message', '未知错误')}
"""
report += f"""
推荐配置:
{'='*60}
"""
# 分析并给出推荐
successful_tests = [t for t in results['batch_tests'] if t['success']]
if successful_tests:
best_throughput = max(successful_tests, key=lambda x: x['avg_throughput'])
best_latency = min(successful_tests, key=lambda x: x['avg_latency_ms'])
report += f"""
✅ 追求最大吞吐量: 使用批次大小 {best_throughput['batch_size']} ({best_throughput['avg_throughput']:.1f} FPS)
✅ 追求最低延迟: 使用批次大小 {best_latency['batch_size']} ({best_latency['avg_latency_ms']:.1f}ms)
✅ 平衡性能与延迟: 建议使用批次大小 4-8
注意事项:
⚠️ 批次大小越大,吞吐量越高,但单帧延迟也会增加
⚠️ 实际部署时需要根据业务需求选择合适的批次大小
⚠️ GPU 内存占用随批次大小增加而增加,需要确保显存充足
"""
# 保存报告
report_file = os.path.join(output_dir, 'batch_performance_summary.txt')
with open(report_file, 'w', encoding='utf-8') as f:
f.write(report)
print(report)
print(f"\n📁 总结报告已保存: {report_file}")
def main():
"""主函数"""
# 查找最新的测试结果文件
results_dir = "batch_test_results"
if not os.path.exists(results_dir):
print("❌ 未找到测试结果目录")
print("请先运行 run_batch_performance_test.py")
return
json_files = [f for f in os.listdir(results_dir)
if f.startswith('batch_test_results_') and f.endswith('.json')]
if not json_files:
print("❌ 未找到测试结果文件")
return
# 使用最新的结果文件
latest_file = sorted(json_files)[-1]
json_path = os.path.join(results_dir, latest_file)
print(f"📊 加载测试结果: {json_path}")
results = load_results(json_path)
# 创建可视化输出目录
viz_dir = os.path.join(results_dir, "visualizations")
os.makedirs(viz_dir, exist_ok=True)
print("\n🎨 生成可视化图表...")
# 生成各种图表
create_throughput_chart(results, viz_dir)
create_gpu_utilization_chart(results, viz_dir)
create_efficiency_chart(results, viz_dir)
create_comprehensive_table(results, viz_dir)
# 生成总结报告
generate_summary_report(results, viz_dir)
print(f"\n✅ 所有可视化图表已生成完成!")
print(f"📁 输出目录: {viz_dir}")
if __name__ == "__main__":
main()