code: def main():
      parser = argparse.ArgumentParser(
          description="OGBN-Products (Cluster-GCN)"
      )
      parser.add_argument("--device", type=int, default=0)
      parser.add_argument("--log_steps", type=int, default=1)
      parser.add_argument("--num_partitions", type=int, default=15000)
      parser.add_argument("--num_workers", type=int, default=12)
      parser.add_argument("--num_layers", type=int, default=3)
      parser.add_argument("--hidden_channels", type=int, default=256)
      parser.add_argument("--dropout", type=float, default=0.5)
      parser.add_argument("--batch_size", type=int, default=32)
      parser.add_argument("--lr", type=float, default=0.001)
      parser.add_argument("--epochs", type=int, default=50)
      parser.add_argument("--eval_steps", type=int, default=5)
      parser.add_argument("--runs", type=int, default=10)
      args = parser.parse_args()
      print(args)
  
      device = (
          f"cuda:{args.device}" if torch.cuda.is_available() else "cpu"
      )
      device = torch.device(device)
  
      dataset = PygNodePropPredDataset(name="ogbn-products")
      split_idx = dataset.get_idx_split()
      data = dataset[0]
  
      # Convert split indices to boolean masks and add them to `data`.
      for key, idx in split_idx.items():
          mask = torch.zeros(data.num_nodes, dtype=torch.bool)
          mask[idx] = True
          data[f"{key}_mask"] = mask
  
      cluster_data = ClusterData(
          data,
          num_parts=args.num_partitions,
          recursive=False,
          save_dir=dataset.processed_dir,
      )
  
      loader = ClusterLoader(
          cluster_data,
          batch_size=args.batch_size,
          shuffle=True,
          num_workers=args.num_workers,
      )
  
      subgraph_loader = NeighborSampler(
          data.edge_index,
          sizes=[-1],
          batch_size=1024,
          shuffle=False,
          num_workers=args.num_workers,
      )
  
      model = SAGE(
          data.x.size(-1),
          args.hidden_channels,
          dataset.num_classes,
          args.num_layers,
          args.dropout,
      ).to(device)
  
      evaluator = Evaluator(name="ogbn-products")
      logger = Logger(args.runs, args)
  
      for run in range(args.runs):
          model.reset_parameters()
          optimizer = torch.optim.Adam(model.parameters(), lr=args.lr)
          for epoch in range(1, 1 + args.epochs):
              loss, train_acc = train(model, loader, optimizer, device)
              if epoch % args.log_steps == 0:
                  print(
                      f"Run: {run + 1:02d}, "
                      f"Epoch: {epoch:02d}, "
                      f"Loss: {loss:.4f}, "
                      f"Approx Train Acc: {train_acc:.4f}"
                  )
  
              if epoch > 19 and epoch % args.eval_steps == 0:
                  result = test(
                      model, data, evaluator, subgraph_loader, device
                  )
                  logger.add_result(run, result)
                  train_acc, valid_acc, test_acc = result
                  print(
                      f"Run: {run + 1:02d}, "
                      f"Epoch: {epoch:02d}, "
                      f"Train: {100 * train_acc:.2f}%, "
                      f"Valid: {100 * valid_acc:.2f}% "
                      f"Test: {100 * test_acc:.2f}%"
                  )
  
          logger.print_statistics(run)
      logger.print_statistics()
  
file_path: ogb/examples/nodeproppred/products/cluster_gcn.py
imports: import argparse
  import torch
  from tqdm.auto import tqdm
  import torch.nn.functional
  from torch_geometric.data import ClusterData, ClusterLoader, NeighborSampler
  from torch_geometric.nn import SAGEConv
  from ogb.nodeproppred import PygNodePropPredDataset, Evaluator
  from logger import Logger
label_desc: Use image node_id 3 for calling a global function with example usage: main() without return types