pyg-nightly 2.7.0.dev20250206__py3-none-any.whl → 2.7.0.dev20250208__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyg-nightly
3
- Version: 2.7.0.dev20250206
3
+ Version: 2.7.0.dev20250208
4
4
  Summary: Graph Neural Network Library for PyTorch
5
5
  Keywords: deep-learning,pytorch,geometric-deep-learning,graph-neural-networks,graph-convolutional-networks
6
6
  Author-email: Matthias Fey <matthias@pyg.org>
@@ -1,4 +1,4 @@
1
- torch_geometric/__init__.py,sha256=YRPiIO7ws7RIgUmJ-pamZ1ePmFmWSCBpTtTWmYrzv7k,1904
1
+ torch_geometric/__init__.py,sha256=xs18p-86SDSyeHiH_4BXNgCg3hZ9F3aP-Swz2mVgRz0,1904
2
2
  torch_geometric/_compile.py,sha256=f-WQeH4VLi5Hn9lrgztFUCSrN_FImjhQa6BxFzcYC38,1338
3
3
  torch_geometric/_onnx.py,sha256=V9ffrIKSqhDw6xUZ12lkuSfNs48cQp2EeJ6Z19GfnVw,349
4
4
  torch_geometric/backend.py,sha256=lVaf7aLoVaB3M-UcByUJ1G4T4FOK6LXAg0CF4W3E8jo,1575
@@ -7,7 +7,7 @@ torch_geometric/config_store.py,sha256=zdMzlgBpUmBkPovpYQh5fMNwTZLDq2OneqX47QEx7
7
7
  torch_geometric/debug.py,sha256=cLyH9OaL2v7POyW-80b19w-ctA7a_5EZsS4aUF1wc2U,1295
8
8
  torch_geometric/deprecation.py,sha256=dWRymDIUkUVI2MeEmBG5WF4R6jObZeseSBV9G6FNfjc,858
9
9
  torch_geometric/device.py,sha256=tU5-_lBNVbVHl_kUmWPwiG5mQ1pyapwMF4JkmtNN3MM,1224
10
- torch_geometric/edge_index.py,sha256=r4_24Rhm3YCK0BF-kzLvL7PlY_1tWcXrBDIr7JPDjkw,70048
10
+ torch_geometric/edge_index.py,sha256=BsLh5tOZRjjSYDkjqOFAdBuvMaDg7EWaaLELYsUL0Z8,70048
11
11
  torch_geometric/experimental.py,sha256=JbtNNEXjFGI8hZ9raM6-qrZURP6Z5nlDK8QicZUIbz0,4756
12
12
  torch_geometric/home.py,sha256=EV54B4Dmiv61GDbkCwtCfWGWJ4eFGwZ8s3KOgGjwYgY,790
13
13
  torch_geometric/index.py,sha256=9ChzWFCwj2slNcVBOgfV-wQn-KscJe_y7502w-Vf76w,24045
@@ -288,8 +288,8 @@ torch_geometric/loader/shadow.py,sha256=_hCspYf9SlJYX0lqEjxFec9e9t1iMScNThOoWR1w
288
288
  torch_geometric/loader/temporal_dataloader.py,sha256=AQ2QFeiXKbPp6I8sUeE8H7br-1_yndivXt7Z6_w62zI,2248
289
289
  torch_geometric/loader/utils.py,sha256=f27mczQ7fEP2HpTsJGJxKS0slPu0j8zTba3jP8ViNck,14901
290
290
  torch_geometric/loader/zip_loader.py,sha256=3lt10fD15Rxm1WhWzypswGzCEwUz4h8OLCD1nE15yNg,3843
291
- torch_geometric/metrics/__init__.py,sha256=Ck-rqQOGoKYRNSI95zlsTtQKVN4ZJGDaYYTMeSOjvvU,435
292
- torch_geometric/metrics/link_pred.py,sha256=dEsKVrjJ3OYnDbeDxowMNTCQMjKdgj-Xsh0L2VY5hLo,18563
291
+ torch_geometric/metrics/__init__.py,sha256=9gPEg0_oMfq7LAr5rsrebasnvYN9nDXwq2ML56lWcMo,529
292
+ torch_geometric/metrics/link_pred.py,sha256=H-s9U9n2CKpj9pRQWG9KdTZ0jueds1iy7hr893BmGoE,23121
293
293
  torch_geometric/nn/__init__.py,sha256=RrWRzEoqtR3lsO2lAzYXboLPb3uYEX2z3tLxiBIVWjc,847
