513 lines
18 KiB
Python
513 lines
18 KiB
Python
|
|
#!/usr/bin/env python
|
|||
|
|
"""
|
|||
|
|
分析BEVFusion评估结果的完整脚本
|
|||
|
|
支持3D检测和BEV分割结果分析
|
|||
|
|
"""
|
|||
|
|
import os
|
|||
|
|
import pickle
|
|||
|
|
import numpy as np
|
|||
|
|
import matplotlib.pyplot as plt
|
|||
|
|
from sklearn.metrics import confusion_matrix, jaccard_score
|
|||
|
|
from sklearn.metrics import classification_report
|
|||
|
|
|
|||
|
|
# 设置环境
|
|||
|
|
os.environ['PATH'] = '/opt/conda/bin:' + os.environ.get('PATH', '')
|
|||
|
|
os.environ['LD_LIBRARY_PATH'] = '/opt/conda/lib/python3.8/site-packages/torch/lib:/opt/conda/lib:/usr/local/cuda/lib64:' + os.environ.get('LD_LIBRARY_PATH', '')
|
|||
|
|
os.environ['PYTHONPATH'] = '/workspace/bevfusion:' + os.environ.get('PYTHONPATH', '')
|
|||
|
|
|
|||
|
|
def load_and_inspect_pkl(pkl_path):
|
|||
|
|
"""加载pkl文件并检查基本结构"""
|
|||
|
|
print("="*60)
|
|||
|
|
print("加载和检查pkl文件结构")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
with open(pkl_path, 'rb') as f:
|
|||
|
|
results = pickle.load(f)
|
|||
|
|
|
|||
|
|
print(f"✓ 成功加载pkl文件: {pkl_path}")
|
|||
|
|
print(f"数据类型: {type(results)}")
|
|||
|
|
|
|||
|
|
if isinstance(results, list):
|
|||
|
|
print(f"包含 {len(results)} 个样本的结果")
|
|||
|
|
|
|||
|
|
if len(results) > 0:
|
|||
|
|
sample = results[0]
|
|||
|
|
print("\n第一个样本的结构:")
|
|||
|
|
print(f" 键: {list(sample.keys())}")
|
|||
|
|
|
|||
|
|
# 分析每个字段
|
|||
|
|
for key, value in sample.items():
|
|||
|
|
if hasattr(value, 'shape'):
|
|||
|
|
print(f" {key}: {type(value)}, shape: {value.shape}")
|
|||
|
|
elif hasattr(value, '__len__') and not isinstance(value, str):
|
|||
|
|
print(f" {key}: {type(value)}, length: {len(value)}")
|
|||
|
|
else:
|
|||
|
|
print(f" {key}: {type(value)}, value: {value}")
|
|||
|
|
|
|||
|
|
elif isinstance(results, dict):
|
|||
|
|
print(f"字典结构,包含 {len(results)} 个键: {list(results.keys())}")
|
|||
|
|
for key, value in results.items():
|
|||
|
|
if hasattr(value, 'shape'):
|
|||
|
|
print(f" {key}: {type(value)}, shape: {value.shape}")
|
|||
|
|
elif hasattr(value, '__len__') and not isinstance(value, str):
|
|||
|
|
print(f" {key}: {type(value)}, length: {len(value)}")
|
|||
|
|
else:
|
|||
|
|
print(f" {key}: {type(value)}, value: {value}")
|
|||
|
|
|
|||
|
|
return results
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 加载失败: {e}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def analyze_detection_results(results):
|
|||
|
|
"""分析3D检测结果"""
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print("分析3D检测结果")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
if not isinstance(results, list):
|
|||
|
|
print("❌ 结果不是列表格式,无法分析检测结果")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
total_boxes = 0
|
|||
|
|
all_scores = []
|
|||
|
|
all_labels = []
|
|||
|
|
sample_stats = []
|
|||
|
|
|
|||
|
|
for i, sample in enumerate(results):
|
|||
|
|
if 'boxes_3d' in sample:
|
|||
|
|
boxes = sample['boxes_3d']
|
|||
|
|
scores = sample.get('scores_3d', [])
|
|||
|
|
labels = sample.get('labels_3d', [])
|
|||
|
|
|
|||
|
|
total_boxes += len(boxes)
|
|||
|
|
all_scores.extend(scores)
|
|||
|
|
all_labels.extend(labels)
|
|||
|
|
|
|||
|
|
sample_stats.append({
|
|||
|
|
'sample_id': i,
|
|||
|
|
'num_boxes': len(boxes),
|
|||
|
|
'avg_score': float(np.mean(scores)) if len(scores) > 0 else 0,
|
|||
|
|
'max_score': float(np.max(scores)) if len(scores) > 0 else 0
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
print(f"总检测框数量: {total_boxes}")
|
|||
|
|
print(".2f")
|
|||
|
|
|
|||
|
|
if all_scores:
|
|||
|
|
print(f"分数范围: {min(all_scores):.3f} ~ {max(all_scores):.3f}")
|
|||
|
|
print(f"平均分数: {np.mean(all_scores):.3f}")
|
|||
|
|
|
|||
|
|
if all_labels:
|
|||
|
|
unique_labels, counts = np.unique(all_labels, return_counts=True)
|
|||
|
|
print("\n类别分布:")
|
|||
|
|
for label, count in zip(unique_labels, counts):
|
|||
|
|
print(f" 类别 {label}: {count} 个检测框")
|
|||
|
|
|
|||
|
|
# 可视化检测置信度分布
|
|||
|
|
plt.figure(figsize=(12, 5))
|
|||
|
|
|
|||
|
|
plt.subplot(1, 2, 1)
|
|||
|
|
plt.hist(all_scores, bins=50, alpha=0.7, edgecolor='black')
|
|||
|
|
plt.xlabel('Detection Confidence')
|
|||
|
|
plt.ylabel('Count')
|
|||
|
|
plt.title('Detection Confidence Distribution')
|
|||
|
|
plt.grid(True, alpha=0.3)
|
|||
|
|
|
|||
|
|
plt.subplot(1, 2, 2)
|
|||
|
|
plt.bar(unique_labels, counts, alpha=0.7, edgecolor='black')
|
|||
|
|
plt.xlabel('Class ID')
|
|||
|
|
plt.ylabel('Count')
|
|||
|
|
plt.title('Class Distribution')
|
|||
|
|
plt.xticks(unique_labels)
|
|||
|
|
plt.grid(True, alpha=0.3)
|
|||
|
|
|
|||
|
|
plt.tight_layout()
|
|||
|
|
plt.savefig('/data/eval_fast/detection_analysis.png', dpi=300, bbox_inches='tight')
|
|||
|
|
plt.show()
|
|||
|
|
|
|||
|
|
print("✓ 检测分析图表已保存至: /data/eval_fast/detection_analysis.png")
|
|||
|
|
# 样本统计
|
|||
|
|
if sample_stats:
|
|||
|
|
print("\n前10个样本的检测统计:")
|
|||
|
|
for stat in sample_stats[:10]:
|
|||
|
|
print(f" 样本 {stat['sample_id']}: {stat['num_boxes']} 框, 平均置信度 {stat['avg_score']:.3f}, 最高置信度 {stat['max_score']:.3f}")
|
|||
|
|
def analyze_segmentation_results(results):
|
|||
|
|
"""分析BEV分割结果"""
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print("分析BEV分割结果")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
if not isinstance(results, list):
|
|||
|
|
print("❌ 结果不是列表格式,无法分析分割结果")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
segmentation_stats = []
|
|||
|
|
|
|||
|
|
for i, sample in enumerate(results):
|
|||
|
|
if 'masks_bev' in sample:
|
|||
|
|
mask = sample['masks_bev'] # 应该是 (C, H, W) 格式
|
|||
|
|
gt_mask = sample.get('gt_masks_bev')
|
|||
|
|
|
|||
|
|
if isinstance(mask, np.ndarray):
|
|||
|
|
# 如果是numpy数组,直接分析
|
|||
|
|
pred_mask = mask
|
|||
|
|
elif hasattr(mask, 'cpu'):
|
|||
|
|
# 如果是torch tensor,转换为numpy
|
|||
|
|
pred_mask = mask.cpu().numpy()
|
|||
|
|
else:
|
|||
|
|
print(f"⚠️ 样本 {i} 的mask格式不支持: {type(mask)}")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
# 计算各类别像素数量
|
|||
|
|
unique_classes, pixel_counts = np.unique(pred_mask, return_counts=True)
|
|||
|
|
|
|||
|
|
stat = {
|
|||
|
|
'sample_id': i,
|
|||
|
|
'mask_shape': pred_mask.shape,
|
|||
|
|
'num_classes': len(unique_classes),
|
|||
|
|
'pixel_counts': dict(zip(unique_classes, pixel_counts)),
|
|||
|
|
'total_pixels': pred_mask.size
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if gt_mask is not None:
|
|||
|
|
if hasattr(gt_mask, 'cpu'):
|
|||
|
|
gt_mask = gt_mask.cpu().numpy()
|
|||
|
|
|
|||
|
|
# 计算IoU
|
|||
|
|
pred_flat = pred_mask.flatten()
|
|||
|
|
gt_flat = gt_mask.flatten()
|
|||
|
|
|
|||
|
|
# 获取真实标签中的唯一类别
|
|||
|
|
gt_unique_classes = np.unique(gt_flat)
|
|||
|
|
|
|||
|
|
# 只使用存在于真实标签中的类别
|
|||
|
|
valid_classes = np.intersect1d(unique_classes, gt_unique_classes)
|
|||
|
|
|
|||
|
|
if len(valid_classes) > 0:
|
|||
|
|
# 计算混淆矩阵
|
|||
|
|
cm = confusion_matrix(gt_flat, pred_flat, labels=valid_classes)
|
|||
|
|
else:
|
|||
|
|
cm = None
|
|||
|
|
|
|||
|
|
# 计算各类IoU
|
|||
|
|
if cm is not None:
|
|||
|
|
iou_per_class = []
|
|||
|
|
for j in range(len(valid_classes)):
|
|||
|
|
if cm[j,:].sum() + cm[:,j].sum() - cm[j,j] > 0:
|
|||
|
|
iou = cm[j,j] / (cm[j,:].sum() + cm[:,j].sum() - cm[j,j])
|
|||
|
|
iou_per_class.append(iou)
|
|||
|
|
else:
|
|||
|
|
iou_per_class.append(0)
|
|||
|
|
|
|||
|
|
stat['iou_per_class'] = dict(zip(valid_classes, iou_per_class))
|
|||
|
|
stat['miou'] = np.mean(iou_per_class) if iou_per_class else 0
|
|||
|
|
else:
|
|||
|
|
stat['iou_per_class'] = {}
|
|||
|
|
stat['miou'] = 0
|
|||
|
|
|
|||
|
|
segmentation_stats.append(stat)
|
|||
|
|
|
|||
|
|
if segmentation_stats:
|
|||
|
|
print(f"分析了 {len(segmentation_stats)} 个样本的分割结果")
|
|||
|
|
|
|||
|
|
# 汇总统计
|
|||
|
|
all_classes = set()
|
|||
|
|
for stat in segmentation_stats:
|
|||
|
|
all_classes.update(stat['pixel_counts'].keys())
|
|||
|
|
|
|||
|
|
print(f"\n总共发现 {len(all_classes)} 个类别: {sorted(all_classes)}")
|
|||
|
|
|
|||
|
|
# 计算平均IoU
|
|||
|
|
if 'miou' in segmentation_stats[0]:
|
|||
|
|
mious = [stat['miou'] for stat in segmentation_stats if 'miou' in stat]
|
|||
|
|
print(f"平均mIoU: {np.mean(mious):.4f}")
|
|||
|
|
|
|||
|
|
# 各类别平均IoU
|
|||
|
|
class_iou_sum = {}
|
|||
|
|
class_iou_count = {}
|
|||
|
|
|
|||
|
|
for stat in segmentation_stats:
|
|||
|
|
if 'iou_per_class' in stat:
|
|||
|
|
for cls, iou in stat['iou_per_class'].items():
|
|||
|
|
if cls not in class_iou_sum:
|
|||
|
|
class_iou_sum[cls] = 0
|
|||
|
|
class_iou_count[cls] = 0
|
|||
|
|
class_iou_sum[cls] += iou
|
|||
|
|
class_iou_count[cls] += 1
|
|||
|
|
|
|||
|
|
print("\n各类别平均IoU:")
|
|||
|
|
for cls in sorted(class_iou_sum.keys()):
|
|||
|
|
avg_iou = class_iou_sum[cls] / class_iou_count[cls]
|
|||
|
|
print(f" 类别 {cls}: {avg_iou:.4f}")
|
|||
|
|
# 可视化分割结果分布
|
|||
|
|
plt.figure(figsize=(15, 10))
|
|||
|
|
|
|||
|
|
# 像素分布
|
|||
|
|
plt.subplot(2, 2, 1)
|
|||
|
|
sample_pixels = segmentation_stats[0]['pixel_counts']
|
|||
|
|
classes = list(sample_pixels.keys())
|
|||
|
|
pixels = list(sample_pixels.values())
|
|||
|
|
plt.bar(classes, pixels, alpha=0.7, edgecolor='black')
|
|||
|
|
plt.xlabel('Class ID')
|
|||
|
|
plt.ylabel('Pixel Count')
|
|||
|
|
plt.title('Pixel Distribution (Sample 0)')
|
|||
|
|
plt.xticks(classes)
|
|||
|
|
plt.grid(True, alpha=0.3)
|
|||
|
|
|
|||
|
|
# IoU分布
|
|||
|
|
if 'iou_per_class' in segmentation_stats[0]:
|
|||
|
|
plt.subplot(2, 2, 2)
|
|||
|
|
ious = list(segmentation_stats[0]['iou_per_class'].values())
|
|||
|
|
plt.bar(classes, ious, alpha=0.7, edgecolor='black', color='green')
|
|||
|
|
plt.xlabel('Class ID')
|
|||
|
|
plt.ylabel('IoU')
|
|||
|
|
plt.title('IoU per Class (Sample 0)')
|
|||
|
|
plt.xticks(classes)
|
|||
|
|
plt.ylim(0, 1)
|
|||
|
|
plt.grid(True, alpha=0.3)
|
|||
|
|
|
|||
|
|
# mIoU分布
|
|||
|
|
if 'miou' in segmentation_stats[0]:
|
|||
|
|
plt.subplot(2, 2, 3)
|
|||
|
|
mious = [stat['miou'] for stat in segmentation_stats if 'miou' in stat]
|
|||
|
|
plt.hist(mious, bins=20, alpha=0.7, edgecolor='black')
|
|||
|
|
plt.xlabel('mIoU')
|
|||
|
|
plt.ylabel('Count')
|
|||
|
|
plt.title('mIoU Distribution Across Samples')
|
|||
|
|
plt.grid(True, alpha=0.3)
|
|||
|
|
|
|||
|
|
plt.tight_layout()
|
|||
|
|
plt.savefig('/data/eval_fast/segmentation_analysis.png', dpi=300, bbox_inches='tight')
|
|||
|
|
plt.show()
|
|||
|
|
|
|||
|
|
print("✓ 分割分析图表已保存至: /data/eval_fast/segmentation_analysis.png")
|
|||
|
|
def visualize_sample(results, sample_idx=0):
|
|||
|
|
"""可视化单个样本的结果"""
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print(f"可视化样本 {sample_idx}")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
if not isinstance(results, list) or sample_idx >= len(results):
|
|||
|
|
print(f"❌ 无效的样本索引 {sample_idx}")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
sample = results[sample_idx]
|
|||
|
|
|
|||
|
|
fig = plt.figure(figsize=(20, 10))
|
|||
|
|
|
|||
|
|
# 检测结果
|
|||
|
|
if 'boxes_3d' in sample and 'scores_3d' in sample:
|
|||
|
|
plt.subplot(2, 3, 1)
|
|||
|
|
scores = sample['scores_3d']
|
|||
|
|
plt.hist(scores, bins=20, alpha=0.7, edgecolor='black')
|
|||
|
|
plt.xlabel('Confidence Score')
|
|||
|
|
plt.ylabel('Count')
|
|||
|
|
plt.title(f'Detection Scores (Sample {sample_idx})')
|
|||
|
|
plt.grid(True, alpha=0.3)
|
|||
|
|
|
|||
|
|
# BEV分割结果
|
|||
|
|
if 'masks_bev' in sample:
|
|||
|
|
mask = sample['masks_bev']
|
|||
|
|
if hasattr(mask, 'cpu'):
|
|||
|
|
mask = mask.cpu().numpy()
|
|||
|
|
|
|||
|
|
if mask.ndim == 3: # (C, H, W)
|
|||
|
|
# 显示前6个类别
|
|||
|
|
for i in range(min(6, mask.shape[0])):
|
|||
|
|
plt.subplot(2, 3, i+2)
|
|||
|
|
plt.imshow(mask[i], cmap='viridis')
|
|||
|
|
plt.title(f'BEV Class {i} (Sample {sample_idx})')
|
|||
|
|
plt.axis('off')
|
|||
|
|
else:
|
|||
|
|
plt.subplot(2, 3, 2)
|
|||
|
|
plt.imshow(mask, cmap='tab20')
|
|||
|
|
plt.title(f'BEV Segmentation (Sample {sample_idx})')
|
|||
|
|
plt.axis('off')
|
|||
|
|
|
|||
|
|
plt.tight_layout()
|
|||
|
|
plt.savefig(f'/data/eval_fast/sample_{sample_idx}_visualization.png', dpi=300, bbox_inches='tight')
|
|||
|
|
plt.show()
|
|||
|
|
|
|||
|
|
print(f"✓ 样本{sample_idx}可视化已保存至: /data/eval_fast/sample_{sample_idx}_visualization.png")
|
|||
|
|
def generate_performance_report(results):
|
|||
|
|
"""生成性能报告"""
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print("生成性能报告")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
report = {}
|
|||
|
|
|
|||
|
|
if not isinstance(results, list):
|
|||
|
|
print("❌ 无法生成报告:结果不是列表格式")
|
|||
|
|
return report
|
|||
|
|
|
|||
|
|
# 检测指标
|
|||
|
|
if any('boxes_3d' in sample for sample in results):
|
|||
|
|
detection_stats = {
|
|||
|
|
'total_samples': len(results),
|
|||
|
|
'total_detections': 0,
|
|||
|
|
'avg_detections_per_sample': 0,
|
|||
|
|
'score_distribution': {'min': float('inf'), 'max': 0, 'mean': 0},
|
|||
|
|
'class_distribution': {}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
all_scores = []
|
|||
|
|
all_labels = []
|
|||
|
|
|
|||
|
|
for sample in results:
|
|||
|
|
if 'boxes_3d' in sample:
|
|||
|
|
detection_stats['total_detections'] += len(sample['boxes_3d'])
|
|||
|
|
if 'scores_3d' in sample:
|
|||
|
|
all_scores.extend(sample['scores_3d'])
|
|||
|
|
if 'labels_3d' in sample:
|
|||
|
|
all_labels.extend(sample['labels_3d'])
|
|||
|
|
|
|||
|
|
detection_stats['avg_detections_per_sample'] = detection_stats['total_detections'] / detection_stats['total_samples']
|
|||
|
|
|
|||
|
|
if all_scores:
|
|||
|
|
detection_stats['score_distribution'] = {
|
|||
|
|
'min': float(np.min(all_scores)),
|
|||
|
|
'max': float(np.max(all_scores)),
|
|||
|
|
'mean': float(np.mean(all_scores))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if all_labels:
|
|||
|
|
unique_labels, counts = np.unique(all_labels, return_counts=True)
|
|||
|
|
detection_stats['class_distribution'] = dict(zip(unique_labels.astype(int), counts))
|
|||
|
|
|
|||
|
|
report['detection'] = detection_stats
|
|||
|
|
|
|||
|
|
# 分割指标
|
|||
|
|
seg_samples = [s for s in results if 'masks_bev' in s and 'gt_masks_bev' in s]
|
|||
|
|
if seg_samples:
|
|||
|
|
segmentation_stats = {
|
|||
|
|
'total_samples': len(seg_samples),
|
|||
|
|
'avg_miou': 0,
|
|||
|
|
'class_wise_iou': {}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
all_mious = []
|
|||
|
|
class_iou_sum = {}
|
|||
|
|
class_iou_count = {}
|
|||
|
|
|
|||
|
|
for sample in seg_samples:
|
|||
|
|
pred_mask = sample['masks_bev']
|
|||
|
|
gt_mask = sample['gt_masks_bev']
|
|||
|
|
|
|||
|
|
if hasattr(pred_mask, 'cpu'):
|
|||
|
|
pred_mask = pred_mask.cpu().numpy()
|
|||
|
|
if hasattr(gt_mask, 'cpu'):
|
|||
|
|
gt_mask = gt_mask.cpu().numpy()
|
|||
|
|
|
|||
|
|
pred_flat = pred_mask.flatten()
|
|||
|
|
gt_flat = gt_mask.flatten()
|
|||
|
|
|
|||
|
|
# 计算mIoU
|
|||
|
|
try:
|
|||
|
|
miou = jaccard_score(gt_flat, pred_flat, average='macro')
|
|||
|
|
all_mious.append(miou)
|
|||
|
|
except:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if all_mious:
|
|||
|
|
segmentation_stats['avg_miou'] = float(np.mean(all_mious))
|
|||
|
|
|
|||
|
|
report['segmentation'] = segmentation_stats
|
|||
|
|
|
|||
|
|
# 打印报告
|
|||
|
|
print("性能报告:")
|
|||
|
|
for task, metrics in report.items():
|
|||
|
|
print(f"\n{task.upper()}:")
|
|||
|
|
if isinstance(metrics, dict):
|
|||
|
|
for key, value in metrics.items():
|
|||
|
|
if isinstance(value, dict):
|
|||
|
|
print(f" {key}:")
|
|||
|
|
for subkey, subvalue in value.items():
|
|||
|
|
print(f" {subkey}: {subvalue}")
|
|||
|
|
else:
|
|||
|
|
print(f" {key}: {value}")
|
|||
|
|
|
|||
|
|
return report
|
|||
|
|
|
|||
|
|
def compare_with_baseline(current_results, baseline_path):
|
|||
|
|
"""与基准结果比较"""
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print("与基准结果比较")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
with open(baseline_path, 'rb') as f:
|
|||
|
|
baseline = pickle.load(f)
|
|||
|
|
|
|||
|
|
current_report = generate_performance_report(current_results)
|
|||
|
|
baseline_report = generate_performance_report(baseline)
|
|||
|
|
|
|||
|
|
print("\n性能比较:")
|
|||
|
|
|
|||
|
|
for task in current_report:
|
|||
|
|
if task in baseline_report:
|
|||
|
|
print(f"\n{task.upper()}:")
|
|||
|
|
current_metrics = current_report[task]
|
|||
|
|
baseline_metrics = baseline_report[task]
|
|||
|
|
|
|||
|
|
if isinstance(current_metrics, dict) and isinstance(baseline_metrics, dict):
|
|||
|
|
for metric in current_metrics:
|
|||
|
|
if metric in baseline_metrics:
|
|||
|
|
current_val = current_metrics[metric]
|
|||
|
|
baseline_val = baseline_metrics[metric]
|
|||
|
|
|
|||
|
|
if isinstance(current_val, (int, float)) and isinstance(baseline_val, (int, float)):
|
|||
|
|
diff = current_val - baseline_val
|
|||
|
|
print(f" {metric}: {current_val:.4f} vs {baseline_val:.4f} ({diff:+.4f})")
|
|||
|
|
elif isinstance(current_val, dict) and isinstance(baseline_val, dict):
|
|||
|
|
print(f" {metric}:")
|
|||
|
|
for submetric in current_val:
|
|||
|
|
if submetric in baseline_val:
|
|||
|
|
c_val = current_val[submetric]
|
|||
|
|
b_val = baseline_val[submetric]
|
|||
|
|
if isinstance(c_val, (int, float)) and isinstance(b_val, (int, float)):
|
|||
|
|
diff = c_val - b_val
|
|||
|
|
print(f" {submetric}: {c_val:.4f} vs {b_val:.4f} ({diff:+.4f})")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 基准比较失败: {e}")
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
# 结果文件路径
|
|||
|
|
results_path = '/data/eval_fast/epoch1_fast_20251119_133104/fast_results.pkl'
|
|||
|
|
|
|||
|
|
# 加载和检查结果
|
|||
|
|
results = load_and_inspect_pkl(results_path)
|
|||
|
|
if results is None:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 分析检测结果
|
|||
|
|
analyze_detection_results(results)
|
|||
|
|
|
|||
|
|
# 分析分割结果
|
|||
|
|
analyze_segmentation_results(results)
|
|||
|
|
|
|||
|
|
# 可视化样本
|
|||
|
|
if len(results) > 0:
|
|||
|
|
visualize_sample(results, sample_idx=0)
|
|||
|
|
|
|||
|
|
# 生成性能报告
|
|||
|
|
performance_report = generate_performance_report(results)
|
|||
|
|
|
|||
|
|
# 可选:与基准比较 (如果有基准文件)
|
|||
|
|
# baseline_path = '/path/to/baseline_results.pkl'
|
|||
|
|
# compare_with_baseline(results, baseline_path)
|
|||
|
|
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print("分析完成!")
|
|||
|
|
print("生成的文件:")
|
|||
|
|
print(" - /data/eval_fast/detection_analysis.png")
|
|||
|
|
print(" - /data/eval_fast/segmentation_analysis.png")
|
|||
|
|
print(" - /data/eval_fast/sample_0_visualization.png")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
main()
|