Repository: pyg-team/pytorch_geometric (python)

Issue:
TypeError: 'list' object is not callable
### 🐛 Describe the bug

```python
from torch.nn import Linear, ReLU, Dropout
from torch_geometric.nn import Sequential, GCNConv, JumpingKnowledge
from torch_geometric.nn import global_mean_pool

model = Sequential('x, edge_index, batch', [
    (Dropout(p=0.5), 'x -> x'),
    (GCNConv(2, 64), 'x, edge_index -> x1'),
    ReLU(inplace=True),
    (GCNConv(64, 64), 'x1, edge_index -> x2'),
    ReLU(inplace=True),
    (lambda x1, x2: [x1, x2], 'x1, x2 -> xs'),
    (JumpingKnowledge("cat", 64, num_layers=2), 'xs -> x'),
    (global_mean_pool, 'x, batch -> x'),
    Linear(2 * 64, 3),
]).to('cpu')
```
It throws `TypeError: 'list' object is not callable`

### Versions

PyTorch version: 2.2.2+cu121
Is debug build: False
CUDA used to build PyTorch: 12.1
ROCM used to build PyTorch: N/A

OS: Ubuntu 22.04.3 LTS (x86_64)
GCC version: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Clang version: Could not collect
CMake version: version 3.27.2
Libc version: glibc-2.35

Python version: 3.9.19 | packaged by conda-forge | (main, Mar 20 2024, 12:50:21)  [GCC 12.3.0] (64-bit runtime)
Python platform: Linux-6.2.0-39-generic-x86_64-with-glibc2.35
Is CUDA available: True
CUDA runtime version: 12.4.131
CUDA_MODULE_LOADING set to: LAZY
GPU models and configuration: 
GPU 0: NVIDIA GeForce RTX 3090 Ti
GPU 1: NVIDIA GeForce RTX 3090 Ti

Nvidia driver version: 550.54.14
cuDNN version: Probably one of the following:
/usr/lib/x86_64-linux-gnu/libcudnn.so.8.6.0
/usr/lib/x86_64-linux-gnu/libcudnn_adv_infer.so.8.6.0
/usr/lib/x86_64-linux-gnu/libcudnn_adv_train.so.8.6.0
/usr/lib/x86_64-linux-gnu/libcudnn_cnn_infer.so.8.6.0
/usr/lib/x86_64-linux-gnu/libcudnn_cnn_train.so.8.6.0
/usr/lib/x86_64-linux-gnu/libcudnn_ops_infer.so.8.6.0
/usr/lib/x86_64-linux-gnu/libcudnn_ops_train.so.8.6.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn.so.8.5.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn_adv_infer.so.8.5.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn_adv_train.so.8.5.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn_cnn_infer.so.8.5.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn_cnn_train.so.8.5.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn_ops_infer.so.8.5.0
/usr/local/cuda-11.7/targets/x86_64-linux/lib/libcudnn_ops_train.so.8.5.0
HIP runtime version: N/A
MIOpen runtime version: N/A
Is XNNPACK available: True

CPU:
Architecture:                       x86_64
CPU op-mode(s):                     32-bit, 64-bit
Address sizes:                      43 bits physical, 48 bits virtual
Byte Order:                         Little Endian
CPU(s):                             48
On-line CPU(s) list:                0-47
Vendor ID:                          AuthenticAMD
Model name:                         AMD Ryzen Threadripper 3960X 24-Core Processor
CPU family:                         23
Model:                              49
Thread(s) per core:                 2
Core(s) per socket:                 24
Socket(s):                          1
Stepping:                           0
Frequency boost:                    enabled
CPU max MHz:                        3800.0000
CPU min MHz:                        2200.0000
BogoMIPS:                           7585.68
Flags:                              fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd amd_ppin arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip rdpid overflow_recov succor smca sev sev_es
Virtualization:                     AMD-V
L1d cache:                          768 KiB (24 instances)
L1i cache:                          768 KiB (24 instances)
L2 cache:                           12 MiB (24 instances)
L3 cache:                           128 MiB (8 instances)
NUMA node(s):                       1
NUMA node0 CPU(s):                  0-47
Vulnerability Gather data sampling: Not affected
Vulnerability Itlb multihit:        Not affected
Vulnerability L1tf:                 Not affected
Vulnerability Mds:                  Not affected
Vulnerability Meltdown:             Not affected
Vulnerability Mmio stale data:      Not affected
Vulnerability Retbleed:             Mitigation; untrained return thunk; SMT enabled with STIBP protection
Vulnerability Spec rstack overflow: Mitigation; safe RET
Vulnerability Spec store bypass:    Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:           Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:           Mitigation; Retpolines, IBPB conditional, STIBP always-on, RSB filling, PBRSB-eIBRS Not affected
Vulnerability Srbds:                Not affected
Vulnerability Tsx async abort:      Not affected

