| 48 | |
| 49 | |
| 50 | def compare(name, ref_path, cpp_path): |
| 51 | ref_data, ref_shape = load_tensor(ref_path) |
| 52 | cpp_data, cpp_shape = load_tensor(cpp_path) |
| 53 | |
| 54 | if ref_data.size != cpp_data.size: |
| 55 | return { |
| 56 | "status": "FAIL", |
| 57 | "note": f"SIZE MISMATCH ref={ref_data.size} cpp={cpp_data.size}", |
| 58 | "ref_shape": ref_shape, |
| 59 | "cpp_shape": cpp_shape, |
| 60 | } |
| 61 | |
| 62 | diff = np.abs(ref_data - cpp_data) |
| 63 | eps = 1e-8 |
| 64 | max_d = float(diff.max()) |
| 65 | mae = float(diff.mean()) |
| 66 | rel_err = diff / (np.abs(ref_data) + eps) |
| 67 | mean_rel = float(rel_err.mean()) |
| 68 | cos = float( |
| 69 | np.dot(ref_data, cpp_data) |
| 70 | / (np.linalg.norm(ref_data) * np.linalg.norm(cpp_data) + 1e-12) |
| 71 | ) |
| 72 | p95 = float(np.percentile(diff, 95)) |
| 73 | p99 = float(np.percentile(diff, 99)) |
| 74 | |
| 75 | worst_idx = int(np.argmax(diff)) |
| 76 | worst_ref = float(ref_data[worst_idx]) |
| 77 | worst_cpp = float(cpp_data[worst_idx]) |
| 78 | |
| 79 | return { |
| 80 | "status": "OK", |
| 81 | "ref_shape": ref_shape, |
| 82 | "cpp_shape": cpp_shape, |
| 83 | "mae": mae, |
| 84 | "max": max_d, |
| 85 | "rel": mean_rel, |
| 86 | "cos": cos, |
| 87 | "p95": p95, |
| 88 | "p99": p99, |
| 89 | "worst_idx": worst_idx, |
| 90 | "worst_ref": worst_ref, |
| 91 | "worst_cpp": worst_cpp, |
| 92 | "n_elements": ref_data.size, |
| 93 | } |
| 94 | |
| 95 | |
| 96 | def main(): |