项目文件夹

文件
Chen Sirui afc83aa216 Graphsim (#2794)
* Add hgat example

* Add experiment

* Clean code

* clear the code

* Add index in README

* Add index in README

* Add index in README

* Add index in README

* Add index in README

* Add index in README

* Change the code title and folder name

* Ready to merge

* Prepare for rebase and change message passing function

* use git ignore to handle empty file

* change file permission to resolve empty file

* Change permission

* change file mode

* Finish Coding

* working code cpu

* pyg compare

* Accelerate with batching

* FastMode Enabled

* update readme

* Update README.md

* refractor code

* add graphsim code

* modified code

* few fix

* Modified graphsim

* Simple Model Added

* Clean up code

* Refractor the code for Merge

* Bugfix enable gradient when train

* update readme and format

Co-authored-by: Chen <chesirui@3c22fbe5458c.ant.amazon.com>
Co-authored-by: Tianjun Xiao <xiaotj1990327@gmail.com>
Co-authored-by: Ubuntu <ubuntu@ip-172-31-4-63.ap-northeast-1.compute.internal>
Co-authored-by: Ubuntu <ubuntu@ip-172-31-45-47.ap-northeast-1.compute.internal>
2021-04-12 19:02:36 +08:00

197 行
6.6 KiB
Python

import dgl
import torch
import torch.nn as nn
from torch.nn import functional as F
import dgl.nn as dglnn
import dgl.function as fn
import copy
from functools import partial
class MLP(nn.Module):
def __init__(self, in_feats, out_feats, num_layers=2, hidden=128):
super(MLP, self).__init__()
self.layers = nn.ModuleList()
layer = nn.Linear(hidden, out_feats)
nn.init.normal_(layer.weight, std=0.1)
nn.init.zeros_(layer.bias)
self.layers.append(nn.Linear(in_feats, hidden))
if num_layers > 2:
for i in range(1, num_layers-1):
layer = nn.Linear(hidden, hidden)
nn.init.normal_(layer.weight, std=0.1)
nn.init.zeros_(layer.bias)
self.layers.append(layer)
layer = nn.Linear(hidden, out_feats)
nn.init.normal_(layer.weight, std=0.1)
nn.init.zeros_(layer.bias)
self.layers.append(layer)
def forward(self, x):
for l in range(len(self.layers)-1):
x = self.layers[l](x)
x = F.relu(x)
x = self.layers[-1](x)
return x
class PrepareLayer(nn.Module):
'''
Generate edge feature for the model input preparation:
as well as do the normalization work.
Parameters
==========
node_feats : int
Number of node features
stat : dict
dictionary which represent the statistics needed for normalization
'''
def __init__(self, node_feats, stat):
super(PrepareLayer, self).__init__()
self.node_feats = node_feats
# stat {'median':median,'max':max,'min':min}
self.stat = stat
def normalize_input(self, node_feature):
return (node_feature-self.stat['median'])*(2/(self.stat['max']-self.stat['min']))
def forward(self, g, node_feature):
with g.local_scope():
node_feature = self.normalize_input(node_feature)
g.ndata['feat'] = node_feature # Only dynamic feature
g.apply_edges(fn.u_sub_v('feat', 'feat', 'e'))
edge_feature = g.edata['e']
return node_feature, edge_feature
class InteractionNet(nn.Module):
'''
Simple Interaction Network
One Layer interaction network for stellar multi-body problem simulation,
it has the ability to simulate number of body motion no more than 12
Parameters
==========
node_feats : int
Number of node features
stat : dict
Statistcics for Denormalization
'''
def __init__(self, node_feats, stat):
super(InteractionNet, self).__init__()
self.node_feats = node_feats
self.stat = stat
edge_fn = partial(MLP, num_layers=5, hidden=150)
node_fn = partial(MLP, num_layers=2, hidden=100)
self.in_layer = InteractionLayer(node_feats-3, # Use velocity only
node_feats,
out_node_feats=2,
out_edge_feats=50,
edge_fn=edge_fn,
node_fn=node_fn,
mode='n_n')
# Denormalize Velocity only
def denormalize_output(self, out):
return out*(self.stat['max'][3:5]-self.stat['min'][3:5])/2+self.stat['median'][3:5]
def forward(self, g, n_feat, e_feat, global_feats, relation_feats):
with g.local_scope():
out_n, out_e = self.in_layer(
g, n_feat, e_feat, global_feats, relation_feats)
out_n = self.denormalize_output(out_n)
return out_n, out_e
class InteractionLayer(nn.Module):
'''
Implementation of single layer of interaction network
Parameters
==========
in_node_feats : int
Number of node features
in_edge_feats : int
Number of edge features
out_node_feats : int
Number of node feature after one interaction
out_edge_feats : int
Number of edge features after one interaction
global_feats : int
Number of global features used as input
relate_feats : int
Feature related to the relation between object themselves
edge_fn : torch.nn.Module
Function to update edge feature in message generation
node_fn : torch.nn.Module
Function to update node feature in message aggregation
mode : str
Type of message should the edge carry
nne : [src_feat,dst_feat,edge_feat] node feature concat edge feature.
n_n : [src_feat-edge_feat] node feature subtract from each other.
'''
def __init__(self, in_node_feats,
in_edge_feats,
out_node_feats,
out_edge_feats,
global_feats=1,
relate_feats=1,
edge_fn=nn.Linear,
node_fn=nn.Linear,
mode='nne'): # 'n_n'
super(InteractionLayer, self).__init__()
self.in_node_feats = in_node_feats
self.in_edge_feats = in_edge_feats
self.out_edge_feats = out_edge_feats
self.out_node_feats = out_node_feats
self.mode = mode
# MLP for message passing
input_shape = 2*self.in_node_feats + \
self.in_edge_feats if mode == 'nne' else self.in_edge_feats+relate_feats
self.edge_fn = edge_fn(input_shape,
self.out_edge_feats) # 50 in IN paper
self.node_fn = node_fn(self.in_node_feats+self.out_edge_feats+global_feats,
self.out_node_feats)
# Should be done by apply edge
def update_edge_fn(self, edges):
x = torch.cat([edges.src['feat'], edges.dst['feat'],
edges.data['feat']], dim=1)
ret = F.relu(self.edge_fn(
x)) if self.mode == 'nne' else self.edge_fn(x)
return {'e': ret}
# Assume agg comes from build in reduce
def update_node_fn(self, nodes):
x = torch.cat([nodes.data['feat'], nodes.data['agg']], dim=1)
ret = F.relu(self.node_fn(
x)) if self.mode == 'nne' else self.node_fn(x)
return {'n': ret}
def forward(self, g, node_feats, edge_feats, global_feats, relation_feats):
# print(node_feats.shape,global_feats.shape)
g.ndata['feat'] = torch.cat([node_feats, global_feats], dim=1)
g.edata['feat'] = torch.cat([edge_feats, relation_feats], dim=1)
if self.mode == 'nne':
g.apply_edges(self.update_edge_fn)
else:
g.edata['e'] = self.edge_fn(g.edata['feat'])
g.update_all(fn.copy_e('e', 'msg'),
fn.sum('msg', 'agg'),
self.update_node_fn)
return g.ndata['n'], g.edata['e']