- Y : 8 values , 2d vector
- X : same as Y
- Y_hat : always constant
- Data: fully connected graph with always 8 nodes
- Model : plain homogeneous GCN
- Loss function : MSE
- Assumption , The x:Y shall have 1:1 correlation so it should able to give enough predictive power to y.
- Question : why is it always constant? Or the approach itself is incorrect?
Output:
Final model outputs: tensor([[0.2878],
[0.2878],
[0.2878],
[0.2878],
[0.2878],
[0.2878],
[0.2878],
[0.2878]], grad_fn=<AddmmBackward0>)
Target values (Y): tensor([[0.2037],
[0.5126],
[0.6616],
[0.7587],
[0.3367],
[0.2623],
[0.7544],
[0.6320]])
Code :
import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv
# Define a more powerful GNN model
class GNN(torch.nn.Module):
def __init__(self, num_node_features, hidden_channels, output_channels):
super(GNN, self).__init__()
self.conv1 = GCNConv(num_node_features, hidden_channels)
self.conv2 = GCNConv(hidden_channels, hidden_channels)
self.conv3 = GCNConv(hidden_channels, hidden_channels) # Additional layer
self.fc = torch.nn.Linear(hidden_channels, output_channels)
def forward(self, x, edge_index):
x = self.conv1(x, edge_index)
x = F.sigmoid(x)
x = self.conv2(x, edge_index)
x = F.sigmoid(x)
x = self.conv3(x, edge_index) # Additional layer
x = F.sigmoid(x)
x = self.fc(x)
return x
# Create a synthetic dataset
num_nodes = 8
num_node_features = 1
x = torch.rand((num_nodes, num_node_features)) # Random node features
edge_index = torch.tensor([[i, j] for i in range(num_nodes) for j in range(num_nodes) if i != j], dtype=torch.long).t().contiguous()
Y = torch.rand((num_nodes, 1)) # Random target ranks
x = Y
# Initialize the model
model = GNN(num_node_features, hidden_channels=32, output_channels=1)
# Define loss function and optimizer
criterion = torch.nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
# Training loop
for epoch in range(100):
optimizer.zero_grad()
out = model(x, edge_index)
loss = criterion(out, Y)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) # Gradient clipping
optimizer.step()
scheduler.step()
print(f"Epoch {epoch+1}, Loss: {loss.item()}")
# Check final outputs
out = model(x, edge_index)
print("Final model outputs:", out)
print("Target values (Y):", Y)