1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// transcribe-debug.h - per-stage tensor dumping for the numerical
// accuracy harness.
//
// Phase 4 step 2 of the encoder port. Provides a single internal API
// the encoder graph builder can call to write a named tensor's
// contents to disk in the same on-disk format that
// scripts/dump_reference_*.py emits, so scripts/compare_tensors.py can
// diff a C++ dump dir against a Python reference dump dir without
// translation.
//
// On-disk format (matches scripts/dump_reference_*.py::write_dump):
//
// <dump_dir>/<name>.f32 raw little-endian fp32, row-major (C order)
// <dump_dir>/<name>.json sidecar metadata
//
// The JSON sidecar carries:
//
// { "name": "...",
// "stage": "...", // optional provenance label
// "shape": [d0, d1, ...], // numpy/row-major (slow-to-fast)
// "dtype": "f32",
// "layout": "row-major",
// "min": <float>, "max": <float>, "mean": <float>,
// "source": { "kind": "cpp" } }
//
// Critical layout note: ggml ne[] is fast-to-slow (ne[0] = innermost,
// most-contiguous dim). Numpy / the Python dumpers use slow-to-fast
// (last axis varies fastest). The dumper converts by reversing ne[]
// and dropping trailing 1s, so a ggml tensor with ne=[1024, 275, 1, 1]
// (typical encoder activation [d_model, T, B=1]) lands on disk as
// shape=[275, 1024] — same as the reference's [T, d_model] tensor
// after squeezing the batch dim.
//
// Activation: dumping is gated on the TRANSCRIBE_DUMP_DIR environment
// variable. When unset, init() is a no-op and every dump_tensor call
// returns immediately. The encoder graph builder can sprinkle
// dump_tensor() calls freely without affecting normal-build cost.
//
// Thread safety: the dump dir is captured once at init() and the
// per-call file writes are not synchronized. The harness assumes
// single-threaded use during numerical accuracy bringup. Concurrent
// dumps would race on file creation and produce truncated output —
// not a goal for v1.
;
namespace transcribe::debug // namespace transcribe::debug