294
294
  torch_geometric/nn/data_parallel.py,sha256=lDAxRi83UNuzAQSj3eu9K2sQheOIU6wqR5elS6oDs90,4764
295
295
  torch_geometric/nn/encoding.py,sha256=QNjwWczYExZ1wRGBmpuqYbn6tB7NC4BU-DEgzjhcZqw,3115
@@ -630,6 +630,6 @@ torch_geometric/utils/undirected.py,sha256=H_nfpI0_WluOG6VfjPyldvcjL4w5USAKWu2x5
630
630
  torch_geometric/visualization/__init__.py,sha256=PyR_4K5SafsJrBr6qWrkjKr6GBL1b7FtZybyXCDEVwY,154
631
631
  torch_geometric/visualization/graph.py,sha256=ZuLPL92yGRi7lxlqsUPwL_EVVXF7P2kMcveTtW79vpA,4784
632
632
  torch_geometric/visualization/influence.py,sha256=CWMvuNA_Nf1sfbJmQgn58yS4OFpeKXeZPe7kEuvkUBw,477
633
- pyg_nightly-2.7.0.dev20250206.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
634
- pyg_nightly-2.7.0.dev20250206.dist-info/METADATA,sha256=KnKyWFmumAGBhzhyA643F5d0-IMruzDX0VRCAosZ3qY,62977
635
- pyg_nightly-2.7.0.dev20250206.dist-info/RECORD,,
633
+ pyg_nightly-2.7.0.dev20250208.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
634
+ pyg_nightly-2.7.0.dev20250208.dist-info/METADATA,sha256=Jmer8BBk_bwb3Zs2JdZLAoVFNv_uQRoH_N9JxVAJQ_U,62977
635
+ pyg_nightly-2.7.0.dev20250208.dist-info/RECORD,,
@@ -30,7 +30,7 @@ from .lazy_loader import LazyLoader
30
30
  contrib = LazyLoader('contrib', globals(), 'torch_geometric.contrib')
31
31
  graphgym = LazyLoader('graphgym', globals(), 'torch_geometric.graphgym')
32
32
 
33
- __version__ = '2.7.0.dev20250206'
33
+ __version__ = '2.7.0.dev20250208'
34
34
 
