Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the ndcg metric [WIP] #2632

Draft
wants to merge 38 commits into
base: master
Choose a base branch
from
Draft
Changes from 6 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
cd6ec7f
Added the ndcg metric [WIP]
kamalojasv181 Jul 23, 2022
6421879
Merge branch 'master' into ndcg
kamalojasv181 Jul 23, 2022
4535af1
added GPU support, corrected mypy errors, and minor fixes
kamalojasv181 Jul 23, 2022
eb73c99
Merge branch 'ndcg' of https://github.com/kamalojasv181/ignite into ndcg
kamalojasv181 Jul 23, 2022
70d06e5
Incorporated the suggested changes
kamalojasv181 Jul 24, 2022
6a86f5f
Fixed mypy error
kamalojasv181 Jul 24, 2022
7b7ed6f
Fixed bugs in NDCG and added tests for output and reset
kamalojasv181 Jul 24, 2022
2c87ee1
Fixed mypy error
kamalojasv181 Jul 24, 2022
f4c628a
Added the exponential form on https://en.wikipedia.org/wiki/Discounte…
kamalojasv181 Jul 25, 2022
e72b59e
Corrected true, pred order and corresponding tests
kamalojasv181 Jul 25, 2022
ef63d85
Added ties case, exponential tests, log_base tests, corresponding tes…
kamalojasv181 Jul 26, 2022
115501b
Added GPU check on top
kamalojasv181 Jul 26, 2022
189b579
Put tensors on GPU inside the function to pervent error
kamalojasv181 Jul 26, 2022
c509456
Improved tests and minor bugfixes
kamalojasv181 Jul 27, 2022
84900f0
Removed device hyperparam from _ndcg_smaple_scores
kamalojasv181 Jul 27, 2022
9bfc06e
Skipped GPU tests for CPU only systems
kamalojasv181 Jul 27, 2022
477e096
Changed Error message
kamalojasv181 Jul 27, 2022
44329d7
Merge branch 'master' of https://github.com/pytorch/ignite into ndcg
kamalojasv181 Aug 27, 2022
5ba7fb7
Merge branch 'pytorch:master' into ndcg
kamalojasv181 Aug 27, 2022
ac800ff
Made tests randomised from deterministic and introduced ignore_ties_f…
kamalojasv181 Aug 27, 2022
691e89a
Merge branch 'ndcg' of https://github.com/kamalojasv181/ignite into ndcg
kamalojasv181 Aug 27, 2022
962bcef
Merge branch 'master' of https://github.com/pytorch/ignite into ndcg
kamalojasv181 Aug 29, 2022
79979cc
Merge branch 'pytorch:master' into ndcg
kamalojasv181 Aug 29, 2022
0c1d6fd
Changed test name to test_output_cuda from test_output_gpu
kamalojasv181 Aug 29, 2022
85cdcaf
Merge branch 'ndcg' of https://github.com/kamalojasv181/ignite into ndcg
kamalojasv181 Aug 29, 2022
fdf7877
Merge branch 'master' into ndcg
kamalojasv181 Aug 29, 2022
2931d20
Changed variable names to replacement and ignore_ties and removed red…
kamalojasv181 Aug 30, 2022
c308e41
Changed variable names to replacement and ignore_ties and removed red…
kamalojasv181 Aug 30, 2022
95ede6c
Merge branch 'master' of https://github.com/pytorch/ignite into ndcg
kamalojasv181 Aug 30, 2022
3a4d2af
Merge branch 'ndcg' of https://github.com/kamalojasv181/ignite into ndcg
kamalojasv181 Aug 30, 2022
6e66273
Removed redundant test cases and removed the redundant if statement
kamalojasv181 Aug 30, 2022
eb75afa
Added distributed tests, added multiple test cases corresponding to o…
kamalojasv181 Aug 30, 2022
dcf276d
Made the tests wsork on in ddp configuration
kamalojasv181 Aug 31, 2022
cb273e7
Merge branch 'master' of https://github.com/pytorch/ignite into ndcg
kamalojasv181 Aug 31, 2022
b0f449b
Merge branch 'pytorch:master' into ndcg
kamalojasv181 Aug 31, 2022
388db23
Merge branch 'ndcg' of https://github.com/kamalojasv181/ignite into ndcg
kamalojasv181 Aug 31, 2022
b3b6b28
Merge branch 'pytorch:master' into ndcg
kamalojasv181 Sep 1, 2022
6dcf3b2
Returning tuple of two tensors instead of tuple of list of tensors
kamalojasv181 Sep 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions ignite/metrics/ndcg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from typing import Callable, Optional, Sequence, Union
vfdev-5 marked this conversation as resolved.
Show resolved Hide resolved

import torch

from ignite.exceptions import NotComputableError
from ignite.metrics.metric import Metric

__all__ = ["NDCG"]


class NDCG(Metric):
def __init__(
self,
output_transform: Callable = lambda x: x,
device: Union[str, torch.device] = torch.device("cpu"),
k: Optional[int] = None,
log_base: Union[int, float] = 2,
vfdev-5 marked this conversation as resolved.
Show resolved Hide resolved
):

self.log_base = log_base

self.k = k

super(NDCG, self).__init__(output_transform=output_transform, device=device)
vfdev-5 marked this conversation as resolved.
Show resolved Hide resolved

def _dcg_sample_scores(
vfdev-5 marked this conversation as resolved.
Show resolved Hide resolved
self, y_true: torch.Tensor, y_score: torch.Tensor, k: Optional[int] = None, log_base: Union[int, float] = 2
) -> torch.Tensor:

discount = (
torch.div(torch.log(torch.arange(y_true.shape[1]) + 2), torch.log(torch.tensor(log_base)))
.pow(-1)
.to(self._device)
)

if k is not None:
discount[k:] = 0

ranking = torch.argsort(y_score, descending=True)

ranked = torch.zeros(y_score.shape, dtype=y_score.dtype, device=self._device)
ranked = ranked.scatter_(1, ranking, y_true)

discounted_gains = torch.mm(ranked, discount.reshape(-1, 1))

return discounted_gains

def _ndcg_sample_scores(
self, y_true: torch.Tensor, y_score: torch.Tensor, k: Optional[int] = None, log_base: Union[int, float] = 2
) -> torch.Tensor:

gain = self._dcg_sample_scores(y_true, y_score, k, log_base=log_base)

normalizing_gain = self._dcg_sample_scores(y_true, y_true, k, log_base=log_base)

all_relevant = normalizing_gain != 0

normalized_gain = torch.div(gain[all_relevant], normalizing_gain[all_relevant])

return normalized_gain

def reset(self) -> None:

self.num_examples = 0
self.ngcd = torch.tensor(0.0, device=self._device)

def update(self, output: Sequence[torch.Tensor]) -> None:

y_pred, y = output[0].detach(), output[1].detach()

gain = self._ndcg_sample_scores(y, y_pred, k=self.k, log_base=self.log_base)

self.ngcd += torch.sum(gain)

self.num_examples += y_pred.shape[0]

def compute(self) -> float:
if self.num_examples == 0:
raise NotComputableError("NGCD must have at least one example before it can be computed.")

return (self.ngcd / self.num_examples).item()