| 202 | # return pred |
| 203 | |
| 204 | class GraphMAE(nn.Module): |
| 205 | |
| 206 | EPS = 1e-15 |
| 207 | |
| 208 | def __init__(self, in_dim, emb_dim, num_layer, kernel='gcn', drop_ratio=0, |
| 209 | act='relu', norm=None, concat=False, mask_ratio=0.5, replace_ratio=0): |
| 210 | super().__init__() |
| 211 | |
| 212 | self.emb_dim = emb_dim if not concat else num_layer * emb_dim |
| 213 | self.mask_ratio = mask_ratio |
| 214 | self.replace_ratio = replace_ratio |
| 215 | |
| 216 | self.encoder = Encoder(in_dim, emb_dim, num_layer, kernel, drop_ratio, act, norm, |
| 217 | concat=False, last_act=True, aggr='mean') |
| 218 | self.decoder = Encoder(emb_dim, in_dim, 1, kernel, drop_ratio, act, norm=None, |
| 219 | concat=False, last_act=False, aggr='mean') |
| 220 | |
| 221 | self.encoder_mask_token = nn.Parameter(torch.zeros(1, in_dim)) |
| 222 | self.encoder_to_decoder = nn.Linear(self.emb_dim, emb_dim, bias=False) |
| 223 | |
| 224 | |
| 225 | def forward(self, x, edge_index, edge_weigt=None, batch=None): |
| 226 | # Mask |
| 227 | mask_x, mask_nodes = self.encding_mask(x) |
| 228 | h = self.encoder(mask_x, edge_index, edge_weigt, batch) |
| 229 | h = self.encoder_to_decoder(h) |
| 230 | |
| 231 | # Re-mask |
| 232 | h[mask_nodes] = 0 |
| 233 | recon = self.decoder(h, edge_index, edge_weigt, batch) |
| 234 | |
| 235 | return x[mask_nodes], recon[mask_nodes] |
| 236 | |
| 237 | |
| 238 | def encding_mask(self, x): |
| 239 | |
| 240 | num_nodes = x.shape[0] |
| 241 | |
| 242 | # random masking |
| 243 | perm = torch.randperm(num_nodes, device=x.device) |
| 244 | num_mask_nodes = int(self.mask_ratio * num_nodes) |
| 245 | mask_nodes = perm[: num_mask_nodes] |
| 246 | # keep_nodes = perm[num_mask_nodes: ] |
| 247 | |
| 248 | if self.replace_ratio > 0: |
| 249 | num_noise_nodes = int(self.replace_ratio * num_mask_nodes) |
| 250 | perm_mask = torch.randperm(num_mask_nodes, device=x.device) |
| 251 | token_nodes = mask_nodes[perm_mask[: int((1 - self.replace_ratio) * num_mask_nodes)]] |
| 252 | noise_nodes = mask_nodes[perm_mask[-int(self.replace_ratio * num_mask_nodes):]] |
| 253 | noise_to_be_chosen = torch.randperm(num_nodes, device=x.device)[:num_noise_nodes] |
| 254 | |
| 255 | out_x = x.clone() |
| 256 | out_x[token_nodes] = 0.0 |
| 257 | out_x[noise_nodes] = x[noise_to_be_chosen] |
| 258 | else: |
| 259 | out_x = x.clone() |
| 260 | token_nodes = mask_nodes |
| 261 | out_x[mask_nodes] = 0.0 |
nothing calls this directly
no outgoing calls
no test coverage detected