You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyTorch训练GCN做链接预测时遇AttributeError报错求助

问题排查:PyTorch Geometric链接预测中的AttributeError错误

报错信息

AttributeError: 'tuple' object has no attribute 'x'

问题原因

  1. 数据集拆分返回值处理错误:RandomLinkSplit执行后会返回包含训练集、验证集、测试集的三元组(train_data, val_data, test_data),但你直接将这个三元组赋值给了data变量,导致后续访问data.x时,实际是在访问tuple的属性,触发报错。
  2. 节点特征未初始化:原始Data对象只设置了edge_index和num_nodes,没有定义节点特征x,而GCN模型的输入依赖节点特征,这会引发后续训练错误。
  3. 链接预测逻辑错误:原代码直接将边索引传入模型获取输出,不符合链接预测的常规逻辑——需要先学习节点嵌入,再通过节点嵌入计算边的预测得分。

修正后的完整代码

数据处理与模型定义

import torch
import pandas as pd
from torch_geometric.data import Data
from torch_geometric.transforms import RandomLinkSplit
from torch_geometric.nn import GCNConv

# 加载边列表数据
df = pd.read_csv('Alliances_torch.csv')

# 提取源节点和目标节点
src = df['Source'].values
tgt = df['Target'].values

# 计算总节点数
num_nodes = max(max(src), max(tgt)) + 1

# 初始化节点特征:示例用全1向量,可根据业务替换为真实节点属性
x = torch.ones((num_nodes, 1), dtype=torch.float)

# 创建完整的Data对象,包含节点特征、边索引和节点数
data = Data(x=x, edge_index=torch.tensor([src, tgt]), num_nodes=num_nodes)

# 拆分数据集:正确接收三元组返回值
transform = RandomLinkSplit(num_val=0.1, num_test=0.1)
train_data, val_data, test_data = transform(data)

# 定义GCN模型
class GCN(torch.nn.Module):
    def __init__(self, num_features, hidden_size, num_classes):
        super(GCN, self).__init__()
        self.conv1 = GCNConv(num_features, hidden_size)
        self.conv2 = GCNConv(hidden_size, num_classes)
    
    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index)
        x = torch.relu(x)
        x = self.conv2(x, edge_index)
        return x

# 初始化模型、优化器和损失函数
model = GCN(num_features=1, hidden_size=16, num_classes=1)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
criterion = torch.nn.BCEWithLogitsLoss()

训练与测试代码

# 训练函数:基于训练集数据执行
def train():
    model.train()
    optimizer.zero_grad()
    # 先学习全图节点嵌入
    out = model(train_data.x, train_data.edge_index)
    # 提取训练正边两端节点的嵌入,通过点积计算边得分
    src_nodes = train_data.train_pos_edge_index[0]
    tgt_nodes = train_data.train_pos_edge_index[1]
    edge_scores = (out[src_nodes] * out[tgt_nodes]).sum(dim=1)
    # 计算损失
    loss = criterion(edge_scores, train_data.train_pos_edge_label.float())
    loss.backward()
    optimizer.step()

# 测试函数:基于测试集数据评估
def test():
    model.eval()
    with torch.no_grad():
        out = model(test_data.x, test_data.edge_index)
        src_nodes = test_data.test_pos_edge_index[0]
        tgt_nodes = test_data.test_pos_edge_index[1]
        edge_scores = (out[src_nodes] * out[tgt_nodes]).sum(dim=1)
        # 生成预测结果并计算准确率
        pred = (edge_scores > 0).flatten()
        correct = pred.eq(test_data.test_pos_edge_label).sum().item()
        acc = correct / test_data.test_pos_edge_label.size(0)
    return acc

# 执行50轮训练与测试
for epoch in range(1, 51):
    train()
    test_acc = test()
    print('Epoch {:03d}, Test Acc: {:.4f}'.format(epoch, test_acc))

内容的提问来源于stack exchange,提问作者Oscar Fernando CV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:44:59