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.
- {pyg_nightly-2.7.0.dev20250206.dist-info → pyg_nightly-2.7.0.dev20250208.dist-info}/METADATA +1 -1
- {pyg_nightly-2.7.0.dev20250206.dist-info → pyg_nightly-2.7.0.dev20250208.dist-info}/RECORD +7 -7
- torch_geometric/__init__.py +1 -1
- torch_geometric/edge_index.py +2 -2
- torch_geometric/metrics/__init__.py +4 -0
- torch_geometric/metrics/link_pred.py +171 -25
- {pyg_nightly-2.7.0.dev20250206.dist-info → pyg_nightly-2.7.0.dev20250208.dist-info}/WHEEL +0 -0
{pyg_nightly-2.7.0.dev20250206.dist-info → pyg_nightly-2.7.0.dev20250208.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: pyg-nightly
|
3
|
-
Version: 2.7.0.
|
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=
|
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=
|
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=
|
292
|
-
torch_geometric/metrics/link_pred.py,sha256=
|
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.
|
634
|
-
pyg_nightly-2.7.0.
|
635
|
-
pyg_nightly-2.7.0.
|
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,,
|
torch_geometric/__init__.py
CHANGED
@@ -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.
|
33
|
+
__version__ = '2.7.0.dev20250208'
|
34
34
|
|
35
35
|
__all__ = [
|
36
36
|
'Index',
|
torch_geometric/edge_index.py
CHANGED
@@ -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) @
|
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
|
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
|
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(
|
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_()
|
File without changes
|