text: import os.path as osp
  
  import torch
  import torch.nn.functional as F
  
  from torch_geometric.datasets import DBLP
  from torch_geometric.nn import HeteroConv, Linear, SAGEConv
  
  path = osp.join(osp.dirname(osp.realpath(__file__)), '../../data/DBLP')
  path = '/data/datasets/DBLP'
  dataset = DBLP(path)
  data = dataset[0]
  print(data)
  
  # We initialize conference node features with a single feature.
  data['conference'].x = torch.ones(data['conference'].num_nodes, 1)
  
  
  class HeteroGNN(torch.nn.Module):
      def __init__(self, metadata, hidden_channels, out_channels, num_layers):
          super().__init__()
  
          self.convs = torch.nn.ModuleList()
          for _ in range(num_layers):
              conv = HeteroConv({
                  edge_type: SAGEConv((-1, -1), hidden_channels)
                  for edge_type in metadata[1]
              })
              self.convs.append(conv)
  
          self.lin = Linear(hidden_channels, out_channels)
  
      def forward(self, x_dict, edge_index_dict):
          for conv in self.convs:
              x_dict = conv(x_dict, edge_index_dict)
              x_dict = {key: F.leaky_relu(x) for key, x in x_dict.items()}
          return self.lin(x_dict['author'])
  
  
  model = HeteroGNN(data.metadata(), hidden_channels=64, out_channels=4,
                    num_layers=2)
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  data, model = data.to(device), model.to(device)
  
  with torch.no_grad():  # Initialize lazy modules.
      out = model(data.x_dict, data.edge_index_dict)
  
  optimizer = torch.optim.Adam(model.parameters(), lr=0.005, weight_decay=0.001)
  
  
  def train():
      model.train()
      optimizer.zero_grad()
      out = model(data.x_dict, data.edge_index_dict)
      mask = data['author'].train_mask
      loss = F.cross_entropy(out[mask], data['author'].y[mask])
      loss.backward()
      optimizer.step()
      return float(loss)
  
  
  @torch.no_grad()
  def test():
      model.eval()
      pred = model(data.x_dict, data.edge_index_dict).argmax(dim=-1)
  
      accs = []
      for split in ['train_mask', 'val_mask', 'test_mask']:
          mask = data['author'][split]
          acc = (pred[mask] == data['author'].y[mask]).sum() / mask.sum()
          accs.append(float(acc))
      return accs
  
  
  for epoch in range(1, 101):
      loss = train()
      train_acc, val_acc, test_acc = test()
      print(f'Epoch: {epoch:03d}, Loss: {loss:.4f}, Train: {train_acc:.4f}, '
            f'Val: {val_acc:.4f}, Test: {test_acc:.4f}')
  