Versions of relevant libraries:
[pip3] fast-pytorch-kmeans==0.2.0.1
[pip3] flake8==7.0.0
[pip3] mypy==1.9.0
[pip3] mypy-extensions==1.0.0
[pip3] numpy==1.24.4
[pip3] numpydoc==1.6.0
[pip3] paddle2onnx==1.0.6
[pip3] pytorchts==0.6.0
[pip3] reformer-pytorch==1.4.4
[pip3] torch==2.2.2
[pip3] torch_cluster==1.6.3+pt22cu121
[pip3] torch-ema==0.3
[pip3] torch-geometric==2.6.0
[pip3] torch_scatter==2.1.2+pt22cu121
[pip3] torch_sparse==0.6.18+pt22cu121
[pip3] torch_spline_conv==1.2.2+pt22cu121
[pip3] torchaudio==2.2.2
[pip3] torchmetrics==0.10.1
[pip3] torchsummary==1.5.1
[pip3] torchvision==0.17.2
[pip3] triton==2.2.0
[conda] fast-pytorch-kmeans       0.2.0.1                  pypi_0    pypi
[conda] nomkl                     1.0                  h5ca1d4c_0    conda-forge
[conda] numpy                     1.24.4                   pypi_0    pypi
[conda] numpydoc                  1.6.0              pyhd8ed1ab_0    conda-forge
[conda] pytorchts                 0.6.0                    pypi_0    pypi
[conda] reformer-pytorch          1.4.4                    pypi_0    pypi
[conda] torch                     2.2.2                    pypi_0    pypi
[conda] torch-cluster             1.6.3+pt22cu121          pypi_0    pypi
[conda] torch-ema                 0.3                      pypi_0    pypi
[conda] torch-geometric           2.6.0                    pypi_0    pypi
[conda] torch-scatter             2.1.2+pt22cu121          pypi_0    pypi
[conda] torch-sparse              0.6.18+pt22cu121          pypi_0    pypi
[conda] torch-spline-conv         1.2.2+pt22cu121          pypi_0    pypi
[conda] torchaudio                2.2.2                    pypi_0    pypi
[conda] torchmetrics              0.10.1                   pypi_0    pypi
[conda] torchsummary              1.5.1                    pypi_0    pypi
[conda] torchvision               0.17.2                   pypi_0    pypi
[conda] triton                    2.2.0                    pypi_0    pypi

Pull request:
Respect `torch.nn.Module.children` in `Sequential`
Fixes #9437.

This issue was introduced in #9369 since the name `children` is reserved in PyTorch. See https://github.com/pytorch/pytorch/blob/b57fa8d9c07b0e03afbe5dab279aa26697b828ea/torch/nn/modules/module.py#L2352-L2359.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6b34a6493..b77526e11 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 
 ### Changed
 
