Files
dgl/tests/python/pytorch/mpops/test_edgewise.py
Hongzhi (Steve), Chen 8a83027274 [Misc] Merge test utils. (#5440)
* merge

* format

* rename

* sort

* sort

* update

* update

* update

* Update tests/utils/checks.py

Co-authored-by: Mufei Li <mufeili1996@gmail.com>

---------

Co-authored-by: Ubuntu <ubuntu@ip-172-31-28-63.ap-northeast-1.compute.internal>
Co-authored-by: Mufei Li <mufeili1996@gmail.com>
2023-03-20 15:32:45 +08:00

210 lines
5.1 KiB
Python

import random
import backend as F
import dgl
import numpy as np
import pytest
import torch
from utils import parametrize_idtype
random.seed(42)
np.random.seed(42)
dgl.seed(42)
torch.random.manual_seed(42)
@parametrize_idtype
@pytest.mark.parametrize("feat_size", [(5,), ()])
def test_copy_u(idtype, feat_size):
ctx = F.ctx()
g = dgl.rand_graph(30, 100)
g = g.astype(idtype).to(ctx)
x = torch.randn(
(g.num_nodes(),) + feat_size, requires_grad=True, device=ctx
)
y = dgl.copy_u(g, x)
y.sum().backward()
x_grad = x.grad
x.grad.zero_()
u, v = g.edges()
y_true = x[u.long()]
y_true.sum().backward()
x_grad_true = x.grad
assert torch.allclose(y, y_true)
assert torch.allclose(x_grad, x_grad_true)
@parametrize_idtype
@pytest.mark.parametrize("feat_size", [(5,), ()])
def test_copy_u_hetero(idtype, feat_size):
ctx = F.ctx()
hg = dgl.heterograph(
{
("user", "follow", "user"): ([0, 1, 2], [2, 3, 4]),
("user", "like", "movie"): ([3, 3, 1, 2], [0, 0, 1, 1]),
}
)
hg = hg.astype(idtype).to(ctx)
x = torch.randn(
(hg.num_nodes("user"),) + feat_size, requires_grad=True, device=ctx
)
y = dgl.copy_u(hg, x, etype="like")
y.sum().backward()
x_grad = x.grad
x.grad.zero_()
u, v = hg.edges(etype="like")
y_true = x[u.long()]
y_true.sum().backward()
x_grad_true = x.grad
assert torch.allclose(y, y_true)
assert torch.allclose(x_grad, x_grad_true)
@parametrize_idtype
@pytest.mark.parametrize("feat_size", [(5,), ()])
def test_copy_v(idtype, feat_size):
ctx = F.ctx()
g = dgl.rand_graph(30, 100)
g = g.astype(idtype).to(ctx)
x = torch.randn(
(g.num_nodes(),) + feat_size, requires_grad=True, device=ctx
)
y = dgl.copy_v(g, x)
y.sum().backward()
x_grad = x.grad
x.grad.zero_()
u, v = g.edges()
y_true = x[v.long()]
y_true.sum().backward()
x_grad_true = x.grad
assert torch.allclose(y, y_true)
assert torch.allclose(x_grad, x_grad_true)
@parametrize_idtype
@pytest.mark.parametrize("feat_size", [(5,), ()])
def test_copy_v_hetero(idtype, feat_size):
ctx = F.ctx()
hg = dgl.heterograph(
{
("user", "follow", "user"): ([0, 1, 2], [2, 3, 4]),
("user", "like", "movie"): ([3, 3, 1, 2], [0, 0, 1, 1]),
}
)
hg = hg.astype(idtype).to(ctx)
x = torch.randn(
(hg.num_nodes("movie"),) + feat_size, requires_grad=True, device=ctx
)
y = dgl.copy_v(hg, x, etype="like")
y.sum().backward()
x_grad = x.grad
x.grad.zero_()
u, v = hg.edges(etype="like")
y_true = x[v.long()]
y_true.sum().backward()
x_grad_true = x.grad
assert torch.allclose(y, y_true)
assert torch.allclose(x_grad, x_grad_true)
binary_arg_sizes = [
((5,), (5,)),
((5,), ()),
((), (5,)),
((1, 3, 3), (4, 1, 3)),
((3, 3), (4, 1, 3)),
((4, 1, 3), (3, 3)),
]
dot_arg_sizes = [
((5,), (5,)),
((1, 3, 3), (4, 1, 3)),
((3, 3), (4, 1, 3)),
((4, 1, 3), (3, 3)),
]
ops = ["add", "sub", "mul", "div"]
def pad_shape(x, y, x_size, y_size):
xy_size = torch.broadcast_shapes(x_size, y_size)
new_x_size = (1,) * (len(xy_size) - len(x_size)) + x_size
new_y_size = (1,) * (len(xy_size) - len(y_size)) + y_size
new_x = x.view(-1, *new_x_size)
new_y = y.view(-1, *new_y_size)
return new_x, new_y
@parametrize_idtype
@pytest.mark.parametrize("op", ops)
@pytest.mark.parametrize("x_size,y_size", binary_arg_sizes)
def test_u_op_v(idtype, op, x_size, y_size):
ctx = F.ctx()
g = dgl.rand_graph(30, 100)
g = g.astype(idtype).to(ctx)
x = torch.randn((g.num_nodes(),) + x_size, requires_grad=True, device=ctx)
y = torch.randn((g.num_nodes(),) + y_size, requires_grad=True, device=ctx)
f_dgl = getattr(dgl, f"u_{op}_v")
z = f_dgl(g, x, y)
z.sum().backward()
x_grad = x.grad
y_grad = y.grad
x_grad.zero_()
y_grad.zero_()
u, v = g.edges()
f_torch = getattr(torch, op)
x_u, y_v = pad_shape(x[u.long()], y[v.long()], x_size, y_size)
z_true = f_torch(x_u, y_v)
z_true.sum().backward()
x_grad_true = x.grad
y_grad_true = y.grad
assert torch.allclose(z, z_true)
assert torch.allclose(x_grad, x_grad_true)
assert torch.allclose(y_grad, y_grad_true)
@parametrize_idtype
@pytest.mark.parametrize("x_size,y_size", dot_arg_sizes)
def test_u_dot_v(idtype, x_size, y_size):
ctx = F.ctx()
g = dgl.rand_graph(30, 100)
g = g.astype(idtype).to(ctx)
x = torch.randn((g.num_nodes(),) + x_size, requires_grad=True, device=ctx)
y = torch.randn((g.num_nodes(),) + y_size, requires_grad=True, device=ctx)
z = dgl.u_dot_v(g, x, y)
z.sum().backward()
x_grad = x.grad
y_grad = y.grad
x_grad.zero_()
y_grad.zero_()
u, v = g.edges()
x_u, y_v = pad_shape(x[u.long()], y[v.long()], x_size, y_size)
z_true = (x_u * y_v).sum(-1).unsqueeze(-1)
z_true.sum().backward()
x_grad_true = x.grad
y_grad_true = y.grad
assert torch.allclose(z, z_true, atol=1e-4, rtol=1e-4)
assert torch.allclose(x_grad, x_grad_true)
assert torch.allclose(y_grad, y_grad_true)