| """ |
| 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] |
|
|
| |
| rbf_W1 = torch.matmul(rbf, self.weight) |
| |
| rbf_W1 = rbf_W1.permute(1, 2, 0) |
| |
|
|
| |
| |
| 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) |
| |
|
|
| 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. |
| """ |
| |
| (rbf_W1, sph) = basis |
| |
| nEdges = rbf_W1.shape[0] |
|
|
| |
| Kmax = torch.max( |
| torch.max(id_ragged_idx) + 1, |
| torch.tensor(0).to(id_ragged_idx.device), |
| ) |
| |
| m2 = m.new_zeros(nEdges, Kmax, self.emb_size) |
| m2[id_reduce, id_ragged_idx] = m |
| |
|
|
| sum_k = torch.matmul(sph, m2) |
|
|
| |
| rbf_W1_sum_k = torch.matmul(rbf_W1, sum_k) |
| |
|
|
| |
| m_ca = torch.matmul(rbf_W1_sum_k.permute(2, 0, 1), self.weight) |
| |
| m_ca = torch.sum(m_ca, dim=0) |
| |
|
|
| return m_ca |
|
|