clef / code /models /common /README.md
tt-hous's picture
Add files using upload-large-folder tool
be3ecc8 verified
|
Raw History Blame Contribute Delete
11.7 kB
# 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.