2090741942justin's picture
Upload mp_20 PXRDNet workspace
39c21b2 verified
Raw
History Blame Contribute Delete
4.96 kB
"""
Copyright (c) Facebook, Inc. and its affiliates.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
"""
import torch
from ..initializers import he_orthogonal_init
class EfficientInteractionDownProjection(torch.nn.Module):
"""
Down projection in the efficient reformulation.
Parameters
----------
emb_size_interm: int
Intermediate embedding size (down-projection size).
kernel_initializer: callable
Initializer of the weight matrix.
"""
def __init__(
self,
num_spherical: int,
num_radial: int,
emb_size_interm: int,
):
super().__init__()
self.num_spherical = num_spherical
self.num_radial = num_radial
self.emb_size_interm = emb_size_interm
self.reset_parameters()
def reset_parameters(self):
self.weight = torch.nn.Parameter(
torch.empty(
(self.num_spherical, self.num_radial, self.emb_size_interm)
),
requires_grad=True,
)
he_orthogonal_init(self.weight)
def forward(self, rbf, sph, id_ca, id_ragged_idx):
"""
Arguments
---------
rbf: torch.Tensor, shape=(1, nEdges, num_radial)
sph: torch.Tensor, shape=(nEdges, Kmax, num_spherical)
id_ca
id_ragged_idx
Returns
-------
rbf_W1: torch.Tensor, shape=(nEdges, emb_size_interm, num_spherical)
sph: torch.Tensor, shape=(nEdges, Kmax, num_spherical)
Kmax = maximum number of neighbors of the edges
"""
num_edges = rbf.shape[1]
# MatMul: mul + sum over num_radial
rbf_W1 = torch.matmul(rbf, self.weight)
# (num_spherical, nEdges , emb_size_interm)
rbf_W1 = rbf_W1.permute(1, 2, 0)
# (nEdges, emb_size_interm, num_spherical)
# Zero padded dense matrix
# maximum number of neighbors, catch empty id_ca with maximum
if sph.shape[0] == 0:
Kmax = 0
else:
Kmax = torch.max(
torch.max(id_ragged_idx + 1),
torch.tensor(0).to(id_ragged_idx.device),
)
sph2 = sph.new_zeros(num_edges, Kmax, self.num_spherical)
sph2[id_ca, id_ragged_idx] = sph
sph2 = torch.transpose(sph2, 1, 2)
# (nEdges, num_spherical/emb_size_interm, Kmax)
return rbf_W1, sph2
class EfficientInteractionBilinear(torch.nn.Module):
"""
Efficient reformulation of the bilinear layer and subsequent summation.
Parameters
----------
units_out: int
Embedding output size of the bilinear layer.
kernel_initializer: callable
Initializer of the weight matrix.
"""
def __init__(
self,
emb_size: int,
emb_size_interm: int,
units_out: int,
):
super().__init__()
self.emb_size = emb_size
self.emb_size_interm = emb_size_interm
self.units_out = units_out
self.reset_parameters()
def reset_parameters(self):
self.weight = torch.nn.Parameter(
torch.empty(
(self.emb_size, self.emb_size_interm, self.units_out),
requires_grad=True,
)
)
he_orthogonal_init(self.weight)
def forward(
self,
basis,
m,
id_reduce,
id_ragged_idx,
):
"""
Arguments
---------
basis
m: quadruplets: m = m_db , triplets: m = m_ba
id_reduce
id_ragged_idx
Returns
-------
m_ca: torch.Tensor, shape=(nEdges, units_out)
Edge embeddings.
"""
# num_spherical is actually num_spherical**2 for quadruplets
(rbf_W1, sph) = basis
# (nEdges, emb_size_interm, num_spherical), (nEdges, num_spherical, Kmax)
nEdges = rbf_W1.shape[0]
# Create (zero-padded) dense matrix of the neighboring edge embeddings.
Kmax = torch.max(
torch.max(id_ragged_idx) + 1,
torch.tensor(0).to(id_ragged_idx.device),
)
# maximum number of neighbors, catch empty id_reduce_ji with maximum
m2 = m.new_zeros(nEdges, Kmax, self.emb_size)
m2[id_reduce, id_ragged_idx] = m
# (num_quadruplets or num_triplets, emb_size) -> (nEdges, Kmax, emb_size)
sum_k = torch.matmul(sph, m2) # (nEdges, num_spherical, emb_size)
# MatMul: mul + sum over num_spherical
rbf_W1_sum_k = torch.matmul(rbf_W1, sum_k)
# (nEdges, emb_size_interm, emb_size)
# Bilinear: Sum over emb_size_interm and emb_size
m_ca = torch.matmul(rbf_W1_sum_k.permute(2, 0, 1), self.weight)
# (emb_size, nEdges, units_out)
m_ca = torch.sum(m_ca, dim=0)
# (nEdges, units_out)
return m_ca