Files
momentry_core/scripts/yolo_count_comparison.py
T
Warren e75c4d6f07 cleanup: remove dead code and duplicate docs
- Remove session-ses_2f27.md (161KB raw session log)
- Remove 49 ROOT_* duplicate files across REFERENCE/
- Remove 14 duplicate files between REFERENCE/ root and history/
- Remove asr_legacy.rs (dead code, replaced by asr.rs)
- Remove src/core/worker/ (duplicate JobWorker)
- Remove src/core/layers/ (empty directory)
- Remove 4 .bak files in src/
- Remove 7 dead private methods in worker/processor.rs
- Remove backup directory from git tracking
2026-05-04 01:31:21 +08:00

210 lines
6.7 KiB
Python

#!/opt/homebrew/bin/python3.11
"""
YOLO Detection Count Comparison
对比 YOLO processor 的检测物体数量和类别
"""
import json
from pathlib import Path
from collections import defaultdict
def load_yolo_results(filepath):
"""加载 YOLO 检测结果"""
if not filepath.exists():
print(f"❌ 文件不存在: {filepath}")
return None
with open(filepath) as f:
data = json.load(f)
results = {
'total_frames': 0,
'total_objects': 0,
'classes': defaultdict(int),
'confidence_avg': 0.0,
'frames_with_objects': 0,
'frames_empty': 0,
}
frames_data = data.get('frames', [])
if isinstance(frames_data, dict):
frames_list = list(frames_data.values())
elif isinstance(frames_data, list):
frames_list = frames_data
else:
return results
results['total_frames'] = len(frames_list)
total_confidence = 0.0
total_objects = 0
for frame in frames_list:
if isinstance(frame, dict):
detections = frame.get('detections', frame.get('objects', []))
if detections and len(detections) > 0:
results['frames_with_objects'] += 1
for det in detections:
if isinstance(det, dict):
total_objects += 1
class_name = det.get('class_name', det.get('name', det.get('class', 'unknown')))
results['classes'][class_name] += 1
confidence = det.get('confidence', det.get('score', 1.0))
if isinstance(confidence, (int, float)):
total_confidence += confidence
else:
results['frames_empty'] += 1
results['total_objects'] = total_objects
if total_objects > 0:
results['confidence_avg'] = total_confidence / total_objects
return results
def compare_classes(results_a, results_b, results_c):
"""对比检测类别"""
all_classes = set()
if results_a:
all_classes.update(results_a['classes'].keys())
if results_b:
all_classes.update(results_b['classes'].keys())
if results_c:
all_classes.update(results_c['classes'].keys())
comparison = []
for class_name in sorted(all_classes):
count_a = results_a['classes'].get(class_name, 0) if results_a else 0
count_b = results_b['classes'].get(class_name, 0) if results_b else 0
count_c = results_c['classes'].get(class_name, 0) if results_c else 0
if count_a != count_b or count_a != count_c or count_b != count_c:
comparison.append({
'class_name': class_name,
'cpu': count_a,
'mps': count_b,
'contract': count_c,
'max': max(count_a, count_b, count_c),
'min': min(count_a, count_b, count_c),
})
return comparison
def main():
benchmark_dir = Path('/Users/accusys/momentry_core_0.1/output/benchmark/yolo_processor')
print("=" * 80)
print("YOLO Detection Count Comparison")
print("=" * 80)
print()
# 加载三个版本的结果
results_a = load_yolo_results(benchmark_dir / 'scheme_A_yolo_processor.json')
results_b = load_yolo_results(benchmark_dir / 'scheme_B_yolo_processor_mps.json')
results_c = load_yolo_results(benchmark_dir / 'scheme_C_yolo_processor_contract_v1.json')
if not results_a and not results_b and not results_c:
print("❌ 没有可用的检测结果文件")
return
# 统计概览
print("【检测统计】")
print()
print("| 版本 | 总帧数 | 检测物体数 | 有物体帧 | 空帧 | 平均置信度 |")
print("|------|--------|-----------|---------|------|------------|")
for name, results in [('CPU', results_a), ('MPS', results_b), ('Contract', results_c)]:
if results:
print(f"| {name} | {results['total_frames']} | {results['total_objects']} | {results['frames_with_objects']} | {results['frames_empty']} | {results['confidence_avg']:.2f} |")
else:
print(f"| {name} | - | - | - | - | - |")
print()
# 类别统计
print("【检测类别统计】")
print()
if results_a and results_a['classes']:
print("CPU版本检测类别:")
print("| 类别 | 数量 |")
print("|------|------|")
for class_name, count in sorted(results_a['classes'].items(), key=lambda x: -x[1]):
print(f"| {class_name} | {count} |")
print(f"| **总计** | {sum(results_a['classes'].values())} |")
print()
# 类别对比
print("【类别数量对比】")
print()
comparison = compare_classes(results_a, results_b, results_c)
if comparison:
print(f"共有 {len(comparison)} 个类别检测数量不同")
print()
print("| 类别 | CPU | MPS | Contract | 最大差异 |")
print("|------|-----|-----|----------|---------|")
for item in comparison[:20]:
diff = item['max'] - item['min']
print(f"| {item['class_name']} | {item['cpu']} | {item['mps']} | {item['contract']} | {diff} |")
if len(comparison) > 20:
print("| ... | ... | ... | ... | ... |")
else:
print("所有类别检测数量一致")
print()
# 检测率分析
print("【检测率分析】")
print()
if results_a and results_a['total_objects'] > 0:
baseline = results_a['total_objects']
print(f"以CPU版本为基准({baseline}个物体):")
print()
print("| 版本 | 检测数 | 检测率 | 漏检数 |")
print("|------|--------|--------|--------|")
for name, results in [('CPU', results_a), ('MPS', results_b), ('Contract', results_c)]:
if results:
rate = results['total_objects'] / baseline * 100
missed = baseline - results['total_objects']
print(f"| {name} | {results['total_objects']} | {rate:.1f}% | {missed} |")
else:
print(f"| {name} | - | - | - |")
print()
print("=" * 80)
print("对比完成")
print("=" * 80)
# 保存结果
output = {
'cpu': results_a,
'mps': results_b,
'contract': results_c,
'comparison': comparison,
}
output_path = benchmark_dir / 'YOLO_COUNT_COMPARISON.json'
with open(output_path, 'w') as f:
json.dump(output, f, indent=2, ensure_ascii=False)
print(f"\n对比结果已保存: {output_path}")
if __name__ == '__main__':
main()