35
35
  __all__ = [
36
36
  'Index',
@@ -183,7 +183,7 @@ class EdgeIndex(Tensor):
183
183
 
184
184
  edge_index = EdgeIndex(
185
185
  [[0, 1, 1, 2],
186
- [1, 0, 2, 1]]
186
+ [1, 0, 2, 1]],
187
187
  sparse_size=(3, 3),
188
188
  sort_order='row',
189
189
  is_undirected=True,
@@ -210,7 +210,7 @@ class EdgeIndex(Tensor):
210
210
  assert not edge_index.is_undirected
211
211
 
212
212
  # Sparse-Dense Matrix Multiplication:
213
- out = edge_index.flip(0) @ torch.randn(3, 16)
213
+ out = edge_index.flip(0) @ torch.randn(3, 16)
214
214
  assert out.size() == (3, 16)
215
215
  """
216
216
  # See "https://pytorch.org/docs/stable/notes/extending.html"
@@ -9,6 +9,8 @@ from .link_pred import (
9
9
  LinkPredMAP,
10
10
  LinkPredNDCG,
11
11
  LinkPredMRR,
12
+ LinkPredCoverage,
13
+ LinkPredDiversity,
12
14
  )
13
15
 
14
16
  link_pred_metrics = [
@@ -20,6 +22,8 @@ link_pred_metrics = [
20
22
  'LinkPredMAP',
21
23
  'LinkPredNDCG',
22
24
  'LinkPredMRR',
25
+ 'LinkPredCoverage',
26
+ 'LinkPredDiversity',
23
27
  ]
24
28
 
25
29
  __all__ = link_pred_metrics
@@ -138,7 +138,7 @@ class LinkPredMetricData:
138
138
  return pos
139
139
 
140
140
 
141
- class LinkPredMetric(BaseMetric):
141
+ class _LinkPredMetric(BaseMetric):
142
142
  r"""An abstract class for computing link prediction retrieval metrics.
143
143
 
144
144
  Args:
@@ -147,7 +147,6 @@ class LinkPredMetric(BaseMetric):
147
147
  is_differentiable: bool = False
148
148
  full_state_update: bool = False
149
149
  higher_is_better: Optional[bool] = None
150
- weighted: bool
151
150
 
152
151
  def __init__(self, k: int) -> None:
153
152
  super().__init__()
@@ -158,16 +157,6 @@ class LinkPredMetric(BaseMetric):
158
157
 
159
158
  self.k = k
160
159
 
161
- self.accum: Tensor
162
- self.total: Tensor
163
-
164
- if WITH_TORCHMETRICS:
165
- self.add_state('accum', torch.tensor(0.), dist_reduce_fx='sum')
166
- self.add_state('total', torch.tensor(0), dist_reduce_fx='sum')
167
- else:
168
- self.register_buffer('accum', torch.tensor(0.))
169
- self.register_buffer('total', torch.tensor(0))
170
-
171
160
  def update(
172
161
  self,
173
162
  pred_index_mat: Tensor,
@@ -194,6 +183,53 @@ class LinkPredMetric(BaseMetric):
194
183
  a vector of positive values. Required for weighted metrics,
195
184
  ignored otherwise. (default: :obj:`None`)
196
185
  """
186
+ raise NotImplementedError
187
+
188
+ def compute(self) -> Tensor:
189
+ r"""Computes the final metric value."""
190
+ raise NotImplementedError
191
+
192
+ def reset(self) -> None:
193
+ r"""Resets metric state variables to their default value."""
194
+ if WITH_TORCHMETRICS:
195
+ super().reset()
196
+ else:
197
+ self._reset()
198
+
199
+ def _reset(self) -> None:
200
+ raise NotImplementedError
201
+
202
+ def __repr__(self) -> str:
203
+ return f'{self.__class__.__name__}(k={self.k})'
204
+
205
+
206
+ class LinkPredMetric(_LinkPredMetric):
207
+ r"""An abstract class for computing link prediction retrieval metrics.
208
+
209
+ Args:
210
+ k (int): The number of top-:math:`k` predictions to evaluate against.
211
+ """
212
+ weighted: bool
213
+
214
+ def __init__(self, k: int) -> None:
215
+ super().__init__(k)
216
+
217
+ self.accum: Tensor
218
+ self.total: Tensor
219
+
220
+ if WITH_TORCHMETRICS:
221
+ self.add_state('accum', torch.tensor(0.), dist_reduce_fx='sum')
222
+ self.add_state('total', torch.tensor(0), dist_reduce_fx='sum')
223
+ else:
224
+ self.register_buffer('accum', torch.tensor(0.))
225
+ self.register_buffer('total', torch.tensor(0))
226
+
227
+ def update(
228
+ self,
229
+ pred_index_mat: Tensor,
230
+ edge_label_index: Union[Tensor, Tuple[Tensor, Tensor]],
231
+ edge_label_weight: Optional[Tensor] = None,
232
+ ) -> None:
197
233
  if self.weighted and edge_label_weight is None:
198
234
  raise ValueError(f"'edge_label_weight' is a required argument for "
199
235
  f"weighted '{self.__class__.__name__}' metrics")
@@ -214,19 +250,10 @@ class LinkPredMetric(BaseMetric):
214
250
  self.total += (data.label_count > 0).sum()
215
251
 
216
252
  def compute(self) -> Tensor:
217
- r"""Computes the final metric value."""
218
253
  if self.total == 0:
219
254
  return torch.zeros_like(self.accum)
220
255
  return self.accum / self.total
221
256
 
222
- def reset(self) -> None:
223
- r"""Resets metric state variables to their default value."""
224
- if WITH_TORCHMETRICS:
225
- super().reset()
226
- else:
227
- self.accum.zero_()
228
- self.total.zero_()
229
-
230
257
  def _compute(self, data: LinkPredMetricData) -> Tensor:
231
258
  r"""Computes the specific metric.
232
259
  To be implemented separately for each metric class.
@@ -237,6 +264,10 @@ class LinkPredMetric(BaseMetric):
237
264
  """
238
265
  raise NotImplementedError
239
266
 
267
+ def _reset(self) -> None:
268
+ self.accum.zero_()
269
+ self.total.zero_()
270
+
240
271
  def __repr__(self) -> str:
241
272
  weighted_repr = ', weighted=True' if self.weighted else ''
242
273
  return f'{self.__class__.__name__}(k={self.k}{weighted_repr})'
@@ -284,7 +315,7 @@ class LinkPredMetricCollection(torch.nn.ModuleDict):
284
315
 
285
316
  if isinstance(metrics, (list, tuple)):
286
317
  metrics = {
287
- (f'{"Weighted" if metric.weighted else ""}'
318
+ (f'{"Weighted" if getattr(metric, "weighted", False) else ""}'
288
319
  f'{metric.__class__.__name__}@{metric.k}'):
289
320
  metric
290
321
  for metric in metrics
@@ -293,6 +324,7 @@ class LinkPredMetricCollection(torch.nn.ModuleDict):
293
324
  assert isinstance(metrics, dict)
294
325
 
295
326
  for name, metric in metrics.items():
327
+ assert isinstance(metric, _LinkPredMetric)
296
328
  self[name] = metric
297
329
 
298
330
  @property
@@ -307,7 +339,8 @@ class LinkPredMetricCollection(torch.nn.ModuleDict):
307
339
  r"""Returns :obj:`True` in case the collection holds at least one
308
340
  weighted link prediction metric.
309
341
  """
310
- return any([metric.weighted for metric in self.values()])
342
+ return any(
343
+ [getattr(metric, 'weighted', False) for metric in self.values()])
311
344
 
312
345
  def update( # type: ignore
313
346
  self,
@@ -348,7 +381,7 @@ class LinkPredMetricCollection(torch.nn.ModuleDict):
348
381
  )
349
382
 
350
383
  for metric in self.values():
351
- if metric.weighted:
384
+ if isinstance(metric, LinkPredMetric) and metric.weighted:
352
385
  metric._update(data)
353
386
  if WITH_TORCHMETRICS:
354
387
  metric._update_count += 1
@@ -362,11 +395,19 @@ class LinkPredMetricCollection(torch.nn.ModuleDict):
362
395
  del data._edge_label_weight_pos
363
396
 
364
397
  for metric in self.values():
365
- if not metric.weighted:
398
+ if isinstance(metric, LinkPredMetric) and not metric.weighted:
366
399
  metric._update(data)
367
400
  if WITH_TORCHMETRICS:
368
401
  metric._update_count += 1
369
402
 
403
+ for metric in self.values():
404
+ if not isinstance(metric, LinkPredMetric):
405
+ metric.update(
406
+ pred_index_mat=pred_index_mat,
407
+ edge_label_index=edge_label_index,
408
+ edge_label_weight=edge_label_weight,
409
+ )
410
+
370
411
  def compute(self) -> Dict[str, Tensor]:
371
412
  r"""Computes the final metric values."""
372
413
  return {name: metric.compute() for name, metric in self.items()}
@@ -521,3 +562,108 @@ class LinkPredMRR(LinkPredMetric):
521
562
  device = pred_rel_mat.device
522
563
  arange = torch.arange(1, pred_rel_mat.size(1) + 1, device=device)
523
564
  return (pred_rel_mat / arange).max(dim=-1)[0]
565
+
566
+
567
+ class LinkPredCoverage(_LinkPredMetric):
568
+ r"""A link prediction metric to compute the Coverage @ :math:`k` of
569
+ predictions.
570
+
571
+ Args:
572
+ k (int): The number of top-:math:`k` predictions to evaluate against.
573
+ num_dst_nodes (int): The total number of destination nodes.
574
+ """
575
+ higher_is_better: bool = True
576
+
577
+ def __init__(self, k: int, num_dst_nodes: int) -> None:
578
+ super().__init__(k)
579
+ self.num_dst_nodes = num_dst_nodes
580
+
581
+ self.mask: Tensor
582
+ mask = torch.zeros(num_dst_nodes, dtype=torch.bool)
583
+ if WITH_TORCHMETRICS:
584
+ self.add_state('mask', mask, dist_reduce_fx='max')
585
+ else:
586
+ self.register_buffer('mask', mask)
587
+
588
+ def update(
589
+ self,
590
+ pred_index_mat: Tensor,
591
+ edge_label_index: Union[Tensor, Tuple[Tensor, Tensor]],
592
+ edge_label_weight: Optional[Tensor] = None,
593
+ ) -> None:
594
+ self.mask[pred_index_mat[:, :self.k].flatten()] = True
595
+
596
+ def compute(self) -> Tensor:
597
+ return self.mask.to(torch.get_default_dtype()).mean()
598
+
599
+ def _reset(self) -> None:
600
+ self.mask.zero_()
601
+
602
+ def __repr__(self) -> str:
603
+ return (f'{self.__class__.__name__}(k={self.k}, '
604
+ f'num_dst_nodes={self.num_dst_nodes})')
605
+
606
+
607
+ class LinkPredDiversity(_LinkPredMetric):
608
+ r"""A link prediction metric to compute the Diversity @ :math:`k` of
609
+ predictions according to item categories.
610
+
611
+ Diversity is computed as
612
+
613
+ .. math::
614
+ div_{u@k} = 1 - \left( \frac{1}{k \cdot (k-1)} \right) \sum_{i \neq j}
615
+ sim(i, j)
616
+
617
+ where
618
+
619
+ .. math::
620
+ sim(i,j) = \begin{cases}
621
+ 1 & \quad \text{if } i,j \text{ share category,}\\
622
+ 0 & \quad \text{otherwise.}
623
+ \end{cases}
624
+
625
+ which measures the pair-wise inequality of recommendations according to
626
+ item categories.
627
+
628
+ Args:
629
+ k (int): The number of top-:math:`k` predictions to evaluate against.
630
+ category (torch.Tensor): A vector that assigns each destination node to
631
+ a specific category.
632
+ """
633
+ higher_is_better: bool = True
634
+
635
+ def __init__(self, k: int, category: Tensor) -> None:
636
+ super().__init__(k)
637
+
638
+ if WITH_TORCHMETRICS:
639
+ self.add_state('accum', torch.tensor(0.), dist_reduce_fx='sum')
640
+ self.add_state('total', torch.tensor(0), dist_reduce_fx='sum')
641
+ else:
642
+ self.register_buffer('accum', torch.tensor(0.))
643
+ self.register_buffer('total', torch.tensor(0))
644
+
645
+ self.category: Tensor
646
+ self.register_buffer('category', category)
647
+
648
+ def update(
649
+ self,
650
+ pred_index_mat: Tensor,
651
+ edge_label_index: Union[Tensor, Tuple[Tensor, Tensor]],
652
+ edge_label_weight: Optional[Tensor] = None,
653
+ ) -> None:
654
+ category = self.category[pred_index_mat[:, :self.k]]
655
+
656
+ sim = (category.unsqueeze(-2) == category.unsqueeze(-1)).sum(dim=-1)
657
+ div = 1 - 1 / (self.k * (self.k - 1)) * (sim - 1).sum(dim=-1)
658
+
659
+ self.accum += div.sum()
660
+ self.total += pred_index_mat.size(0)
661
+
662
+ def compute(self) -> Tensor:
663
+ if self.total == 0:
664
+ return torch.zeros_like(self.accum)
665
+ return self.accum / self.total
666
+
667
+ def _reset(self) -> None:
668
+ self.accum.zero_()
669
+ self.total.zero_()