+- Added support for modifying `filename` of the stored partitioned file in `ClusterLoader` ([#9448](https://github.com/pyg-team/pytorch_geometric/pull/9448))
 - Support other than two-dimensional inputs in `AttentionalAggregation` ([#9433](https://github.com/pyg-team/pytorch_geometric/pull/9433))
 - Improved model performance of the `examples/ogbn_papers_100m.py` script ([#9386](https://github.com/pyg-team/pytorch_geometric/pull/9386), [#9445](https://github.com/pyg-team/pytorch_geometric/pull/9445))
 - Added the `fmt` arg to `Dataset.get_summary` ([#9408](https://github.com/pyg-team/pytorch_geometric/pull/9408))
diff --git a/torch_geometric/io/fs.py b/torch_geometric/io/fs.py
index f39c08af6..89c142d95 100644
--- a/torch_geometric/io/fs.py
+++ b/torch_geometric/io/fs.py
@@ -186,11 +186,11 @@ def rm(path: str, recursive: bool = True) -> None:
     get_fs(path).rm(path, recursive)
 
 
-def mv(path1: str, path2: str, recursive: bool = True) -> None:
+def mv(path1: str, path2: str) -> None:
     fs1 = get_fs(path1)
     fs2 = get_fs(path2)
     assert fs1.protocol == fs2.protocol
-    fs1.mv(path1, path2, recursive=recursive)
+    fs1.mv(path1, path2)
 
 
 def glob(path: str) -> List[str]:
diff --git a/torch_geometric/loader/cluster.py b/torch_geometric/loader/cluster.py
index 3839b0301..5f82d90a0 100644
--- a/torch_geometric/loader/cluster.py
+++ b/torch_geometric/loader/cluster.py
@@ -1,4 +1,5 @@
 import copy
+import os
 import os.path as osp
 import sys
 from dataclasses import dataclass
@@ -43,6 +44,8 @@ class ClusterData(torch.utils.data.Dataset):
             (default: :obj:`False`)
         save_dir (str, optional): If set, will save the partitioned data to the
             :obj:`save_dir` directory for faster re-use. (default: :obj:`None`)
+        filename (str, optional): Name of the stored partitioned file.
+            (default: :obj:`None`)
         log (bool, optional): If set to :obj:`False`, will not log any
             progress. (default: :obj:`True`)
         keep_inter_cluster_edges (bool, optional): If set to :obj:`True`,
@@ -56,6 +59,7 @@ class ClusterData(torch.utils.data.Dataset):
         num_parts: int,
         recursive: bool = False,
         save_dir: Optional[str] = None,
+        filename: Optional[str] = None,
         log: bool = True,
         keep_inter_cluster_edges: bool = False,
         sparse_format: Literal['csr', 'csc'] = 'csr',
@@ -69,8 +73,8 @@ class ClusterData(torch.utils.data.Dataset):
         self.sparse_format = sparse_format
 
         recursive_str = '_recursive' if recursive else ''
-        filename = f'metis_{num_parts}{recursive_str}.pt'
-        path = osp.join(save_dir or '', filename)
+        root_dir = osp.join(save_dir or '', f'part_{num_parts}{recursive_str}')
+        path = osp.join(root_dir, filename or 'metis.pt')
 
         if save_dir is not None and osp.exists(path):
             self.partition = torch.load(path)
@@ -82,6 +86,7 @@ class ClusterData(torch.utils.data.Dataset):
             self.partition = self._partition(data.edge_index, cluster)
 
             if save_dir is not None:
+                os.makedirs(root_dir, exist_ok=True)
                 torch.save(self.partition, path)
 
             if log:  # pragma: no cover
diff --git a/torch_geometric/nn/sequential.py b/torch_geometric/nn/sequential.py
index cdff2d2a1..1cafc0b06 100644
--- a/torch_geometric/nn/sequential.py
+++ b/torch_geometric/nn/sequential.py
@@ -82,7 +82,7 @@ class Sequential(torch.nn.Module):
             :obj:`OrderedDict` of modules (and function header definitions) can
             be passed.
     """
-    children: List[Child]
+    _children: List[Child]
 
     def __init__(
         self,
@@ -145,7 +145,7 @@ class Sequential(torch.nn.Module):
             raise ValueError(f"'{self.__class__.__name__}' expects a "
                              f"non-empty list of modules")
 
-        self.children: List[Child] = []
+        self._children: List[Child] = []
         for i, (name, module) in enumerate(modules.items()):
             desc: Optional[str] = None
             if isinstance(module, (tuple, list)):
@@ -174,26 +174,26 @@ class Sequential(torch.nn.Module):
                 return_names = [v.strip() for v in signature[1].split(',')]
                 child = Child(name, param_names, return_names)
             else:
-                param_names = self.children[-1].return_names
+                param_names = self._children[-1].return_names
                 child = Child(name, param_names, param_names)
 
             setattr(self, name, module)
-            self.children.append(child)
+            self._children.append(child)
 
         self._set_jittable_template()
 
     def reset_parameters(self) -> None:
         r"""Resets all learnable parameters of the module."""
-        for child in self.children:
+        for child in self._children:
             module = getattr(self, child.name)
             if hasattr(module, 'reset_parameters'):
                 module.reset_parameters()
 
     def __len__(self) -> int:
-        return len(self.children)
+        return len(self._children)
 
     def __getitem__(self, idx: int) -> torch.nn.Module:
-        return getattr(self, self.children[idx].name)
+        return getattr(self, self._children[idx].name)
 
     def __setstate__(self, data: Dict[str, Any]) -> None:
         super().__setstate__(data)
@@ -202,7 +202,7 @@ class Sequential(torch.nn.Module):
     def __repr__(self) -> str:
         module_descs = [
             f"{', '.join(c.param_names)} -> {', '.join(c.return_names)}"
-            for c in self.children
+            for c in self._children
         ]
         module_reprs = [
             f'  ({i}) - {self[i]}: {module_descs[i]}' for i in range(len(self))
@@ -224,7 +224,7 @@ class Sequential(torch.nn.Module):
                                 f"values for argument '{key}'")
             value_dict[key] = arg
 
-        for child in self.children:
+        for child in self._children:
             args = [value_dict[name] for name in child.param_names]
             outs = getattr(self, child.name)(*args)
             if len(child.return_names) == 1:
@@ -253,7 +253,7 @@ class Sequential(torch.nn.Module):
                 # Keyword arguments:
                 modules=[self._caller_module],
                 signature=self.signature,
-                children=self.children,
+                children=self._children,
             )
 
             self.forward = module.forward.__get__(self)


Test patch:
diff --git a/test/nn/test_sequential.py b/test/nn/test_sequential.py
index 87e5361ca..6239aa29f 100644
--- a/test/nn/test_sequential.py
+++ b/test/nn/test_sequential.py
@@ -28,7 +28,7 @@ def test_sequential_basic():
         (GCNConv(64, 64), 'x, edge_index -> x'),
         ReLU(inplace=True),
         Linear(64, 7),
-    ])
+    ]).cpu()
     model.reset_parameters()
 
     assert len(model) == 5