File size: 11,101 Bytes
2d448dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | from .MyUtils import color_print, pyg_data_to_dgl_graph
import torch
import dgl
from dgl.data import FraudAmazonDataset, FraudYelpDataset
import torch_geometric
from torch_geometric.transforms import GDC
from torch_geometric.data import Data, Dataset, DataLoader
from torch_geometric.utils import to_dense_adj, dense_to_sparse
from sklearn.model_selection import train_test_split
from tqdm import tqdm
def splitDataset(index, label, train_ratio):
idx_train, idx_rest, y_train, y_rest = train_test_split(index, label[index], stratify=label[index],
train_size=train_ratio,
random_state=2, shuffle=True)
idx_valid, idx_test, y_valid, y_test = train_test_split(idx_rest, y_rest, stratify=y_rest,
test_size=0.5,
random_state=2, shuffle=True)
train_mask = torch.zeros([len(label)]).bool()
val_mask = torch.zeros([len(label)]).bool()
test_mask = torch.zeros([len(label)]).bool()
train_mask[idx_train] = 1
val_mask[idx_valid] = 1
test_mask[idx_test] = 1
return train_mask, val_mask, test_mask
def nodeSelect(graph_pyg, nodes_per_subgraph):
num = graph_pyg.x.shape[0]
num_selected = num - num % nodes_per_subgraph
if num_selected:
feat_selected=graph_pyg.x[:num_selected]
label_selected=graph_pyg.y[:num_selected]
train_mask_selected=graph_pyg.train_mask[:num_selected]
test_mask_selected=graph_pyg.test_mask[:num_selected]
val_mask_selected=graph_pyg.val_mask[:num_selected]
edge_index_selected_mask=(graph_pyg.edge_index[0] < num_selected) & (graph_pyg.edge_index[1] < num_selected)
edge_index_unselected=graph_pyg.edge_index[:,~edge_index_selected_mask]
edge_index_selected=graph_pyg.edge_index[:,edge_index_selected_mask]
graph_pyg_selected=Data(x=feat_selected,
edge_index=edge_index_selected,
y=label_selected,
train_mask=train_mask_selected,
val_mask=val_mask_selected,
test_mask=test_mask_selected)
print(f'num_seleced: {num_selected}/{num}')
return graph_pyg_selected, edge_index_unselected
def nodeSample(graph_pyg, nodes_per_subgraph):
color_print(f'!!!!! Start node sampling')
num = graph_pyg.x.shape[0]
num_selected = num - num % nodes_per_subgraph
subgraphs=[]
for i in tqdm(range(num_selected//nodes_per_subgraph)):
start_idx = i * nodes_per_subgraph
subset=torch.arange(start_idx,start_idx+nodes_per_subgraph)
sub_edge_index = torch_geometric.utils.subgraph(subset,graph_pyg.edge_index,num_nodes=graph_pyg.num_nodes)[0] - i*nodes_per_subgraph
sub_x=graph_pyg.x[start_idx:start_idx + nodes_per_subgraph]
sub_new_x=graph_pyg.new_x[start_idx:start_idx + nodes_per_subgraph]
sub_y=graph_pyg.y[start_idx:start_idx + nodes_per_subgraph]
sub_adj=to_dense_adj(sub_edge_index,max_num_nodes=nodes_per_subgraph)[0]
sub_train_mask=graph_pyg.train_mask[start_idx:start_idx+nodes_per_subgraph]
sub_val_mask=graph_pyg.val_mask[start_idx:start_idx+nodes_per_subgraph]
sub_test_mask=graph_pyg.test_mask[start_idx:start_idx+nodes_per_subgraph]
sub_data=Data(x=sub_x,new_x=sub_new_x,edge_index=sub_edge_index,y=sub_y,adj=sub_adj,train_mask=sub_train_mask,val_mask=sub_val_mask,test_mask=sub_test_mask)
subgraphs.append(sub_data)
color_print(f'!!!!! Finish node sampling')
return subgraphs
def sampleCheck(node_groups, nodes_per_subgraph):
cnt=0
wrong_num=0
for g in node_groups:
if g.x.shape[0]!=nodes_per_subgraph:
color_print(g.x.shape[0],cnt)
color_print(f'!!!!! Sampling check false')
wrong_num=wrong_num+1
cnt=cnt+1
if not wrong_num:
color_print(f'!!!!! Sampling check true')
def loadDataset(dataset, train_ratio):
if dataset=='yelp':
graph_dgl = FraudYelpDataset()[0]
graph_dgl = dgl.to_homogeneous(graph_dgl,ndata=['feature', 'label', 'train_mask', 'val_mask', 'test_mask'])
graph_dgl = dgl.add_self_loop(graph_dgl)
feat = graph_dgl.ndata['feature'].float()
label = graph_dgl.ndata['label'].long()
edge_index = torch.stack(graph_dgl.edges(etype=('_N', '_E', '_N')))
index = list(range(len(label)))
train_mask, val_mask, test_mask = splitDataset(index,label,train_ratio)
graph_pyg=Data(x=feat,edge_index=edge_index,y=label,train_mask=train_mask,val_mask=val_mask,test_mask=test_mask)
graph_dgl.ndata['train_mask']=train_mask
graph_dgl.ndata['val_mask']=val_mask
graph_dgl.ndata['test_mask']=test_mask
elif dataset=='amazon':
graph_dgl = FraudAmazonDataset()[0]
graph_dgl = dgl.to_homogeneous(graph_dgl,ndata=['feature', 'label', 'train_mask', 'val_mask', 'test_mask'])
graph_dgl = dgl.add_self_loop(graph_dgl)
feat = graph_dgl.ndata['feature'].float()
label = graph_dgl.ndata['label'].long()
edge_index = torch.stack(graph_dgl.edges(etype=('_N', '_E', '_N')))
index = list(range(3305, len(label)))
train_mask, val_mask, test_mask = splitDataset(index,label,train_ratio)
graph_pyg=Data(x=feat,edge_index=edge_index,y=label,train_mask=train_mask,val_mask=val_mask,test_mask=test_mask)
graph_dgl.ndata['train_mask']=train_mask
graph_dgl.ndata['val_mask']=val_mask
graph_dgl.ndata['test_mask']=test_mask
elif dataset=='blogcatalog':
bc_path = f'../bc.pt'
graph_pyg = torch.load(bc_path)[0]
graph_pyg.edge_index = graph_pyg.edge_indexes[0]
graph_dgl = pyg_data_to_dgl_graph(graph_pyg)
label = graph_dgl.ndata['label'].long()
index = list(range(len(label)))
train_mask, val_mask, test_mask = splitDataset(index,label,train_ratio)
graph_pyg.train_mask=train_mask
graph_pyg.val_mask=val_mask
graph_pyg.test_mask=test_mask
graph_dgl.ndata['train_mask']=train_mask
graph_dgl.ndata['val_mask']=val_mask
graph_dgl.ndata['test_mask']=test_mask
else:
print(f'{dataset}-graph_dgl not exist')
return None
color_print(f'{dataset}_graph_dgl: ')
print(f'{graph_dgl}')
color_print(f'{dataset}_graph_pyg: ')
print(f'{graph_pyg}')
color_print(f'train_val_test split')
print(f'train_num: {train_mask.sum()}; val_num: {val_mask.sum()}; test_num: {test_mask.sum()}')
return graph_dgl, graph_pyg, train_mask, val_mask, test_mask
def mergeGraphDataList(args, graph_pyg, syn_relation_dict):
# 初始化合并后的组件
x, y, new_x, edge_index = [], [], [], []
adj_matrices = []
ddpm_train_mask, ddpm_val_mask, ddpm_test_mask = [], [], []
cum_num_nodes = 0 # 累积节点数,用于更新edge_index
new_x_ssupgcl=syn_relation_dict['graph_pyg_ssupgcl_new_x']
for data in syn_relation_dict['syn_relation_list']:
# for data in syn_relation_dict['new_data_list']:
# 更新节点特征和标签
x.append(data.x)
new_x.append(data.new_x)
y.append(data.y)
# 更新edge_index
current_edge_index = data.edge_index + cum_num_nodes
edge_index.append(current_edge_index)
# 更新邻接矩阵
adj_matrices.append(data.adj)
# 更新掩码
ddpm_train_mask.append(data.train_mask)
ddpm_val_mask.append(data.val_mask)
ddpm_test_mask.append(data.test_mask)
# 更新节点累计数
cum_num_nodes += data.num_nodes
node_per_subgraph=args.nodes_per_subgraph
num_unselected=graph_pyg.x.shape[0] % node_per_subgraph
num_unselected
# 合并所有组件
new_x = torch.cat(new_x, dim=0)
new_x = torch.cat([new_x, new_x_ssupgcl[-num_unselected:]],dim=0)
x = torch.cat(x, dim=0)
x = torch.cat([x, graph_pyg.x[-num_unselected:]],dim=0)
y = torch.cat(y, dim=0)
y = torch.cat([y, graph_pyg.y[-num_unselected:]],dim=0)
edge_index = torch.cat(edge_index, dim=1)
# edge_index = torch.cat([edge_index, ddpm_yelp_unselected_edge_index], dim=1)
edge_index = torch.cat([edge_index, syn_relation_dict['unselected_edge_index']], dim=1)
# edge_index = torch.cat([edge_index, syn_relation_dict['yelp_unselected_edge_index']], dim=1)
ddpm_train_mask = torch.cat(ddpm_train_mask, dim=0)
ddpm_train_mask = torch.cat([ddpm_train_mask, graph_pyg.train_mask[-num_unselected:]], dim=0)
ddpm_val_mask = torch.cat(ddpm_val_mask, dim=0)
ddpm_val_mask = torch.cat([ddpm_val_mask, graph_pyg.val_mask[-num_unselected:]], dim=0)
ddpm_test_mask = torch.cat(ddpm_test_mask, dim=0)
ddpm_test_mask = torch.cat([ddpm_test_mask, graph_pyg.test_mask[-num_unselected:]], dim=0)
# 创建新的Data对象
if args.dataset=='blogcatalog' and args.GuiDDPM_sample_with_guidance: # blogcatalog 要降维
merged_data = Data(x=new_x, edge_index=edge_index, y=y, train_mask=ddpm_train_mask, val_mask=ddpm_val_mask, test_mask=ddpm_test_mask)
else:
merged_data = Data(x=x, edge_index=edge_index, y=y, train_mask=ddpm_train_mask, val_mask=ddpm_val_mask, test_mask=ddpm_test_mask)
return merged_data
def GDCAugment(graph_pyg_type, avg_degree):
# 应用 GDC 转换
gdc = GDC(self_loop_weight=1, normalization_in='sym',
normalization_out='col', diffusion_kwargs=dict(method='ppr', alpha=0.05),
sparsification_kwargs=dict(method='threshold', avg_degree=avg_degree), exact=True)
graph_pyg_type.transform = gdc
gdc_transformed_data = gdc(graph_pyg_type) # 应用 GDC 转换
return gdc_transformed_data
def data4WFusionTrain(graph_pyg, graph_syn, graph_gdc_list):
new_edges_dict = {}
new_edges_dict[('node', 'relation0', 'node')] = (graph_pyg.edge_index[0], graph_pyg.edge_index[1])
new_edges_dict[('node', 'relation1', 'node')] = (graph_syn.edge_index[0], graph_syn.edge_index[1])
for idx, graph_gdc in enumerate(graph_gdc_list, start=2):
new_edges_dict[(f'node', f'relation{idx}', f'node')] = (graph_gdc.edge_index[0], graph_gdc.edge_index[1])
# 设置节点总数
num_nodes = graph_syn.x.shape[0]
# 创建异构图时显式指定节点的数量
graph_WFusion = dgl.heterograph(new_edges_dict, num_nodes_dict={'node': num_nodes})
# 设置节点特征和标签
graph_WFusion.nodes['node'].data['feature'] = graph_syn.x
graph_WFusion.nodes['node'].data['label'] = graph_syn.y
graph_WFusion.nodes['node'].data['train_mask'] = graph_syn.train_mask
graph_WFusion.nodes['node'].data['test_mask'] = graph_syn.test_mask
graph_WFusion.nodes['node'].data['val_mask'] = graph_syn.val_mask
return graph_WFusion |