torchsight.metrics.retrieval
module
Module with metrics for retrievals tasks.
Source code
"""Module with metrics for retrievals tasks."""
import torch
class AveragePrecision():
"""Computes the average precision in a retrieval task.
What's the difference with the mAP of an object detection task? Because here we use a different formula,
we use the one indicated here:
https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Average_precision
"""
averages = [] # List of Average Precisions computed by this metric
def __call__(self, results, relevant=None):
"""Compute the Average Precision for each query.
The results tensor must have shape `(q, r)` where `q` is the number of queries
and `r` is the number of results per query. The results must be labeled with a `1`
when are correct (or relevant) and ordered in descendant order.
Example:
A tensor like:
```
[[1., 1., 0., 1.],
[0., 1., 0., 0.]]
```
has `2` queries with `4` results. The first result for the first query is correct
but the first result for the second query is incorrect. The first query has 3 correct
results and the second query only one.
Arguments:
results (torch.Tensor): the ordered results of the queries labeled as correct
with a 1.
relevant (torch.Tensor, optional): the amount of relevant results for each query.
If it's not provided it will assume that in the results are all the relevant
results, so it can be computed by `results.sum(dim=1)`.
Returns:
torch.Tensor: with the average precision of each query.
"""
if len(results.shape) == 1:
results = results.unsqueeze(dim=0)
if len(results.shape) != 2:
raise ValueError('"results" can only be a tensor of shape (q, r).')
# Get the number of relevant results
if relevant is None:
relevant = results.sum(dim=1) # (q, 1)
if (relevant == 0).sum() >= 1:
raise ValueError('There are queries without relevant results and could generate NaN results.')
# Get the precision @k for each k in r
precision = torch.zeros_like(results) # (q, r)
for k in range(1, results.shape[1] + 1):
precision[:, k - 1] = results[:, :k].sum(dim=1) / k # (q,)
# Set as zero the precision when the k-th element was not relevant
precision[results != 1] = 0
# Get the average precision for each query
avg = precision.sum(dim=1) / relevant # (q,)
self.averages.append(avg)
return avg
def mean(self):
"""Compute the mean average precision based on the past average precision computed
stored in the self.averages list.
Returns:
torch.Tensor: with shape `(1,)` with the mean of the average precisions computed.
"""
return torch.cat(self.averages).mean()
Classes
class AveragePrecision
-
Computes the average precision in a retrieval task.
What's the difference with the mAP of an object detection task? Because here we use a different formula, we use the one indicated here: https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Average_precision
Source code
class AveragePrecision(): """Computes the average precision in a retrieval task. What's the difference with the mAP of an object detection task? Because here we use a different formula, we use the one indicated here: https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Average_precision """ averages = [] # List of Average Precisions computed by this metric def __call__(self, results, relevant=None): """Compute the Average Precision for each query. The results tensor must have shape `(q, r)` where `q` is the number of queries and `r` is the number of results per query. The results must be labeled with a `1` when are correct (or relevant) and ordered in descendant order. Example: A tensor like: ``` [[1., 1., 0., 1.], [0., 1., 0., 0.]] ``` has `2` queries with `4` results. The first result for the first query is correct but the first result for the second query is incorrect. The first query has 3 correct results and the second query only one. Arguments: results (torch.Tensor): the ordered results of the queries labeled as correct with a 1. relevant (torch.Tensor, optional): the amount of relevant results for each query. If it's not provided it will assume that in the results are all the relevant results, so it can be computed by `results.sum(dim=1)`. Returns: torch.Tensor: with the average precision of each query. """ if len(results.shape) == 1: results = results.unsqueeze(dim=0) if len(results.shape) != 2: raise ValueError('"results" can only be a tensor of shape (q, r).') # Get the number of relevant results if relevant is None: relevant = results.sum(dim=1) # (q, 1) if (relevant == 0).sum() >= 1: raise ValueError('There are queries without relevant results and could generate NaN results.') # Get the precision @k for each k in r precision = torch.zeros_like(results) # (q, r) for k in range(1, results.shape[1] + 1): precision[:, k - 1] = results[:, :k].sum(dim=1) / k # (q,) # Set as zero the precision when the k-th element was not relevant precision[results != 1] = 0 # Get the average precision for each query avg = precision.sum(dim=1) / relevant # (q,) self.averages.append(avg) return avg def mean(self): """Compute the mean average precision based on the past average precision computed stored in the self.averages list. Returns: torch.Tensor: with shape `(1,)` with the mean of the average precisions computed. """ return torch.cat(self.averages).mean()
Class variables
var averages
Methods
def mean(self)
-
Compute the mean average precision based on the past average precision computed stored in the self.averages list.
Returns
torch.Tensor: with shape
(1,)
with the mean of the average precisions computed.Source code
def mean(self): """Compute the mean average precision based on the past average precision computed stored in the self.averages list. Returns: torch.Tensor: with shape `(1,)` with the mean of the average precisions computed. """ return torch.cat(self.averages).mean()