Source code for UM2N.model.MRN_GTE

# Author: Chunyang Wang
# GitHub Username: acse-cw1722
# Modified by Mingrui Zhang

import os
import sys

import torch
import torch.nn as nn
import torch.nn.functional as F

cur_dir = os.path.dirname(__file__)
sys.path.append(cur_dir)
from deformer import (  # noqa: E402
    RecurrentGATConv,
)
from extractor import (  # noqa: E402
    LocalFeatExtractor,
)
from transformer_model import TransformerModel

__all__ = ["MRNGlobalTransformerEncoder"]


[docs] class MRNGlobalTransformerEncoder(torch.nn.Module): """ Mesh Refinement Network (MRN) implementing global and local feature extraction and recurrent graph-based deformations. The global feature extraction is performed by a transformer. Attributes: num_loop (int): Number of loops for the recurrent layer. gfe_out_c (int): Output channels for global feature extractor. lfe_out_c (int): Output channels for local feature extractor. hidden_size (int): Size of the hidden layer. gfe (GlobalFeatExtractor): Global feature extractor. lfe (LocalFeatExtractor): Local feature extractor. lin (nn.Linear): Linear layer for feature transformation. deformer (RecurrentGATConv): GAT-based deformer block. """ def __init__(self, gfe_in_c=2, lfe_in_c=4, deform_in_c=7, num_loop=3): """ Initialize MRN. Args: gfe_in_c (int): Input channels for the global feature extractor. lfe_in_c (int): Input channels for the local feature extractor. deform_in_c (int): Input channels for the deformer block. num_loop (int): Number of loops for the recurrent layer. """ super().__init__() self.num_loop = num_loop self.gfe_out_c = 16 self.lfe_out_c = 16 self.hidden_size = 512 # set here # minus 2 because we are not using x,y coord (first 2 channels) self.all_feat_c = (deform_in_c - 2) + self.gfe_out_c + self.lfe_out_c # self.gfe = GlobalFeatExtractor(in_c=gfe_in_c, out_c=self.gfe_out_c) self.lfe = LocalFeatExtractor(num_feat=lfe_in_c, out=self.lfe_out_c) self.transformer_out_dim = 16 self.transformer_encoder = TransformerModel( input_dim=2, embed_dim=64, output_dim=self.transformer_out_dim, num_heads=4, num_layers=1, ) # use a linear layer to transform the input feature to hidden # state size self.lin = nn.Linear(self.all_feat_c, self.hidden_size) self.deformer = RecurrentGATConv( coord_size=2, hidden_size=self.hidden_size, heads=6, concat=False ) # self.deformer = GATDeformerBlock(in_dim=self.deformer_in_feat) def _forward(self, data): """ Forward pass for MRN. Args: data (Data): Input data object containing mesh and feature info. Returns: coord (Tensor): Deformed coordinates. """ conv_feat_in = data.conv_feat # [batch_size, feat, grid, grid] batch_size = conv_feat_in.shape[0] mesh_feat = data.mesh_feat # [num_nodes * batch_size, 4] edge_idx = data.edge_index # [num_edges * batch_size, 2] # mesh_feat [coord_x, coord_y, u, hessian_norm] # Here we select the u and hessian_norm for global feature extraction global_feat = self.transformer_encoder( mesh_feat[:, :2].reshape(batch_size, -1, 2) ) global_feat = global_feat.reshape(-1, self.transformer_out_dim) local_feat = self.lfe(mesh_feat, edge_idx) hidden_in = torch.cat([data.x[:, 2:], local_feat, global_feat], dim=1) hidden = F.selu(self.lin(hidden_in)) return hidden
[docs] def move(self, data, num_step=1): """ Move the mesh according to the deformation learned, with given number steps. Args: data (Data): Input data object containing mesh and feature info. num_step (int): Number of deformation steps. Returns: coord (Tensor): Deformed coordinates. """ coord = data.x[:, :2] edge_idx = data.edge_index hidden = self._forward(data) # Recurrent GAT deform for i in range(num_step): coord, hidden = self.deformer(coord, hidden, edge_idx) return coord
[docs] def forward(self, data): """ Forward pass for MRN. Args: data (Data): Input data object containing mesh and feature info. Returns: coord (Tensor): Deformed coordinates. """ coord = data.x[:, :2] edge_idx = data.edge_index hidden = self._forward(data) # Recurrent GAT deform for i in range(self.num_loop): coord, hidden = self.deformer(coord, hidden, edge_idx) return coord