我正在使用PyTorch Geometric开发一个图神经网络。这个想法是从多变量时间序列开始,根据这些时间序列之间的相关性建立一个图,然后对图进行分类。我已经构建了一个CorrelationLayer,它使用pearson系数计算图的邻接矩阵,并将其乘以可训练权重的矩阵。然后将这个矩阵连同作为节点特征的时间序列一起传递给一个图卷积层(我将在图卷积之后添加其他层进行分类,但我为这个问题做了一个超简化的版本)。问题是,当我尝试训练模型时,相关层的权重没有更新,而图卷积层的参数没有任何问题)
下面是相关层的代码:class CorrelationLayer(nn.Module):
def __init__(self, num_time_series):
super().__init__()
self.num_time_series = num_time_series
self.weights = nn.Parameter(torch.rand((num_time_series, num_time_series)))
def forward(self, x):
correlations = torch.zeros((x.shape[0], x.shape[0]))
for i in range(x.shape[0]):
for j in range(i+1, x.shape[0]):
c, _ = pearsonr(x[i], x[j])
correlations[i, j] = c
correlations[j, i] = c
correlations = correlations * self.weights
return correlations
下面是GCN模型的代码:
class GCN(nn.Module):
def __init__(self, num_time_series, ts_length, hidden_channels):
super(GCN, self).__init__()
self.corr_layer = CorrelationLayer(num_time_series)
self.graph_conv = GCNConv(ts_length, hidden_channels)
return
def forward(self, x):
adj = self.corr_layer(x)
out = self.graph_conv(x, torch_geometric.utils.dense_to_sparse(adj)[0])
return out
这是我为了托盘和测试模型而写的代码,带有一些示例数据:
def train(model, X_train, Y_train):
model.train()
for x, y in zip(X_train,Y_train):
out = model(x)
print(model.corr_layer.weights)
print(model.graph_conv.state_dict().values())
loss = criterion(out, y)
loss.backward()
optimizer.step()
optimizer.zero_grad()
X = torch.tensor([
[
[0.,1.,2.,3.],
[1.,2.,3.,4.],
[0.,6.,3.,1.],
[3.,2.,1.,0.]
],
[
[2.,4.,6.,8.],
[1.,2.,3.,4.],
[1.,8.,3.,7.],
[3.,2.,1.,0.]
],
[
[0.,1.,2.,3.],
[1.,2.,3.,4.],
[0.,6.,3.,1.],
[3.,2.,1.,0.]
]
])
Y = torch.tensor([
[[1.],[1.],[1.],[1.]],
[[0.],[0.],[0.],[0.]],
[[1.],[1.],[1.],[1.]]
])
model = GCN(4,4,1)
optimizer = torch.optim.Adam(model.parameters(), lr=0.5)
criterion = torch.nn.MSELoss()
for epoch in range(1, 100):
train(model, X,Y)
通过训练函数中的打印,我们可以看到graph_conv层的参数正在更新,而相关层的权重没有更新。
目前我的猜测是,问题是在从邻接矩阵过渡到稀疏版本与dense_to_sparse,但我不确定。
有没有人经历过类似的事情,有什么想法或建议?
好吧,尽管这是一个非常尖锐和具体的问题,但对于将来经过这里的任何人来说,这是解决方案:
正如用户theecho7在PyTorch论坛(https://discuss.pytorch.org/t/pytorch-geometric-custom-layer-parameters-not-updating/170632/2)上指出的那样
dense_to_sparse包含两个张量,第一个张量是元素的索引集,第二个张量是值张量。索引张量不包含值张量有梯度的地方。
所以在forward方法中我改变了
out = self.graph_conv(x, torch_geometric.utils.dense_to_sparse(adj)[0])
out = self.graph_conv(x, torch_geometric.utils.dense_to_sparse(adj)[0], torch_geometric.utils.dense_to_sparse(adj)[1])
,现在相关层的权重更新。