我是 pytorch 和 pytorch 几何的新手,我正在尝试进行节点分类。大约 5-10% 的节点应该被归类为
violates
(因为它们违反了我想要预测的条件),而其余的则不应该。违规节点依赖于距离大约 5-10 个边的节点,我不知道这个 GCN 是否可以跟踪它(如果可以,请也回答这个问题)。我使用了文档中的示例并对其进行了调整以适合我的数据。我的问题是模型只输出 0。我哪里出错了?我该从哪里开始呢?我尝试调整一些参数,但没有改变任何东西,所以我认为我使用了错误的 GCN 设置。预先感谢!
import pandas as pd
import torch
import torch.nn.functional as F
from torch_geometric.data import Data
from torch_geometric.nn import GCNConv
TOTAL_TRAINING_DATA_SIZE = 10
VALIDATION_FACTOR = 0.2
TRAINING_DATA_SIZE = int(TOTAL_TRAINING_DATA_SIZE * (1 - VALIDATION_FACTOR))
def read_graph_data(amount):
graphs = []
for i in range(amount):
with pd.ExcelFile(f'training_data/test_{i}_graph_matrices.xlsx') as graph_file:
nodes = pd.read_excel(graph_file, 'nodes', usecols=[1, 2, 3, 4, 5])
edges = pd.read_excel(graph_file, 'edges', usecols=[1, 2])
node_classifications = pd.read_excel(graph_file, 'classifications',
dtype={'violates': bool}, usecols=[1])
graphs.append([nodes, edges, node_classifications])
return graphs
def create_dataset(graphs):
dataset = []
for i in range(TOTAL_TRAINING_DATA_SIZE):
nodes, edges, node_classifications = graphs[i]
edge_index = torch.tensor(edges.values, dtype=torch.long)
node_features = torch.tensor(nodes.values, dtype=torch.float)
node_classifications_ = torch.tensor(node_classifications.values, dtype=torch.long).flatten()
data = Data(x=node_features, y=node_classifications_, edge_index=edge_index.t().contiguous())
data.validate(raise_on_error=True)
dataset.append(data)
return dataset
class GCN(torch.nn.Module):
def __init__(self):
super().__init__()
self.conv1 = GCNConv(5, 16)
self.conv2 = GCNConv(16, 1)
def forward(self, data):
x, edge_index = data.x, data.edge_index
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, training=self.training)
x = self.conv2(x, edge_index)
return F.log_softmax(x, dim=1)
print('reading training data')
graphs = read_graph_data(TOTAL_TRAINING_DATA_SIZE)
dataset = create_dataset(graphs)
print('starting training')
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = GCN().to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=5e-4)
model.train()
for index in range(TRAINING_DATA_SIZE):
data = dataset[index].to(device)
for epoch in range(200):
optimizer.zero_grad()
out = model(data)
loss = F.nll_loss(out.flatten(), data.y)
loss.backward()
optimizer.step()
print('starting eval')
model.eval()
all_correct = 0
eval_test_case_amount = 0
for index in range(TRAINING_DATA_SIZE, TOTAL_TRAINING_DATA_SIZE):
data = dataset[index].to(device)
pred = model(data).argmax(dim=1)
print(pred.sum()) # compare the outputs (accumulated sum is enough because this line always prints 0)
print(data.y.sum())
comparison_correct = (pred == data.y)
correct = comparison_correct.sum()
all_correct += correct
eval_test_case_amount += len(pred)
assert (correct <= len(pred)), f'{correct} {len(pred)}'
acc = int(all_correct) / int(eval_test_case_amount)
print(f'Accuracy: {acc:.4f}')
我发现了问题:
pred = model(data).argmax(dim=1)
始终输出 0,因为输出向量只有一个元素。我改变了数据的结构,现在它可以工作了。
一个有趣的评论:
F.nll_loss
无法处理目标向量中的多个维度,所以我不得不切换到L1Loss