File size: 11,684 Bytes
be3ecc8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# TTNN Validation & Testing Utilities

Helpers for validating TTNN computations against reference implementations and
for moving tensors between TTNN and PyTorch. The public API is implemented
across `models.common.validation_tools`, `models.common.metrics`,
`models.common.auto_compose`, and `models.common.distribute_as`, and is
exercised in:

- `models/common/tests/test_validation_tools.py`
- `models/common/tests/test_metrics.py`
- `models/common/tests/test_auto_compose.py`
- `models/common/tests/test_distribute_as.py`
- `models/common/tests/host/test_metrics_pytorch_only.py`

The examples in these tests are the most up‑to‑date reference for usage.

## Quick Start – host reference (`compare_to_torch`)

Use `compare_to_torch` when your reference implementation is a PyTorch function.
Inputs and outputs are automatically converted between TTNN and PyTorch.

```python
import torch
import ttnn
from models.common.validation_tools import compare_to_torch, Metric, get_validation_registry


@compare_to_torch(
    reference_fn=torch.matmul,
    metric_tolerances={
        Metric.MAX_ABS_ERROR: 1e-1,
        Metric.PCC: 0.99,
    },
)
def ttnn_matmul(a, b):
    # a, b are TTNN tensors (possibly sharded)
    return ttnn.matmul(a, b)


def run_example(device: ttnn.MeshDevice):
    m, n, k = 16, 24, 12
    a = torch.randn(1, m, k, dtype=torch.bfloat16)
    b = torch.randn(1, k, n, dtype=torch.bfloat16)

    a_tt = ttnn.from_torch(a.unsqueeze(0), device=device, dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT)
    b_tt = ttnn.from_torch(b.unsqueeze(0), device=device, dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT)

    _ = ttnn_matmul(a_tt, b_tt)

    registry = get_validation_registry()
    registry.print_report()
```

Note:
- When the signature of the decorated function is different from the reference function, `input_to_torch` and `output_to_torch` can be used to map the inputs and outputs between the decorated function and the reference function.
- See `models/common/tests/test_validation_tools.py::test_validation_matmul` for a real test using
this pattern.

## Quick Start – TTNN reference (`compare_to_ttnn`)

Use `compare_to_ttnn` when both your implementation and reference are TTNN‑based
and you want metrics computed directly on device.

```python
import torch
import ttnn
from models.common.validation_tools import compare_to_ttnn


def torch_rms_norm(x, weight, eps=1e-6):
    var = x.pow(2).mean(-1, keepdim=True)
    return weight * x * torch.rsqrt(var + eps)


class DeviceValidatedRMSNorm:
    def __init__(self, weight: torch.Tensor, eps: float, device: ttnn.MeshDevice):
        self.eps = eps
        self.device = device
        self.weight_torch = weight
        self.weight = ttnn.from_torch(
            weight.unsqueeze(0).unsqueeze(0), device=device, dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT
        )

    def _reference_impl(self, x):
        x_torch = ttnn.to_torch(x).squeeze(0)
        y_torch = torch_rms_norm(x_torch, self.weight_torch, self.eps)
        return ttnn.from_torch(
            y_torch.unsqueeze(0), device=self.device, dtype=ttnn.bfloat16, layout=ttnn.TILE_LAYOUT
        )

    @compare_to_ttnn(reference_fn=lambda self, x: self._reference_impl(x))
    def __call__(self, x):
        x_sq = ttnn.mul(x, x)
        mean_x_sq = ttnn.mean(x_sq, dim=-1, keepdim=True)
        rms = ttnn.sqrt(ttnn.add(mean_x_sq, self.eps))
        x_norm = ttnn.mul(x, ttnn.reciprocal(rms))
        return ttnn.mul(x_norm, self.weight)
```
Note:
- When the signature of the decorated function is different from the reference function, `input_to_ttnn` and `output_to_ttnn` can be used to map the inputs and outputs between the decorated function and the reference function.
- This mirrors the pattern used by `DeviceValidatedRMSNorm` in
`models/common/tests/test_validation_tools.py`.

## Features

