<jupyter_start><jupyter_text>Option 1: load graph edges from pickle file<jupyter_code>node_count = 34
# Load from pickle file

with open('edge_list.pickle', 'rb') as f:
    edge_list = pickle.load(f)
print(edge_list)
import torch
import numpy as np

def build_karate_club_graph(edges):
    g = dgl.DGLGraph()
    g.add_nodes(node_count)
    src, dst = zip(*edges)
    src = np.asarray(src).astype('int64')
    dst = np.asarray(dst).astype('int64')
    g.add_edges(torch.tensor(src), torch.tensor(dst))
    # edges are directional in DGL; make them bidirectional
    g.add_edges(torch.tensor(dst), torch.tensor(src))
    return g
G = build_karate_club_graph(edge_list)<jupyter_output><empty_output><jupyter_text>Option 2: load DGL dataset<jupyter_code>G = dgl.data.KarateClubDataset()[0]<jupyter_output><empty_output><jupyter_text>Display graph<jupyter_code>print('We have %d nodes.' % G.number_of_nodes())
print('We have %d edges.' % G.number_of_edges())
# Since the actual graph is undirected, we convert it for visualization purpose.
nx_G = G.to_networkx().to_undirected()
# Kamada-Kawaii layout usually looks pretty for arbitrary graphs
pos = nx.kamada_kawai_layout(nx_G)
nx.draw(nx_G, pos, with_labels=True, node_color=[[.7, .7, .7]])<jupyter_output><empty_output><jupyter_text>Train model<jupyter_code>from dgl.nn import GraphConv
from torch.nn import Module
import torch.nn.functional as F

class GCN(Module):
    def __init__(self, in_feats, h_feats, num_classes):
        super(GCN, self).__init__()
        self.conv1 = GraphConv(in_feats, h_feats)
        self.conv2 = GraphConv(h_feats, num_classes)

    def forward(self, g, in_feat):
        h = self.conv1(g, in_feat)
        h = F.relu(h)
        h = self.conv2(g, h)
        return h
    
net = GCN(34, 5, 2)
inputs = torch.eye(G.number_of_nodes())
labeled_nodes = torch.tensor([0, 33])  # only the instructor and the president nodes are labeled
labels = torch.tensor([0,1])  # their labels are different
optimizer = torch.optim.Adam(net.parameters(), lr=0.1)
all_preds = []
epochs = 30

for epoch in range(epochs):
    preds = net(G, inputs)
    all_preds.append(preds)
    # we only compute loss for labeled nodes
    loss = F.cross_entropy(preds[labeled_nodes], labels)

    optimizer.zero_grad() # PyTorch accumulates gradients by default
    loss.backward() 
    optimizer.step()

    print('Epoch %d | Loss: %.4f' % (epoch, loss.item()))
last_epoch = all_preds[epochs-1].detach().numpy()
predicted_class = np.argmax(last_epoch, axis=-1)
color = np.where(predicted_class==0, 'c', 'r')

print(predicted_class)
print(color)
nx.draw_networkx(nx_G, pos, node_color=color, with_labels=True, node_size=300)
print(last_epoch[8])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12968405584129317, 'fraction_numerical': 0.013592946362968405, 'mean_word_length': 4.7568710359408035, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '171007', 'license': 'MIT', 'n_tokens_mistral': 1031, 'n_tokens_neox': 1007, 'n_words': 220, 'path': 'Chapter 07/pytorch/DGL on Karate Club.ipynb', 'repo_name': 'amikewatson/Learn-Amazon-SageMaker-second-edition', 'size': '2722'}