How to change block.dstdata?

i create a heterograph g and sample a block from it. i want to change an item in block.dstdata. i use “block.dstdata[property_name] = a_new_dict” but it says “Expect number of features to match number of nodes (len(u))”. And i use “block.ndata[property_name] = a_new_dict” but the change of block.ndata doesn’t change block.dstdata.

Hi jyqcool welcome to the community!

I’ve been able to replicate your issue, but not solve it. Here’s a minimal example.

import torch
import dgl
from dgl.dataloading import NodeDataLoader, MultiLayerFullNeighborSampler

# links between the 6 nodes of type A
u1 = [0,1,2,3,4,5]
v1 = [4,5,0,1,2,3]

# links between the 5 nodes of type B
u2 = [0,1,2,3,4]
v2 = [4,0,1,2,3]

# links between the node type A and type B
u3 = [0,1,2,3,4]
v3 = [0,1,2,3,4]

# my example from another post

graph = dgl.heterograph({   ('a', 'same_a', 'a') : (u1, v1),
                            ('b', 'same_b', 'b') : (u2, v2),
                            ('a', 'diff_a', 'b') : (u3, v3),
                            ('b', 'diff_b', 'a') : (v3, u3)}, num_nodes_dict = {'a':6,'b':5})

# assign features to our nodes data
graph.nodes['a'].data['feat'] = torch.ones((6,1))
graph.nodes['b'].data['feat'] = torch.ones((5,2))

sampler = MultiLayerFullNeighborSampler(2)
train_ids = {}
train_ids['a'] = torch.arange(0,graph.num_nodes('a'),dtype=torch.int64)
train_ids['b'] = torch.arange(0,graph.num_nodes('b'),dtype=torch.int64)


trainloader     = NodeDataLoader(graph,train_ids, sampler, batch_size=70, shuffle=True, drop_last=False)

# we use these mfgs to test your problem
_, _, mfgs = next(iter(trainloader)) # blocks also regularly mfgs - message flow graphs

Here we can check the node features features by calling call mfgs[-1].srcdata or mfgs[-1].ndata and get this as a return.

defaultdict(<class 'dict'>, {'feat': {'a': tensor([[1.],
        [1.],
        [1.],
        [1.],
        [1.],
        [1.]]), 'b': tensor([[1., 1.],
        [1., 1.],
        [1., 1.],
        [1., 1.],
        [1., 1.]])}, '_ID': {'a': tensor([5, 0, 1, 3, 4, 2]), 'b': tensor([4, 1, 2, 0, 3])}})

Note I’ve applied the change using the apply_nodes method. But was only able to update the srcdata, and ndata, but not the dstdata.

mfgs[-1].apply_nodes(lambda nodes: {'feat': torch.zeros(nodes.data['feat'].shape)}, ntype='a')
mfgs[-1].apply_nodes(lambda nodes: {'feat': torch.zeros(nodes.data['feat'].shape)}, ntype='b')
mfgs[-1].dstdata['feat']= {'a': torch.zeros(mfgs[-1].dstdata['feat']['a'].shape)}

Calling mfgs[-1].srcdata['feat'] / mfgs[-1].ndata['feat'] shows updated zero features where mfgs[-1].dstdata['feat'] returns unchanged dict.

# srdata output
{'a': tensor([[0.],
         [0.],
         [0.],
         [0.],
         [0.],
         [0.]]),
 'b': tensor([[0., 0.],
         [0., 0.],
         [0., 0.],
         [0., 0.],
         [0., 0.]])}
# dstdata output
{'a': tensor([[1.],
         [1.],
         [1.],
         [1.],
         [1.],
         [1.]]),
 'b': tensor([[1., 1.],
         [1., 1.],
         [1., 1.],
         [1., 1.],
         [1., 1.]])}

I imagine it’s tied to how the dst_data view is generated, or some callback etc. I don’t really undestand your intended use case but maybe the one the only @mufeili could provide some insight? Is this the expected behavior?

“block.apply_nodes()” is easier than “block.ndata[property_name] = a_new_dict” !Thanks to your advice,I can change block.ndata. And we still don’t know how to change block.dstdata. But that’s ok,the change of block.ndata also solve my problem. Thanks, GC.