- **Decorator‑based validation** – Wrap TTNN functions or methods and compare
  them against PyTorch or TTNN references.
- **Host and device modes** – `compare_to_torch` (PyTorch reference) and
  `compare_to_ttnn` (TTNN reference).
- **TTNN‑native metrics** – When both outputs are TTNN tensors, metrics are
  computed on device with minimal host transfer.
- **Configurable tolerances** – Per‑metric tolerances via the `Metric` enum,
  string keys, or `MetricSpec`.
- **Custom metrics** – Inject your own metric functions.
- **Global registry** – Collects all validation runs for reporting.
- **Easy disabling** – Turn validation on/off globally without changing call
  sites.

## Core Components

### Validation decorators

All decorators live in `models.common.validation_tools`:

- `compare_to_torch(reference_fn, *, input_to_torch=None, output_to_torch=None, metric_tolerances=None, enabled=True, raise_exceptions=False, return_reference_output=False)`
  - Use when `reference_fn` is a PyTorch implementation.
  - By default, all TTNN tensors in the arguments/outputs are converted to
    PyTorch via `to_torch_auto_compose`.
  - Optional `input_to_torch(*args, **kwargs)` lets you override how inputs
    are mapped to the reference.
  - Optional `output_to_torch(output)` converts the implementation output
    before metrics are computed.

- `compare_to_ttnn(reference_fn, *, input_to_ttnn=None, output_to_ttnn=None, metric_tolerances=None, enabled=True, raise_exceptions=False, return_reference_output=False)`
  - Use when `reference_fn` consumes and returns TTNN tensors.
  - Optional `input_to_ttnn(*args, **kwargs)` lets you override how inputs
    are mapped to the reference.
  - Optional `output_to_ttnn(output)` converts the implementation output
    before metrics are computed.
  - If both implementation and reference return TTNN tensors, metrics run
    entirely on device.

In both cases, decorating a function records a `ValidationResult` in the global
`ValidationRegistry` every time the function is called (unless disabled).

### Metrics

Metric utilities are implemented in `models.common.metrics`:

- `compute_max_abs_error(impl, ref)` – max absolute error.
- `compute_mean_abs_error(impl, ref)` – mean absolute error.
- `compute_pcc(impl, ref)` – Pearson correlation coefficient; uses TTNN
  operations when possible and falls back to host.
- `comp_allclose(impl, ref, rtol=..., atol=...)` – allclose check plus a
  detailed delta string.
- `DEFAULT_METRICS` – dict with built‑in metrics (`"max_abs_error"`,
  `"mean_abs_error"`, `"pcc"`).

Metrics support both TTNN and PyTorch tensors.

### Registry and control functions

From `models.common.validation_tools`:

- `get_validation_registry() -> ValidationRegistry`
  - Holds all `ValidationResult` objects.
  - Provides `get_summary()` and `print_report(verbose: bool = False)`.

- `enable_validation(enabled: bool = True)`
  - Globally enable/disable validation; when disabled, decorators become
    transparent wrappers.

- `clear_validation_results()`
  - Clear all accumulated validation results.

`ValidationResult` includes:

- `function_name`
- `passed` (bool)
- `metrics` – map of metric name → per‑metric result (value, passed, error)
- `execution_time_impl`, `execution_time_ref`
- `timestamp`
- `logs` – optional debug strings

### Auto‑compose helper

`to_torch_auto_compose` lives in `models.common.auto_compose`.

It converts an arbitrary TTNN tensor (including sharded/replicated multi‑device
tensors) to a single PyTorch tensor by automatically choosing the appropriate
mesh composer.

It is heavily used in:

- `test_auto_compose.py`
- `test_distribute_as.py`
- all `compare_to_torch`‑based examples.

## Usage Patterns

High‑level patterns illustrated in the tests:

1. **Host reference with explicit input mapping**
   - See `HostValidatedRMSNorm` in `models/common/tests/test_validation_tools.py`.
   - Uses `compare_to_torch` with `input_to_torch` to map TTNN inputs and
     TTNN weights to a pure‑PyTorch reference function.

