DepthART / src /tool /compare_depth_outputs.py
sunyijie
first commit
efaa3d7
Raw History Blame Contribute Delete
5.11 kB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
DepthART 两路深度输出的相关性/一致性对比。
支持三种输入格式,自动识别:
- 汇总 NPZ(names/depths),如 ONNX 脚本 --dump-npz 生成的文件
- 分块汇总目录(*.npz 中含 names/depths)
- 旧的逐图 NPZ 目录(<图片名>.npz 中含 depth)
指标(逐图计算后汇总 mean/p50/p90/min):
pearson 皮尔逊相关系数
spearman 斯皮尔曼秩相关
cosine 余弦相似度
mae / rmse 原始量纲误差
aligned_* 最小二乘 scale-shift 对齐后的误差
rel_error mae / mean(|ref|)
用法:
../../venv/bin/python src/tool/compare_depth_outputs.py \
--ref results/nyu654/fp32/npz --pred results/nyu654/axmodel \
--out results/nyu654/eval/corr_fp32_axmodel.json
"""
import argparse
import json
from pathlib import Path
import numpy as np
from scipy.stats import spearmanr
from tqdm import tqdm
def load_predictions(path):
path = Path(path)
if path.is_file():
files = [path]
elif path.is_dir():
files = sorted(path.glob('*.npz'))
if not files:
raise ValueError(f'目录中没有 NPZ: {path}')
else:
raise FileNotFoundError(f'路径不存在: {path}')
preds = {}
for fp in files:
with np.load(fp, allow_pickle=False) as data:
if 'depths' in data and 'names' in data:
for name, depth in zip(data['names'], data['depths']):
preds[str(name)] = np.asarray(depth)
elif 'depth' in data:
preds[fp.name[:-len('.npz')]] = np.asarray(data['depth'])
else:
raise ValueError(f'无法识别的 NPZ: {fp}')
return preds
def compare(ref, pred):
a = np.asarray(ref, dtype=np.float64).ravel()
b = np.asarray(pred, dtype=np.float64).ravel()
if a.shape != b.shape:
raise ValueError(f'shape 不一致: {a.shape} vs {b.shape}')
diff = b - a
mae = float(np.mean(np.abs(diff)))
rmse = float(np.sqrt(np.mean(diff ** 2)))
cosine = float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-12))
pearson = float(np.corrcoef(a, b)[0, 1])
spearman = float(spearmanr(a, b).statistic)
slope, offset = np.polyfit(a, b, 1)
aligned = b - (slope * a + offset)
return {
'pearson': pearson,
'spearman': spearman,
'cosine': cosine,
'mae': mae,
'rmse': rmse,
'rel_error': mae / (np.mean(np.abs(a)) + 1e-12),
'scale': float(slope),
'offset': float(offset),
'aligned_mae': float(np.mean(np.abs(aligned))),
'aligned_rmse': float(np.sqrt(np.mean(aligned ** 2))),
}
def summarize(rows):
keys = ('pearson', 'spearman', 'cosine', 'rel_error', 'aligned_rmse')
out = {}
for k in keys:
values = np.array([r[k] for r in rows])
out[k] = {'mean': float(values.mean()), 'p50': float(np.percentile(values, 50)),
'p90': float(np.percentile(values, 90)), 'min': float(values.min())}
return out
def main():
parser = argparse.ArgumentParser(description='两路深度输出相关性对比')
parser.add_argument('--ref', required=True, help='参考输出(基准后端)')
parser.add_argument('--pred', required=True, help='待比较输出')
parser.add_argument('--out', help='结果 JSON 路径')
args = parser.parse_args()
ref = load_predictions(args.ref)
pred = load_predictions(args.pred)
names = sorted(set(ref) & set(pred))
if not names:
raise ValueError('两路输出没有同名样本')
missing = (len(ref) - len(names)) + (len(pred) - len(names))
if missing:
print(f'警告: {missing} 个样本名称不匹配,已忽略')
rows = []
for name in tqdm(names, desc='compare', ncols=80):
rows.append({'name': name, **compare(ref[name], pred[name])})
summary = summarize(rows)
low = [r for r in rows if r['pearson'] < 0.9]
worst = sorted(rows, key=lambda r: r['pearson'])[:5]
report = {
'ref': str(args.ref), 'pred': str(args.pred),
'num_samples': len(rows),
'summary': summary,
'pearson_below_0.9': len(low),
'worst': [{'name': r['name'], 'pearson': r['pearson'],
'mae': r['mae'], 'aligned_rmse': r['aligned_rmse']} for r in worst],
'per_image': rows,
}
print(f'\n样本数 {len(rows)},pearson<0.9 的 {len(low)} 张')
print(f'{"指标":<14}{"mean":>12}{"p50":>12}{"p90":>12}{"min":>12}')
for k, v in summary.items():
print(f'{k:<14}{v["mean"]:>12.4f}{v["p50"]:>12.4f}{v["p90"]:>12.4f}{v["min"]:>12.4f}')
print('\n最差 5 张:')
for r in worst:
print(f' {r["name"]:<32} pearson={r["pearson"]:.4f} mae={r["mae"]:.4f}')
if args.out:
Path(args.out).parent.mkdir(parents=True, exist_ok=True)
with open(args.out, 'w') as fp:
json.dump(report, fp, indent=2)
print(f'\n结果已保存: {args.out}')
if __name__ == '__main__':
main()