Ny sary dia fomba mahery vaika hanehoana angon-drakitra, misintona manokana ny fifandraisana misy eo amin'ireo sampan-draharaha amin'ny fampiharana isan-karazany. Na manao modely amin'ny tambajotra sosialy ianao, na fifandraisana amin'ny proteinina, na rafi-pitaterana, na maotera fanolorana, dia maneho sy mamakafaka ireo fifampiankinana be pitsiny ireo ny kisary. Amin'izao tontolo entin'ny angon-drakitra ankehitriny izao, ny fahatakarana ny fifandraisana misy eo amin'ny sampana dia matetika no zava-dehibe toy ny fahatakarana ireo sampan-draharaha ihany - eo no tena hamirapiratra ny sary.
Ny faminavinana rohy dia iray amin'ireo asa fototra amin'ny famakafakana grafika, ahitana ny faminaniana momba ny fifandraisana (na rohy) eo amin'ny nodes (ireo singa aseho amin'ny grafika). Alaivo sary an-tsaina ny fanolorana namana vaovao ao amin'ny tambajotra sosialy, maminavina ny mety ho fiaraha-miasa amin'ny kisary fanononana akademika, na maminavina ny fifandraisana amin'ny ho avy eo amin'ny mpampiasa sy ny vokatra amin'ny sehatra e-varotra - ireo rehetra ireo dia ohatra amin'ny vinavinan'ny rohy miasa. Ity asa ity dia manampy amin'ny fanitarana ny tambajotra, manatsoaka hevitra tsy hita, ary mamantatra ny tsy mety. Ho an'ny fampiharana manomboka amin'ny fanatsarana ny traikefan'ny mpampiasa ka hatramin'ny fanatsarana ny fitadiavana hosoka, ny vinavinan'ny rohy dia singa manan-danja amin'ny fahombiazana.
Mba hanehoana ny faminaniana momba ny rohy dia hampiasa ny angon-drakitra Twitch Social Network avy amin'ny Stanford Network Analysis Project (SNAP) izahay. Ity angona ity dia mirakitra ny fifandraisana ara-tsosialy misy eo amin'ireo mpampiasa amin'ny sehatra streaming Twitch, izay misy ny nodes maneho ny mpampiasa Twitch, ary ny sisiny dia maneho ny fisakaizana eo amin'izy ireo. Ny angon-drakitra dia voarafitra tsara, manamora ny fanodinana sy ny fiasana.
Amin'ny fanarahana azy dia hianatra ny fomba fananganana tetikasa, fanodinana angon-drakitra ianao, fananganana modely, ary hanombantombana izany ho an'ny vinavinan'ny rohy amin'ny angona tena izy.
Mitondra fanamby tsy manam-paharoa ny fiasana amin'ny angona voarafitra amin'ny grafika, ary eto no idiran'ny Graph Neural Networks (GNNs) . Tsy toy ny tambajotra neural nentim-paharazana izay miasa amin'ny fampidirana habe raikitra, ny GNN dia afaka mitantana ny haben'ny grafika tsy misy dikany ary mampiasa ny lamina mifandray amin'ny angon-drakitra. Amin'ny alàlan'ny fanangonana vaovao avy amin'ny mpifanolo-bodirindrina amin'ny node iray, ny GNN dia mianatra fanehoana izay mirakitra ny toetran'ny node sy ny firafitry ny grafika, ka mahatonga azy ireo hahomby amin'ny asa toy ny fanasokajiana node, faminaniana rohy, ary fanasokajiana ny grafika.
Ny Deep Graph Library ( DGL.ai ) dia fitaovana matanjaka amin'ny fananganana GNN amin'ny mora sy mahomby. Miaraka amin'ny DGL, ny mpamorona dia afaka mampiasa ny maritrano GNN manara-penitra mba hiatrehana asa isan-karazany, anisan'izany ny faminaniana rohy. Ny DGL dia manome fitaovana isan-karazany amin'ny fiasana amin'ny grafika homogeneous sy heterogène, ka mahatonga azy io ho fitaovana azo ampiasaina ho an'ny mpikaroka sy ny mpitsabo. Amin'ny fanatsorana ny fampiharana ny GNN, ny DGL dia mamela anao hifantoka bebe kokoa amin'ny famolavolana vahaolana vaovao fa tsy ho tafahitsoka amin'ny fahasarotana ara-teknika fototra.
Miaraka amin'ity fototra ity ao an-tsaina, andao isika hiditra amin'ny fananganana modely faminaniana rohy amin'ny fampiasana GNNs sy DGL.ai .
Ny dingana voalohany dia ny fametrahana ny tetikasantsika amin'ny fanafarana ireo tranomboky ilaina:
import json import numpy as np import pandas as pd import dgl from dgl.data import DGLDataset from dgl.nn import SAGEConv import torch import torch.nn as nn from torch.nn.functional import binary_cross_entropy_with_logits, relu, dropout from torch.nn.utils import clip_grad_norm_ from torch.optim.lr_scheduler import ReduceLROnPlateau import itertools import scipy.sparse as sp from sklearn.metrics import roc_auc_score
Mba hanomanana ny angon-drakitra ho an'ny fanofanana dia hampiditra ny angon-drakitra Twitch aloha isika, asehoy azy ho toy ny grafika, ary avy eo mizara izany ho andiana fiofanana sy fitsapana. Hamorona kilasy mahazatra izay mandova avy amin'ny DGLDataset izahay, izay hanampy amin'ny famolavolana ny fizotry ny fampidinana angona sy hanamafisana ny asa mifandraika amin'ny grafika.
Ity ny kaody hamoronana sy hanodinana mialoha ny angon-drakitra:
# create a dataset that inherits DGLDataset class SocialNetworkDataset(DGLDataset): def __init__(self): super().__init__(name='social_network') def process(self): # load edges edges_df = pd.read_csv('./twitch/ENGB/musae_ENGB_edges.csv') # ensure edges are bidirectional edges_df_rev = edges_df.copy() edges_df_rev.columns = ['to', 'from'] edges_df_rev = edges_df_rev[['from', 'to']] edges_df = pd.concat([edges_df, edges_df_rev], ignore_index=True) edges_df.drop_duplicates(inplace=True) # create a graph using DGL max_node_id = max(edges_df['from'].max(), edges_df['to'].max()) edges_src = torch.from_numpy(edges_df['from'].to_numpy()) edges_dst = torch.from_numpy(edges_df['to'].to_numpy()) self.graph = dgl.graph( (edges_src, edges_dst), num_nodes=max_node_id + 1, ) # load and node features with open('./twitch/ENGB/musae_ENGB_features.json') as f: node_features_dict = json.load(f) # feature lists have various lengths, pad them with zeros max_feature_list_len = max([len(l) for l in node_features_dict.values()]) for k in node_features_dict: if len(node_features_dict[k]) < max_feature_list_len: node_features_dict[k] += [0] * (max_feature_list_len - len(node_features_dict[k])) # set node features in graph node_features_df = pd.DataFrame.from_dict(node_features_dict).T.astype('float64') node_features_np = node_features_df.to_numpy() self.graph.ndata['feat'] = torch.from_numpy(node_features_np).float() def __len__(self): return 1 # only the whole graph is returned def __getitem__(self, idx): return self.graph
Atombohy izao ny angonay mba hampidirana ny angon-drakitra.
# init the dataset dataset = SocialNetworkDataset() g = dataset[0]
Ny dingana manaraka dia ny famoronana ny fiofanana sy ny fitsapana . Hozarainay ho 80/20 ny sisiny ho an'ny fiofanana sy fitsapana. Mamokatra santionany tsara (siny efa misy) sy ny santionany miiba (siny tsy misy) ho an'ny andiany roa izahay. Ho an'ny grafika lehibe kokoa, ny fitaovana dgl.sampling
an'ny DGL dia mety hanampy, fa eto, mifanaraka amin'ny fitadidiana ny kisary manontolo. Ity ny kaody hamoronana andiana fiofanana sy fitsapana:
# pick edges for train and test sets (80/20 split) # (for larger graphs, we can use dgl.sampling.negative etc) u, v = g.edges() edge_ids = np.random.permutation(g.num_edges()) test_set_size = int(len(edge_ids) * 0.2) train_set_size = len(edge_ids) - test_set_size # positive samples: existing edges test_positive_u, test_positive_v = u[edge_ids[:test_set_size]], v[edge_ids[:test_set_size]] train_positive_u, train_positive_v = u[edge_ids[test_set_size:]], v[edge_ids[test_set_size:]] # negative samples: nonexistent edges adj = sp.coo_matrix((np.ones(len(u)), (u.numpy(), v.numpy()))) adj_negative = 1 - adj.todense() - np.eye(g.num_nodes()) negative_u, negative_v = np.where(adj_negative != 0) negative_edge_ids = np.random.choice(len(negative_u), g.num_edges()) test_negative_u, test_negative_v = ( negative_u[negative_edge_ids[:test_set_size]], negative_v[negative_edge_ids[:test_set_size]], ) train_negative_u, train_negative_v = ( negative_u[negative_edge_ids[test_set_size:]], negative_v[negative_edge_ids[test_set_size:]], ) # create a training graph by copying the original graph and removing test edges train_g = dgl.remove_edges(g, edge_ids[:test_set_size]) # define positive and negative graphs for train and test sets train_positive_g = dgl.graph((train_positive_u, train_positive_v), num_nodes=g.num_nodes()) train_negative_g = dgl.graph((train_negative_u, train_negative_v), num_nodes=g.num_nodes()) test_positive_g = dgl.graph((test_positive_u, test_positive_v), num_nodes=g.num_nodes()) test_negative_g = dgl.graph((test_negative_u, test_negative_v), num_nodes=g.num_nodes())
Hampiasa tambajotra neural convolutional Graph Sample and Aggregate (GraphSAGE) izahay mba hianarana ny fanehoana ny node, fantatra ihany koa amin'ny hoe embeddings , izay mirakitra ny rafitra sy ny endrik'ireo node tsirairay ao anatin'ny grafika. GraphSAGE dia miasa amin'ny alàlan'ny fanangonana vaovao momba ny endri-javatra avy amin'ny mpifanolo-bodirindrina amin'ny node tsirairay mba hamoronana fanehoana manan-danja ho an'ny node tsirairay. Ity dingana ity, fantatra amin'ny anarana hoe fivondronan'ny mpifanolo-bodirindrina , dia ahafahan'ilay maodely mianatra lamina manankarena sy eo an-toerana ao amin'ny grafika.
Ao amin'ny sosona GraphSAGE tsirairay, ny maodely dia mampihatra asa aggregation (amin'ity tranga ity, ny asa "midika") mba hanangonana vaovao avy amin'ny nodes mifanolo-bodirindrina, izay avy eo miaraka amin'ny endri-javatra manokana ny node. Ny fametrahana sosona convolutional maro dia ahafahan'ny maodely maka vaovao avy amin'ny node miha-lavitra , manitatra amin'ny fomba mahomby ny fijerin'ny node tsirairay ao anatin'ny grafika.
Mba hanamafisana ny fahombiazan'ny modely sy hampihenana ny overfitting, dia hampiharina ny fialana aorian'ny sosona tsirairay.
Andeha isika hanangana ny maodely GraphSAGE miaraka amin'ny sosona convolutional telo , miaraka amin'ny fiasa forward
hamaritana ny fandehan'ny angona amin'izany:
# define the GraphSAGE model with 3 convolutional layers class GraphSAGE(nn.Module): def __init__( self, input_features, hidden_features, output_features, dropout_probability=0.3, ): super(GraphSAGE, self).__init__() self.conv_layer_1 = SAGEConv(input_features, hidden_features, "mean") self.conv_layer_2 = SAGEConv(hidden_features, hidden_features, "mean") self.conv_layer_3 = SAGEConv(hidden_features, output_features, "mean") self.dropout_probability = dropout_probability def forward(self, graph, input_features): # first layer with ReLU activation and dropout h = relu(self.conv_layer_1(graph, input_features)) h = dropout(h, p=self.dropout_probability) # second layer with ReLU activation and dropout h = relu(self.conv_layer_2(graph, h)) h = dropout(h, p=self.dropout_probability) # third layer without dropout h = self.conv_layer_3(graph, h) return h
Ny fivoahana aorian'ny sosona fahatelo ( h
) dia misy ny fametahana node. Mba haminavina ny mety hisian'ny sisiny (na rohy) eo anelanelan'ny node roa, dia hampiasa vinavina Multi-Layer Perceptron (MLP) isika. Ity MLP ity dia maka ny fidiran'ny node roa ho fampidirana ary manisa isa iray manondro ny mety hisian'ny sisiny misy eo anelanelan'izy ireo.
# define the MLP predictor class MLPPredictor(nn.Module): def __init__(self, hidden_features): super().__init__() # first linear layer to combine node embeddings self.W1 = nn.Linear(hidden_features * 2, hidden_features) # second linear layer to produce a single score output self.W2 = nn.Linear(hidden_features, 1) def apply_edges(self, edges): # concatenate source and destination node embeddings h = torch.cat([edges.src["h"], edges.dst["h"]], dim=1) # pass through MLP layers to get the edge score score = self.W2(relu(self.W1(h))).squeeze(1) return {'score': score} def forward(self, g, h): with g.local_scope(): g.ndata["h"] = h g.apply_edges(self.apply_edges) return g.edata["score"]
Ny mpamadika MLP dia miasa toy izao manaraka izao:
Ity fomba fiasa misy sosona ity dia ahafahan'ny mpamantatra haka ny fifandraisana saro-pady eo amin'ireo node tsiroaroa ary manisa naoty sisiny izay azo adika ho toy ny mety hisian'ny fisian'ny sisiny.
Mba hampiofanana amin'ny fomba mahomby ny maodely, dia mila asa fatiantoka izay afaka manombana ny fahombiazan'ny modely amin'ny faminaniana rohy. Satria olana fanasokajiana mimari-droa ity asa ity - izay misy na tsy misy ny rohy tsirairay - dia mampiasa cross-entropy binary (BCE) izahay ho toy ny fatiantoka. Ny cross-entropy binary dia mandrefy ny tsy fitovizan'ny isa vinavinain'ny maodely sy ny etikety tena izy (1 ho an'ny rohy efa misy, 0 ho an'ny tsy misy rohy). Mampiasa ny _with_logits
version izahay satria ny maodely dia mamoaka isa manta (logits) fa tsy probabilities. Ity dikan-tenin'ny BCE ity dia miorina kokoa rehefa miasa miaraka amin'ny logits, satria manambatra ny asa sigmoid sy ny cross-entropy ho dingana iray.
Ity ny code kajy ny fatiantoka:
def compute_loss(positive_logits, negative_logits): # concatenate positive and negative scores y_predicted = torch.cat([positive_logits, negative_logits]) # create true labels (1 for existing links, 0 for nonexistent) y_true = torch.cat([torch.ones(positive_logits.shape[0]), torch.zeros(negative_logits.shape[0])]) return binary_cross_entropy_with_logits(y_predicted, y_true)
Mba hanombanana ny modely dia mampiasa ny faritra eo ambanin'ny ROC Curve (AUC) metrika. Ny AUC dia mety tsara amin'ny vinavinan'ny rohy satria mitantana amin'ny fomba mahomby ny angon-drakitra tsy mifandanja , izay misy santionany ratsy (tsy misy sisiny) mahazatra kokoa noho ny santionany tsara. Ny naotin'ny AUC dia manome antsika ny fahatsapan'ny modely ny laharam-pahamehana ny rohy efa misy ambony noho ny tsy misy.
Ity ny kaody handinihana ny AUC:
def compute_auc(positive_logits, negative_logits): y_predicted = torch.cat([positive_logits, negative_logits]).detach().numpy() y_true = torch.cat([torch.ones(positive_logits.shape[0]), torch.zeros(negative_logits.shape[0])]).detach().numpy() return roc_auc_score(y_true, y_predicted)
Fanamarihana: Mampiasa detach()
izahay hanesorana ny tensor amin'ny tabilao kajy, ahafahantsika manisa ny AUC tsy misy fiantraikany amin'ny gradients.
Ankehitriny isika dia vonona ny hampiofana ny modely. Hanombohana, hasehontsika ny maodely, ny vinavina, ary ny optimizer, ary hamaritra ny tadivavarana fanofanana . Hofaritantsika ihany koa ny tahan'ny fianarana, ny haben'ny sosona miafina, ary ny tahan'ny fialana, ankoatry ny hyperparameter hafa. Na dia tsy handrakotra ny fanatsarana ny hyperparameter eto aza izahay , dia hampiasa fandaharam-potoana ny tahan'ny fianarana hanitsiana ny tahan'ny fianarana raha toa ny lembalemba fatiantoka - midika izany fa mijanona ny fihenany mandritra ny vanim-potoana voafaritra (amin'ity tranga ity, 25). Ny mpandrindra ny fandaharam-potoana dia manasasaka ny tahan'ny fianarana rehefa mitranga izany, izay afaka manampy ny modely hifanatona amin'ny fomba mahomby kokoa.
Ity ny kaody hanombohana ny modely sy hananganana fiofanana:
# init the model num_hidden_features = 32 model = GraphSAGE( train_g.ndata['feat'].shape[1], num_hidden_features, num_hidden_features, ) predictor = MLPPredictor(num_hidden_features) # create an optimizer and a learning rate scheduler learning_rate = 0.01 optimizer = torch.optim.Adam( itertools.chain(model.parameters(), predictor.parameters()), lr=learning_rate, ) lr_scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=25) # train the model num_epochs = 1000 for epoch in range(num_epochs + 1): # forward h = model(train_g, train_g.ndata['feat']) positive_logits = predictor(train_positive_g, h) negative_logits = predictor(train_negative_g, h) loss = compute_loss(positive_logits, negative_logits) # backward optimizer.zero_grad() loss.backward() # clip gradients clip_grad_norm_(model.parameters(), 1.0) optimizer.step() # adjust learning rate based on the loss lr_scheduler.step(loss) # print loss, current learning rate, and AUC if epoch % 100 == 0: last_lr = lr_scheduler.get_last_lr()[0] train_auc = compute_auc(positive_logits, negative_logits) print(f'Epoch: {epoch}, learning rate: {last_lr}, loss: {loss}, AUC: {train_auc}')
Andeha hojerentsika ny code ary diniho ny vokatra:
Epoch: 0, learning rate: 0.01, loss: 262.4156188964844, AUC: 0.4934097124994463 Epoch: 100, learning rate: 0.01, loss: 0.5642552375793457, AUC: 0.7473735298706314 Epoch: 200, learning rate: 0.01, loss: 0.4622882306575775, AUC: 0.8431058751115716 Epoch: 300, learning rate: 0.01, loss: 0.40566185116767883, AUC: 0.8777374138645864 Epoch: 400, learning rate: 0.01, loss: 0.38118976354599, AUC: 0.8944719038039551 Epoch: 500, learning rate: 0.01, loss: 0.3690297603607178, AUC: 0.9039401673234729 Epoch: 600, learning rate: 0.005, loss: 0.3579995930194855, AUC: 0.9112366798940639 Epoch: 700, learning rate: 0.005, loss: 0.3557407557964325, AUC: 0.9128097572016495 Epoch: 800, learning rate: 0.005, loss: 0.3510144352912903, AUC: 0.9152937255697913 Epoch: 900, learning rate: 0.00125, loss: 0.3425179123878479, AUC: 0.9202487786553115 Epoch: 1000, learning rate: 0.00015625, loss: 0.3432360589504242, AUC: 0.9198250134354529
Araka ny hitantsika, ny maodely dia mahatratra AUC manodidina ny 0.92, izay manondro ny fahombiazan'ny faminaniana . Mariho fa mihena ny tahan'ny fianarana eo anelanelan'ny vanim-potoana 500 sy 600 rehefa mihamitombo ny fatiantoka. Ity fanitsiana ity dia ahafahana manitsy tsara kokoa, mitarika amin'ny fihenan'ny fahaverezana kely. Aorian'ny fotoana iray, ny fatiantoka sy ny AUC dia mitombina, izay manondro fa nifandona ny modely.
Andeha hojerentsika ny maodely amin'ny angona fitsapana (izay tsy nampiasaina nandritra ny fiofanana) ary hojerentsika raha mampifanaraka tsara izany:
# evaluate the model on the test data with torch.no_grad(): test_positive_scores = predictor(test_positive_g, h) test_negative_scores = predictor(test_negative_g, h) test_loss = compute_loss(test_positive_scores, test_negative_scores) test_auc = compute_auc(test_positive_scores, test_negative_scores) print(f'Test loss: {test_loss}, Test AUC: {test_auc}')
Ny vokany dia:
Test loss: 0.675215482711792, Test AUC: 0.866213400711374
Ny AUC fitsapana dia ambany kely noho ny AUC fanofanana, izay manondro ny tsy fahampiana kely. Na izany aza, ny AUC an'ny 0.866 dia mampiseho fa ny modely dia mbola mandeha tsara amin'ny angona tsy hita . Ny fanitsiana fanampiny amin'ny hyperparameter dia mety hanatsara ny ankapobeny, indrindra raha manahy ny overfitting.
Miaraka amin'ny maodely voaofanay, afaka maminavina ny mety hisian'ny fifandraisana misy eo amin'ny nodes ao amin'ny grafika izahay . Hamorona vinavina ho an'ny node rehetra mety ho roa izahay, ahafahantsika mamantatra ireo fifandraisana vaovao mety hitranga.
ndata['h']
an'ny candidat, dia ho fandraisan'anjaran'ny faminaniana rohy.
Ity ny code ho an'ireto dingana ireto:
# build node pairs, avoid self-loops (with_replacement=False) node_pairs = torch.combinations(torch.arange(g.num_nodes()), r=2, with_replacement=False) candidate_u = node_pairs[:, 0] candidate_v = node_pairs[:, 1] # build a graph with all node pairs candidate_graph = dgl.graph((candidate_u, candidate_v)) candidate_graph_node_embeddings = model(g, g.ndata['feat']) # we use embeddings from the original graph candidate_graph.ndata['h'] = candidate_graph_node_embeddings # use the predictor to predict the existence of links between nodes predicted_scores = predictor(candidate_graph, candidate_graph_node_embeddings)
Amin'izao fotoana izao dia manana vinavina ho an'ny mpivady kandida rehetra isika, afaka manamarina ny mety hisian'ny rohy misy eo amin'ireo node manokana . Ohatra, andeha hojerentsika ny isa sy ny mety hisian'ny rohy eo amin'ny node 1773 sy 7005, izay tsy mifandray mivantana amin'ny angona voalohany:
# find the index of the node pair (1773, 7005) pair_index = torch.where((candidate_u == 1773) & (candidate_v == 7005))[0] print(f'Pair index: {pair_index}') # get the logit score for this pair and compute probability of link existence pair_link_score = predicted_scores[pair_index].item() # logit score print(f'Pair link score: {pair_link_score}') link_probability = torch.sigmoid(torch.tensor(pair_link_score)).item() # apply sigmoid to convert score into probability print(f'Link probability: {link_probability * 100}%')
Izao no vokany:
Pair index: tensor([11066978]) Pair link score: 0.7675977945327759 Link probability: 68.30010414123535%
Araka ny modely misy antsika dia misy 68.3% ny mety hisian'ny fifandraisana eo amin'ny mpampiasa 1773 sy 7005 .
Ato amin'ity lahatsoratra ity, nahomby izahay nanamboatra modely ho an'ny faminaniany rohy vaovao amin'ny tabilao sosialy, mampiseho ny fampiasana ny Graph Neural Networks sy DGL ho an'ny faminaniana rohy. Ny fampiasana angon-drakitra somary kely dia nahafahanay niasa tamin'ny milina eo an-toerana. Na izany aza, rehefa mihabetsaka hatrany amin'ny node sy sisiny an-tapitrisany na an'arivony tapitrisa, ny fikarakarana azy ireo dia mitaky vahaolana mandroso kokoa, toy ny fampiofanana mizara amin'ny cluster GPU.
Amin'ny dingana manaraka, dia hijery ny fomba fitantanana ny grafika midadasika sy ny fampiharana ny vinavinan'ny rohy amin'ny tontolon'ny rahona izahay, ahafahanao mampihatra ireo teknika ireo amin'ny angon-drakitra amin'ny ambaratonga famokarana.