2. **TTNN reference (on‑device metrics)**
   - See `DeviceValidatedRMSNorm` in `models/common/tests/test_validation_tools.py`.
   - Uses `compare_to_ttnn` where both implementation and reference return
     TTNN tensors; metrics run on device.

3. **Simple library calls**
   - See `ttnn_matmul` and `ttnn_matmul_reverse` in `models/common/tests/test_validation_tools.py`.
   - `compare_to_torch(reference_fn=torch.matmul, ...)` with optional
     `input_to_torch` remapping.

4. **Checkpoint / `from_torch` validation**
   - See `from_torch_checkpoint` in `models/common/tests/test_validation_tools.py`.
   - Validates a direct `ttnn.from_torch(...)` call using `compare_to_torch`
     and `output_to_torch`.

5. **Custom metric via `MetricSpec`**
   - See `ttnn_matmul_metric_spec` in `models/common/tests/test_validation_tools.py`
     and `MetricSpec` usage in `models/common/tests/host/test_metrics_pytorch_only.py`.
   - Use `MetricSpec(tolerance=..., higher_is_better=..., compute_fn=...)`
     in `metric_tolerances`.

6. **Non‑decorator usage**
   - `test_validation_non_decorator_class_vs_class_torch` demonstrates calling
     `compare_to_torch` in a more manual, non‑decorator style between two
     callable classes.

## Default Metrics and Tolerances

When `metric_tolerances` is omitted, the framework uses sensible defaults:

- `Metric.MAX_ABS_ERROR` with tolerance `1e-2`
- `Metric.PCC` with tolerance `0.99`

If you pass a `metric_tolerances` dict, keys can be:

- `Metric` enum members (recommended), e.g. `Metric.MAX_ABS_ERROR`
- strings (`"max_abs_error"`, `"mean_abs_error"`, `"pcc"`)
- arbitrary names when used with `MetricSpec`

Values can be:

- a float tolerance (uses the built‑in metric)
- a `MetricSpec` instance to define a custom metric and tolerance

Example:

```python
from models.common.validation_tools import Metric, MetricSpec
from models.common.metrics import compute_pcc


@compare_to_torch(
    reference_fn=torch.matmul,
    metric_tolerances={
        Metric.PCC: MetricSpec(tolerance=0.99, higher_is_better=True, compute_fn=compute_pcc),
        Metric.MAX_ABS_ERROR: 1.5e-1,
    },
)
def ttnn_matmul_metric_spec(a, b):
    return ttnn.matmul(a, b)
```

## Testing

The local test suite in `models/common/tests` shows end‑to‑end usage:

- `test_validation_tools.py`
  - Core decorator usage, registry behaviour, error handling, custom metrics.
- `test_metrics.py`
  - Numerical correctness of device and host metric functions.
- `host/test_metrics_pytorch_only.py`
  - Pure‑PyTorch metric tests.
- `test_auto_compose.py`
  - Auto‑composition of sharded/replicated TTNN tensors into PyTorch.
- `test_distribute_as.py`
  - Distribution helpers (`from_torch_dist_as`) that mirror an existing TTNN
    tensor’s topology.

Example commands (run from the repo root, with TTNN available):

```bash
python -m pytest models/common/tests/test_validation_tools.py -v
python -m pytest models/common/tests/test_metrics.py -v
python -m pytest models/common/tests/host/test_metrics_pytorch_only.py -v
```

## API Reference (public surface)

All symbols below are imported from `models.common.validation_tools` and `models.common.metrics`:

- Decorators:
  - `compare_to_torch`
  - `compare_to_ttnn`
- Registry and control:
  - `ValidationResult`
  - `ValidationRegistry`
  - `get_validation_registry`
  - `enable_validation`
  - `clear_validation_results`
- Metrics:
  - `Metric` (enum: `MAX_ABS_ERROR`, `MEAN_ABS_ERROR`, `PCC`)
  - `MetricSpec`
  - `compute_max_abs_error`
  - `compute_mean_abs_error`
  - `compute_pcc`
  - `comp_allclose`
  - `DEFAULT_METRICS`
- Auto‑compose:
  - `to_torch_auto_compose`

For concrete, runnable examples of each API, see the tests listed at the top
of this document.