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

结合VQ-VAE与GCN时遇'Tensor'无'ndata'属性错误求助

问题分析与解决:AttributeError: 'Tensor' object has no attribute 'ndata'

问题背景

我是深度学习领域新手,在Google Colab环境中使用DGL库尝试结合VQ-VAE模型与GCN,已确认PyTorch和DGL版本均为最新,模型构建过程正常,但训练拟合阶段触发AttributeError: 'Tensor' object has no attribute 'ndata'。

模型定义代码

class Model(nn.Module):
    def __init__(self, num_hiddens, num_residual_layers, num_residual_hiddens, 
                 num_embeddings, embedding_dim, commitment_cost, decay=0):
        super(Model, self).__init__()
        
        self._encoder = Encoder(3, num_hiddens,
                                num_residual_layers, 
                                num_residual_hiddens)
        self._pre_vq_conv = nn.Conv2d(in_channels=num_hiddens, 
                                      out_channels=embedding_dim,
                                      kernel_size=1, 
                                      stride=1)
        if decay > 0.0:
            self._vq_vae = VectorQuantizerEMA(num_embeddings, embedding_dim, 
                                              commitment_cost, decay)
        else:
            self._vq_vae = VectorQuantizer(num_embeddings, embedding_dim,
                                           commitment_cost)
        self._decoder = Decoder(embedding_dim,
                                num_hiddens, 
                                num_residual_layers, 
                                num_residual_hiddens)

    def forward(self, g):
        x = g.ndata['feat']
        z = self._encoder(x)
        z = self._pre_vq_conv(z)
        loss, quantized, perplexity, _ = self._vq_vae(z)
        x_recon = self._decoder(quantized)

        return loss, x_recon, perplexity


model = Model(num_hiddens, num_residual_layers, num_residual_hiddens,
              num_embeddings, embedding_dim, 
              commitment_cost, decay).to(device)

optimizer = optim.Adam(model.parameters(), lr=learning_rate, amsgrad=False)

训练代码

model.train()
train_res_recon_error = []
train_res_perplexity = []

for i, batch in enumerate(training_loader):
    batch_graph = batch.to(device)  # Memindahkan graf ke perangkat yang sesuai
    optimizer.zero_grad()

    

for batch_graph in training_loader:
    batch_graph = batch_graph.to(device)
    inputs = batch_graph.ndata['feat']
    batch_size = inputs.shape[0]
    # Memastikan dimensi input sesuai dengan kebutuhan model
    inputs = inputs.reshape(batch_size, -1, 1, 1)

    optimizer.zero_grad()
    vq_loss, data_recon, perplexity = model(inputs)
    recon_error = F.mse_loss(data_recon, inputs) / data_variance
    loss = recon_error + vq_loss
    loss.backward()
    optimizer.step()


    # Menjalankan model pada data input
    inputs = batch_graph.ndata['feat'].to(device)
    vq_loss, data_recon, perplexity = model(inputs)

    # Menghitung error rekonstruksi
    recon_error = F.mse_loss(data_recon, inputs) / data_variance

    # Menghitung total loss
    loss = recon_error + vq_loss

    # Backward pass dan update parameter
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()


    #optimizer.step()

    train_res_recon_error.append(recon_error.item())
    train_res_perplexity.append(perplexity.item())

    if (i+1) % 100 == 0:
        print('%d iterations' % (i+1))
        print('recon_error: %.3f' % np.mean(train_res_recon_error[-100:]))
        print('perplexity: %.3f' % np.mean(train_res_perplexity[-100:]))
        print()

报错信息

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-80-717a0674743f> in <cell line: 14>()
     20 
     21     optimizer.zero_grad()
---> 22     vq_loss, data_recon, perplexity = model(inputs)
     23     recon_error = F.mse_loss(data_recon, inputs) / data_variance
     24     loss = recon_error + vq_loss

1 frames
/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py in _call_impl(self, *args, **kwargs)
   1499                 or _global_backward_pre_hooks or _global_backward_hooks
   1500                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1501             return forward_call(*args, **kwargs)
   1502         # Do not call functions when jit is used
   1503         full_backward_hooks, non_full_backward_hooks = [], []

<ipython-input-75-1fbfd62ffc59> in forward(self, g)
     23 
     24     def forward(self, g):
---> 25         x = g.ndata['feat']
     26         z = self._encoder(x)
     27         z = self._pre_vq_conv(z)

AttributeError: 'Tensor' object has no attribute 'ndata'

问题根源

模型的forward方法设计为接收DGL Graph对象,但训练代码中传入的是从图中提取出的Tensor(batch_graph.ndata['feat']),而PyTorch Tensor没有ndata属性,因此触发报错。同时训练代码存在重复执行前向传播、梯度更新的冗余逻辑。

修复方案

方案1:调整模型以直接接收Tensor输入(适配现有CNN结构)

从代码中的Conv2d层可以看出,Encoder/Decoder是基于CNN的结构,不需要Graph对象,直接修改模型的forward方法:

def forward(self, x):
    # 直接使用传入的Tensor输入,不再从Graph中提取特征
    z = self._encoder(x)
    z = self._pre_vq_conv(z)
    loss, quantized, perplexity, _ = self._vq_vae(z)
    x_recon = self._decoder(quantized)

    return loss, x_recon, perplexity

同时清理训练代码中的冗余逻辑:

model.train()
train_res_recon_error = []
train_res_perplexity = []

# 保留单个循环,去掉外层无效的enumerate循环
for i, batch_graph in enumerate(training_loader):
    batch_graph = batch_graph.to(device)
    inputs = batch_graph.ndata['feat']
    batch_size = inputs.shape[0]
    # 调整输入维度适配Conv2d的[batch_size, channels, height, width]格式
    inputs = inputs.reshape(batch_size, -1, 1, 1).to(device)

    optimizer.zero_grad()
    # 传入处理好的Tensor输入
    vq_loss, data_recon, perplexity = model(inputs)
    recon_error = F.mse_loss(data_recon, inputs) / data_variance
    loss = recon_error + vq_loss
    loss.backward()
    optimizer.step()

    train_res_recon_error.append(recon_error.item())
    train_res_perplexity.append(perplexity.item())

    if (i+1) % 100 == 0:
        print('%d iterations' % (i+1))
        print('recon_error: %.3f' % np.mean(train_res_recon_error[-100:]))
        print('perplexity: %.3f' % np.mean(train_res_perplexity[-100:]))
        print()

方案2:如果需要结合GCN(保留Graph输入)

若你的Encoder包含GCN层,需要传入Graph对象,则修改模型的forward方法以适配Graph处理,同时调整训练代码传入Graph:

# 模型forward方法示例(假设Encoder是GCN结构)
def forward(self, g):
    x = g.ndata['feat']
    # 用GCN处理Graph节点特征
    z = self._encoder(g, x)
    # 调整维度适配后续Conv2d层
    z = z.reshape(-1, num_hiddens, 1, 1)
    z = self._pre_vq_conv(z)
    loss, quantized, perplexity, _ = self._vq_vae(z)
    # 解码后恢复节点特征维度
    x_recon = self._decoder(quantized).reshape(-1, x.shape[1])

    return loss, x_recon, perplexity

# 训练代码中直接传入Graph对象
vq_loss, data_recon, perplexity = model(batch_graph)
# 计算损失时使用Graph中的原始特征作为目标
recon_error = F.mse_loss(data_recon, batch_graph.ndata['feat']) / data_variance

内容的提问来源于stack exchange,提问作者Fairuuz Amaanullah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:12:08