##実装したい内容
dglライブラリを用いて、
グラフ構造の畳み込みニューラルネットワークを実装したいです。
2種類のグラフ(circle,star)
をランダムに生成して、2クラス分類をするものを作成する予定です。
モデルの定義と訓練は以下のようになります。
(pytorchを用いて実装しています。)
python
1import dgl 2import torch 3 4def collate(samples): 5 # The input `samples` is a list of pairs 6 # (graph, label). 7 graphs, labels = map(list, zip(*samples)) 8 batched_graph = dgl.batch(graphs) 9 return batched_graph, torch.tensor(labels) 10 11from dgl.nn.pytorch import GraphConv 12 13import torch.nn as nn 14import torch.nn.functional as F 15 16#モデルの定義 17class Classifier(nn.Module): 18 def __init__(self, in_dim, hidden_dim, n_classes): 19 super(Classifier, self).__init__() 20 self.conv1 = GraphConv(in_dim, hidden_dim) 21 self.conv2 = GraphConv(hidden_dim, hidden_dim) 22 self.classify = nn.Linear(hidden_dim, n_classes) 23 #self.conv1,self.conv2をconvolution層として表現 24 #nn.Linearで全結合層として表現 25 26 27 #グラフの畳み込みと活性化関数 28 #順伝播 29 def forward(self, g): 30 # Use node degree as the initial node feature. For undirected graphs, the in-degree 31 # is the same as the out_degree. 32 h = g.in_degrees().view(-1, 1).float() 33 # Perform graph convolution and activation function. 34 h = F.relu(self.conv1(g, h)) 35 h = F.relu(self.conv2(g, h)) 36 g.ndata['h'] = h 37 # Calculate graph representation by averaging all the node representations. 38 hg = dgl.mean_nodes(g, 'h') 39 return self.classify(hg) 40 41import torch.optim as optim 42from torch.utils.data import DataLoader 43 44#320個のトレーニングセットと、80個の訓練セットを作成する。 45trainset = testclusternotest.MiniGCDatasetnotest(320, 10, 20) 46testset = testclusternotest.MiniGCDatasetnotest(80, 10, 20) 47# Use PyTorch's DataLoader and the collate function 48# defined before. 49 50data_loader = DataLoader(trainset, batch_size=32, shuffle=True, 51 collate_fn=collate) 52 53 54# modelを作成 55model = Classifier(1, 256, trainset.num_classes) 56loss_func = nn.CrossEntropyLoss() 57optimizer = optim.Adam(model.parameters(), lr=0.001) 58 59model.train() 60 61epoch_losses = [] 62 63#80回同じ操作を繰り返す。 64for epoch in range(80): 65 epoch_loss = 0 66 for iter, (bg, label) in enumerate(data_loader): 67 prediction = model(bg) 68 loss = loss_func(prediction, label) 69 #勾配のリセット 70 optimizer.zero_grad() 71 #逆伝播の更新 72 loss.backward() 73 #重みの更新 74 optimizer.step() 75 epoch_loss += loss.detach().item() 76 # epoch_loss = epoch_loss/(iter+1) 77 epoch_loss /= (iter + 1) 78 print('Epoch {}, loss {:.4f}'.format(epoch, epoch_loss)) 79 epoch_losses.append(epoch_loss)
#使用したデータセット
以下のようなMiniGCDatasetと呼ばれるDGLライブラリ付属のデータセットを改変いたしました。元は8クラス分類でしたが、2クラスに書き換えました。
元のデータセットは、以下のURLからご覧ください。
https://docs.dgl.ai/en/0.4.x/_modules/dgl/data/minigc.html#MiniGCDataset
python
1"""作成したデータセット""" 2import math, os 3import networkx as nx 4import numpy as np 5 6from .dgl_dataset import DGLDataset 7from .utils import save_graphs, load_graphs, makedirs 8from .. import backend as F 9from ..convert import from_networkx 10from ..transform import add_self_loop 11 12__all__ = ['MiniGCDatasetnotest'] 13 14class MiniGCDatasetnotest(DGLDataset): 15 16 def __init__(self, num_graphs, min_num_v, max_num_v, seed=0, 17 save_graph=True, force_reload=False, verbose=False): 18 self.num_graphs = num_graphs 19 self.min_num_v = min_num_v 20 self.max_num_v = max_num_v 21 self.seed = seed 22 self.save_graph = save_graph 23 super(MiniGCDatasetnotest, self).__init__(name="testclusternotest", hash_key=(num_graphs, min_num_v, max_num_v, seed), 24 force_reload=force_reload, 25 verbose=verbose) 26 27 def process(self): 28 self.graphs = [] 29 self.labels = [] 30 self._generate(self.seed) 31 32 def __len__(self): 33 """Return the number of graphs in the dataset.""" 34 return len(self.graphs) 35 36 def __getitem__(self, idx): 37 """Get the idx-th sample. 38 39 Parameters 40 --------- 41 idx : int 42 The sample index. 43 44 Returns 45 ------- 46 (:class:`dgl.Graph`, Tensor) 47 The graph and its label. 48 """ 49 return self.graphs[idx], self.labels[idx] 50 51 def has_cache(self): 52 graph_path = os.path.join(self.save_path, 'dgl_graph_{}.bin'.format(self.hash)) 53 if os.path.exists(graph_path): 54 return True 55 56 return False 57 58 def save(self): 59 """save the graph list and the labels""" 60 if self.save_graph: 61 graph_path = os.path.join(self.save_path, 'dgl_graph_{}.bin'.format(self.hash)) 62 save_graphs(str(graph_path), self.graphs, {'labels': self.labels}) 63 64 def load(self): 65 graphs, label_dict = load_graphs(os.path.join(self.save_path, 'dgl_graph_{}.bin'.format(self.hash))) 66 self.graphs = graphs 67 self.labels = label_dict['labels'] 68 69 @property 70 def num_classes(self): 71 """Number of classes.""" 72 return 2 73 74 def _generate(self, seed): 75 if seed is not None: 76 np.random.seed(seed) 77 self._gen_cycle(self.num_graphs // 2) 78 self._gen_star(self.num_graphs // 2) 79 80 # preprocess 81 for i in range(self.num_graphs): 82 # convert to DGLGraph, and add self loops 83 self.graphs[i] = add_self_loop(from_networkx(self.graphs[i])) 84 self.labels = F.tensor(np.array(self.labels).astype(np.int)) 85 86 def _gen_cycle(self, n): 87 for _ in range(n): 88 num_v = np.random.randint(self.min_num_v, self.max_num_v) 89 g = nx.cycle_graph(num_v) 90 self.graphs.append(g) 91 self.labels.append(0) 92 93 def _gen_star(self, n): 94 for _ in range(n): 95 num_v = np.random.randint(self.min_num_v, self.max_num_v) 96 # nx.star_graph(N) gives a star graph with N+1 nodes 97 g = nx.star_graph(num_v - 1) 98 self.graphs.append(g) 99 self.labels.append(1)
##発生したエラー
Index Error: Target 5 is out of bounds.が出力されました。
python
1IndexError Traceback (most recent call last) 2<ipython-input-15-dfdf585f0b2f> in <module> 3 36 for iter, (bg, label) in enumerate(data_loader): 4 37 prediction = model(bg) 5---> 38 loss = loss_func(prediction, label) 6 39 #勾配のリセット 7 40 optimizer.zero_grad() 8 9~/anaconda/envs/pytorch/lib/python3.6/site-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction) 10 2216 .format(input.size(0), target.size(0))) 11 2217 if dim == 2: 12-> 2218 ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index) 13 2219 elif dim == 4: 14 2220 ret = torch._C._nn.nll_loss2d(input, target, weight, _Reduction.get_enum(reduction), ignore_index) 15 16IndexError: Target 5 is out of bounds.
#自分で試したこと
print関数にて、labelがきちんと出力されているのか以下で確認しました。
python
1for epoch in range(80): 2 epoch_loss = 0 3 for iter, (bg, label) in enumerate(data_loader): 4 prediction = model(bg) 5 print(label) 6 loss = loss_func(prediction, label)
出力結果
python
1tensor([5, 1, 4, 3, 7, 4, 0, 6, 0, 0, 4, 0, 2, 3, 0, 3, 4, 5, 3, 1, 3, 4, 7, 7, 4, 6, 5, 7, 3, 0, 1, 1])
これより、tensorの最初の要素5が、0か1でないために、エラーが出ていると推測されます。元は8クラス分類だったのでこの出力は納得がいくのですが、どのようにデータセットを書き換えれば良いかがわかりません。
どなたかご教授願えませんでしょうか。
あなたの回答
tips
プレビュー