|
| 1 | +# Copyright (c) 2026, Alibaba Group; |
| 2 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | +# you may not use this file except in compliance with the License. |
| 4 | +# You may obtain a copy of the License at |
| 5 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | +# Unless required by applicable law or agreed to in writing, software |
| 7 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 8 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 9 | +# See the License for the specific language governing permissions and |
| 10 | +# limitations under the License. |
| 11 | + |
| 12 | +import torch |
| 13 | +from torchmetrics import Metric |
| 14 | + |
| 15 | + |
| 16 | +class UniqueRatio(Metric): |
| 17 | + """Codebook-coverage metric: mean of per-batch (unique rows / batch size). |
| 18 | +
|
| 19 | + Each ``update`` counts the unique rows of a ``(B, n_layers)`` semantic-ID |
| 20 | + code tensor and accumulates the per-batch ratio; ``compute`` returns the |
| 21 | + running mean. Empty batches (``B == 0``, e.g. an empty final DDP/TorchRec |
| 22 | + shard) are skipped. States reduce by ``sum`` across ranks. |
| 23 | + """ |
| 24 | + |
| 25 | + higher_is_better = True |
| 26 | + is_differentiable = False |
| 27 | + |
| 28 | + def __init__(self, **kwargs) -> None: |
| 29 | + super().__init__(**kwargs) |
| 30 | + self.add_state("ratio_sum", default=torch.tensor(0.0), dist_reduce_fx="sum") |
| 31 | + self.add_state("count", default=torch.tensor(0.0), dist_reduce_fx="sum") |
| 32 | + |
| 33 | + def update(self, codes: torch.Tensor) -> None: |
| 34 | + """Accumulate the unique-ratio of one batch of codes. |
| 35 | +
|
| 36 | + Args: |
| 37 | + codes (Tensor): semantic-ID codes, shape (B, n_layers). |
| 38 | + """ |
| 39 | + batch_size = codes.shape[0] |
| 40 | + if batch_size == 0: |
| 41 | + return |
| 42 | + unique = torch.unique(codes, dim=0).shape[0] |
| 43 | + self.ratio_sum += unique / batch_size |
| 44 | + self.count += 1 |
| 45 | + |
| 46 | + def compute(self) -> torch.Tensor: |
| 47 | + """Mean per-batch unique ratio (NaN before any non-empty update).""" |
| 48 | + return self.ratio_sum / self.count |
0 commit comments