paint-brush
አገናኞችን በግራፍ መተንበይ ከግራፍ ነርቭ ኔትወርኮች እና DGL.ai ጋር@andrei9735
አዲስ ታሪክ

አገናኞችን በግራፍ መተንበይ ከግራፍ ነርቭ ኔትወርኮች እና DGL.ai ጋር

Andrei14m2024/11/06
Read on Terminal Reader

በጣም ረጅም፤ ማንበብ

የግራፍ ነርቭ ኔትወርኮችን እና ዲጂኤልን ለአገናኝ ትንበያ መጠቀማቸውን በማሳየት በማህበራዊ ግራፍ ውስጥ አዲስ አገናኞችን ለመተንበይ ሞዴል መገንባት ይማሩ።
featured image - አገናኞችን በግራፍ መተንበይ ከግራፍ ነርቭ ኔትወርኮች እና DGL.ai ጋር
Andrei HackerNoon profile picture


ግራፎች ውሂብን የሚወክሉበት ኃይለኛ መንገዶች ናቸው፣ በልዩ ልዩ ዓይነት አፕሊኬሽኖች ውስጥ ባሉ አካላት መካከል ያሉ ግንኙነቶችን የሚይዝ። ማህበራዊ አውታረ መረቦችን ፣ የፕሮቲን ግንኙነቶችን ፣ የመጓጓዣ ስርዓቶችን ፣ ወይም የምክር ሞተሮችን ሞዴል እየሰሩ ቢሆንም ፣ ግራፎች በተፈጥሮው እነዚህን ውስብስብ እርስ በርስ መደጋገፍ ይወክላሉ እና ይተነትናል። ዛሬ በመረጃ በተደገፈ ዓለም ውስጥ በህጋዊ አካላት መካከል ያለውን ግንኙነት መረዳት ብዙውን ጊዜ ህጋዊ አካላትን እንደመረዳት አስፈላጊ ነው - ግራፎች በትክክል የሚያበሩበት።


የግንኙነት ትንበያ በግራፍ ትንታኔ ውስጥ ካሉት መሠረታዊ ተግባራት ውስጥ አንዱ ነው ፣ ይህም በመስቀለኛ መንገድ (በግራፍ ውስጥ የተወከሉት አካላት) ግንኙነቶችን (ወይም አገናኞችን) ትንበያን ያካትታል። በማህበራዊ አውታረመረብ ውስጥ አዳዲስ ጓደኞችን ለመምከር ፣ በአካዳሚክ ጥቅስ ግራፍ ውስጥ ሊሆኑ የሚችሉትን ትብብር መተንበይ ወይም በተጠቃሚዎች እና ምርቶች መካከል የወደፊት ግንኙነቶችን በኢ-ኮሜርስ መቼት መተንበይ - እነዚህ ሁሉ በተግባር ላይ ያሉ የግንኙነት ትንበያ ምሳሌዎች ናቸው። ይህ ተግባር አውታረ መረቦችን ለማስፋት፣ የጎደሉትን መረጃዎች ለመገመት እና ያልተለመዱ ነገሮችን ለመለየት ይረዳል። የተጠቃሚን ልምድ ከማጎልበት እስከ ማጭበርበር ፈልጎ ማግኛ ድረስ ላሉት መተግበሪያዎች የአገናኝ ትንበያ ለስኬት ቁልፍ አካል ነው።


የአገናኝ ትንበያን ለማሳየት፣ ከስታንፎርድ ኔትወርክ ትንተና ፕሮጀክት (SNAP) የ Twitch Social Network ዳታ ስብስብን እንጠቀማለን። ይህ የውሂብ ስብስብ በ Twitch ዥረት መድረክ ላይ በተጠቃሚዎች መካከል ያለውን ማህበራዊ ግንኙነቶችን ይይዛል፣ አንጓዎች Twitch ተጠቃሚዎችን የሚወክሉበት እና ጠርዞች በመካከላቸው ጓደኝነትን ይወክላሉ። የመረጃ ቋቱ በደንብ የተዋቀረ ነው፣ ይህም አስቀድሞ ለመስራት እና ለመስራት ቀላል ያደርገዋል።


በመከተል፣ ፕሮጀክትን እንዴት ማዋቀር፣ ውሂብን እንደሚያስቀድሙ፣ ሞዴል መገንባት እና በገሃዱ ዓለም የውሂብ ስብስብ ላይ ለአገናኝ ትንበያ መገምገም እንደሚችሉ ይማራሉ።

ግራፍ የነርቭ አውታረ መረቦች እና ጥልቅ ግራፍ ቤተ-መጽሐፍት።

በግራፍ የተዋቀረ መረጃ መስራት ልዩ ተግዳሮቶችን ያቀርባል፣ እና እዚህ ግራፍ ነርቭ ኔትወርኮች (ጂኤንኤን) ይመጣሉ። ጂኤንኤን ከግራፍ መረጃ ጋር ለመስራት የተነደፈ የነርቭ ኔትወርክ አይነት ነው። በቋሚ መጠን ግብአት ላይ ከሚሰሩ ባህላዊ የነርቭ ኔትወርኮች በተለየ፣ ጂኤንኤን የዘፈቀደ የግራፍ መጠኖችን ማስተናገድ እና በመረጃው ውስጥ ያለውን የግንኙነት ንድፎችን መጠቀም ይችላሉ። ከአንጓዎች ጎረቤቶች መረጃን በማዋሃድ ጂኤንኤን ሁለቱንም የመስቀለኛ መንገድ ባህሪያትን እና የግራፉን አወቃቀሩን የሚይዙ ውክልናዎችን ይማራሉ፣ ይህም እንደ የመስቀለኛ ክፍል ምደባ፣ አገናኝ ትንበያ እና የግራፍ ምደባ ላሉ ተግባራት በጣም ውጤታማ ያደርጋቸዋል።


የዲፕ ግራፍ ቤተ-መጽሐፍት ( DGL.ai ) ጂኤንኤን በቀላል እና በቅልጥፍና ለመገንባት ኃይለኛ መሣሪያ ነው። በዲጂኤል፣ ገንቢዎች የአገናኝ ትንበያን ጨምሮ የተለያዩ ስራዎችን ለመስራት ዘመናዊ የጂኤንኤን አርክቴክቸር መጠቀም ይችላሉ። DGL ከተመሳሳይ እና ከተለያዩ ግራፎች ጋር አብሮ ለመስራት የተለያዩ መገልገያዎችን ያቀርባል፣ ይህም ለተመራማሪዎች እና ለሙያተኞች ሁለገብ መሳሪያ ያደርገዋል። የጂኤንኤን አተገባበርን በማቃለል DGL በቴክኒካዊ ውስብስብ ችግሮች ውስጥ ከመጠመድ ይልቅ አዳዲስ መፍትሄዎችን በማዘጋጀት ላይ የበለጠ እንዲያተኩሩ ይፈቅድልዎታል።


ይህንን መሠረት በአእምሯችን ይዘን፣ ጂኤንኤን እና DGL.aiን በመጠቀም አገናኝ ትንበያ ሞዴልን ለመገንባት እንዝለቅ።

ፕሮጀክቱን በማዘጋጀት ላይ

የመጀመርያው እርምጃ የሚያስፈልጉትን ቤተ-መጻሕፍት በማስመጣት ፕሮጀክታችንን ማዘጋጀት ነው።

 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

የውሂብ ቅድመ ዝግጅት እና የባቡር ሙከራ ክፍፍል

መረጃውን ለሥልጠና ለማዘጋጀት በመጀመሪያ Twitch ዳታሴትን እንጭነዋለን፣ እንደ ግራፍ እንወክላለን፣ እና በመቀጠል ወደ ስልጠና እና የሙከራ ስብስቦች እንከፍለዋለን። ከ DGLDataset የሚወርስ ብጁ ክፍል እንፈጥራለን፣ ይህም የውሂብ የመጫን ሂደቱን ለማዋቀር እና ከግራፍ ጋር የተገናኙ ስራዎችን ለማቀላጠፍ ይረዳል።


  1. የግራፍ ዳታውን በመጫን ላይ ፡ በሂደቱ ተግባር ውስጥ ከመረጃ ቋቱ የጠርዙን ዝርዝር በማንበብ እንጀምራለን። በዋናው የመረጃ ቋት ውስጥ ያሉት ጠርዞች ያልተመሩ (የጋራ ጓደኝነትን የሚወክሉ) ስለሆኑ ግንኙነቶቹ በግራፍችን ውስጥ ባለሁለት አቅጣጫ መሆናቸውን ለማረጋገጥ የተገላቢጦሽ ጠርዞችን እንጨምራለን ።
  2. የመስቀለኛ መንገድ ባህሪያትን በመጫን ላይ፡ በመቀጠል ፣ የመስቀለኛ መንገድ ባህሪያትን ከJSON ፋይል እንጭናለን። እያንዳንዱ መስቀለኛ መንገድ በርዝመታቸው ሊለያዩ የሚችሉ የባህሪዎች ዝርዝር አለው፣ስለዚህ በሁሉም መስቀለኛ ቋቶች ላይ ወጥ የሆነ ርዝመት እንዲኖረን አጠር ያሉ የባህሪ ዝርዝሮችን በዜሮ እንሸፍናለን።


የመረጃ ቋቱን ለመፍጠር እና ለማስኬድ ኮዱ ይኸውና፡-

 # 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


አሁን የግራፍ ውሂቡን ለመጫን የእኛን የውሂብ ስብስብ እናስጀምራለን.

 # init the dataset dataset = SocialNetworkDataset() g = dataset[0]


ቀጣዩ ደረጃ የስልጠና እና የሙከራ ስብስቦችን መፍጠር ነው. ለስልጠና እና ለሙከራ ጠርዞቹን ወደ 80/20 ሬሾ እንከፍላለን። ለሁለቱም ስብስቦች ሁለቱንም አወንታዊ (ነባር ጠርዞች) እና አሉታዊ ናሙናዎችን (የሌሉ ጠርዞችን) እናመነጫለን። ለትልቅ ግራፎች፣ የዲጂኤል dgl.sampling መገልገያዎች አጋዥ ሊሆኑ ይችላሉ፣ ግን እዚህ፣ ሙሉው ግራፍ በማህደረ ትውስታ ውስጥ ይስማማል። የሥልጠና እና የሙከራ ስብስቦችን ለመፍጠር ኮድ ይኸውና፦


 # 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())

ሞዴል፡ GraphSAGE Convolutional Layers እና MLP Predictor

በግራፍ ውስጥ የእያንዳንዱን መስቀለኛ መንገድ አወቃቀር እና ገፅታዎች የሚይዙ መስቀለኛ መንገዶችን ለመማር የግራፍ ናሙና እና ድምር (GraphSAGE) convolutional neural network እንጠቀማለን። GraphSAGE ለእያንዳንዱ መስቀለኛ መንገድ ትርጉም ያለው ውክልና ለመፍጠር ከእያንዳንዱ መስቀለኛ መንገድ ጎረቤቶች የባህሪ መረጃን በማዋሃድ ይሰራል። ይህ ሂደት፣ የጎረቤት ድምር በመባል ይታወቃል፣ ሞዴሉ በግራፉ ውስጥ የበለፀጉ፣ የተተረጎሙ ቅጦችን እንዲማር ያስችለዋል።


በእያንዳንዱ የ GraphSAGE ንብርብር ውስጥ, ሞዴሉ ከአጎራባች አንጓዎች መረጃን ለመሰብሰብ የመደመር ተግባርን (በዚህ ሁኔታ "አማካይ" ተግባር) ይተገበራል, ከዚያም ከእራሱ መስቀለኛ መንገድ ጋር ይጣመራል. ብዙ ኮንቮሉሽን ንብርብሮችን መደርደር ሞዴሉ ከጊዜ ወደ ጊዜ ከሩቅ አንጓዎች መረጃን እንዲይዝ ያስችለዋል፣ ይህም እያንዳንዱን የመስቀለኛ ክፍል እይታ በግራፉ ውስጥ በደንብ ያሰፋል።


የሞዴል አፈጻጸምን ለማሻሻል እና ከመጠን በላይ መገጣጠምን ለመቀነስ ከእያንዳንዱ ንብርብር በኋላ ማቋረጥን እንተገብራለን።


አሁን የ GraphSAGE ሞዴሉን በሶስት ኮንቮሉሽን ንብርብሮች እንገንባ፣ መረጃ በእሱ ውስጥ እንዴት እንደሚፈስ ለማወቅ forward ተግባር ጋር።


 # 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


ከሶስተኛው ንብርብር ( h ) በኋላ የሚወጣው ውጤት የመስቀለኛ ክፍሎችን ያካትታል. በማናቸውም ሁለት አንጓዎች መካከል የጠርዝ (ወይም አገናኝ) እድልን ለመተንበይ ባለብዙ-ንብርብር ፐርሴፕሮን (MLP) ትንበያ እንጠቀማለን። ይህ MLP የሁለት አንጓዎችን መክተት እንደ ግብአት ወስዶ በመካከላቸው ያለውን የጠርዝ እድል የሚያመለክት ነጥብ ያሰላል።


 # 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"]


MLP ትንበያ እንደሚከተለው ይሰራል።

  • የግቤት መጠን ፡ የትንበያው የግቤት መጠን በተማሩት የመስቀለኛ ክፍል መክተት ላይ የተመሰረተ ነው። እያንዳንዱ ጠርዝ ሁለት አንጓዎችን ስለሚያገናኝ፣ እያንዳንዳቸውን (እያንዳንዱን መጠን የተደበቀ_ባህሪያትን) እናስቀምጠዋለን ፣ይህም የድብቅ_ባህሪዎች * 2 ግቤት መጠን እንዲኖር እናደርጋለን።
  • ንብርብር 1 (ደብሊው1) ፡ ይህ ንብርብር የተጣመሩትን መክተቻዎች በማስኬድ የውፅአት ልኬቱን ወደ ድብቅ_ባህሪዎች በመመለስ በመስቀለኛ መንገዱ መካከል ያለውን ጠቃሚ ግንኙነት ይጠብቃል።
  • ንብርብር 2 (W2) ፡ ይህ የመጨረሻው ንብርብር ለእያንዳንዱ ጥንድ አንጓዎች አንድ ነጠላ ስክላር ነጥብ ያስገኛል፣ ይህም በመካከላቸው ያለውን የጠርዝ እድልን ይወክላል።


ይህ የተደራረበ አካሄድ ተንባቢው በአንጓዎች ጥንዶች መካከል ያሉ ውስብስብ ግንኙነቶችን እንዲይዝ እና የጠርዝ የመኖር እድል ተብሎ ሊተረጎም የሚችል የጠርዝ ነጥብ እንዲያሰላ ያስችለዋል።

የመጥፋት ተግባር እና AUC

ሞዴላችንን በብቃት ለማሰልጠን የአምሳያው አፈጻጸም በአገናኝ ትንበያ ላይ ሊለካ የሚችል የኪሳራ ተግባር ያስፈልገናል። ይህ ተግባር የሁለትዮሽ ምደባ ችግር ስለሆነ - እያንዳንዱ አገናኝ ባለበት ወይም ከሌለ - ሁለትዮሽ መስቀል-ኢንትሮፒ (BCE) እንደ ኪሳራ ተግባራችን እንጠቀማለን። ሁለትዮሽ መስቀል-ኢንትሮፒ በአምሳያው የተገመቱ ውጤቶች እና በተጨባጭ መለያዎች መካከል ያለውን ልዩነት ይለካል (1 ለነባር ማገናኛ፣ 0 ለአገናኝ የለም)። _with_logits ሥሪቱን እንጠቀማለን ምክንያቱም ሞዴላችን ፕሮባቢሊቲዎችን ከማድረግ ይልቅ ጥሬ ነጥቦችን (ሎጊቶችን) ስለሚያወጣ ነው። የሲግሞይድ ተግባርን እና መስቀል-ኢንትሮፒን ወደ አንድ ደረጃ በማጣመር ይህ የቢሲኢ ስሪት ከሎጊቶች ጋር ሲሰራ የበለጠ የተረጋጋ ነው።


ኪሳራን የሚያሰላ ኮድ ይኸውና፡-

 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)


ሞዴሉን ለመገምገም፣ በ ROC Curve (AUC) ስር ያለውን አካባቢ መለኪያ እንጠቀማለን። AUC ከአዎንታዊ ናሙናዎች ይልቅ አሉታዊ ናሙናዎች (የሌሉ ጠርዞች) በጣም የተለመዱ ስለሆኑ ሚዛናዊ ያልሆነ መረጃን በብቃት ስለሚይዝ ለአገናኝ ትንበያ በጣም ተስማሚ ነው። የAUC ነጥብ ሞዴሉ ምን ያህል ነባር አገናኞችን ከሌሉ ግንኙነቶች ከፍ እንደሚያደርግ ግንዛቤ ይሰጠናል።


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)

ማሳሰቢያ፡- ቴነሮችን ከኮምፒዩቲሽን ግራፍ ለማውጣት detach() እንጠቀማለን፣ይህም AUC ን ቅልመትን ሳይነካ ለማስላት ያስችለናል።

ሞዴሉን ማሰልጠን

አሁን ሞዴሉን ለማሰልጠን ዝግጁ ነን. ለመጀመር ሞዴሉን፣ ትንበያውን እና አመቻችውን በቅጽበት እንገልጻለን እና የስልጠና ምልልሱን እንገልጻለን ። እንዲሁም የመማሪያ መጠንን፣ የተደበቀ የንብርብር መጠን እና የማቋረጥ መጠን ከሌሎች ሃይፐር መለኪያዎች መካከል እንገልፃለን። የሃይፐርፓራሜትር ማመቻቸትን እዚህ ላይ ባንሸፍነውም ፣ የጠፋው ፕላታየስ ከሆነ የመማሪያ ፍጥነቱን ለማስተካከል የመማሪያ ተመን መርሐግብርን እንጠቀማለን - ይህ ማለት ለተወሰኑ የዘመናት ብዛት መቀነስ ያቆማል (በዚህ ሁኔታ፣ 25)። ይህ በሚሆንበት ጊዜ መርሐግብር አውጪው የመማሪያውን ፍጥነት በግማሽ ይቀንሳል፣ ይህም ሞዴሉ ይበልጥ ውጤታማ በሆነ መንገድ እንዲሰበሰብ ይረዳል።


ሞዴሉን ለመጀመር እና ስልጠና ለማዘጋጀት ኮድ ይኸውና፡

 # 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}')


ኮዱን እናሂድና ውጤቱን እንመርምር፡-

 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


እንደምናየው፣ ሞዴሉ 0.92 አካባቢ AUC ያሳካል፣ ይህም ጠንካራ ትንበያ አፈጻጸምን ያሳያል ። በEpochs 500 እና 600 መካከል ያለው ኪሳራ ሲረጋጋ የመማሪያው ፍጥነት ይቀንሳል። ይህ ማስተካከያ ጥሩ ማስተካከያ እንዲኖር ያስችላል, ይህም ወደ ትንሽ ኪሳራ ይቀንሳል. ከተወሰነ ነጥብ በኋላ, ኪሳራው እና AUC ይረጋጋሉ, ይህም ሞዴሉ እንደተሰበሰበ ያሳያል.


ሞዴሉን በሙከራው መረጃ ላይ እንገመግመው (በስልጠና ወቅት ጥቅም ላይ ያልዋለ) እና በጥሩ ሁኔታ አጠቃላይ ከሆነ ይመልከቱ፡-

 # 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}')


ውጤቱ፡-

 Test loss: 0.675215482711792, Test AUC: 0.866213400711374


የፈተናው AUC ከስልጠናው AUC በመጠኑ ያነሰ ነው፣ ይህም መጠነኛ መገጣጠምን ያሳያል። ነገር ግን፣ የ0.866 AUC እንደሚያሳየው ሞዴሉ አሁንም በማይታዩ መረጃዎች ላይ በደንብ ይሰራል ። የሃይፐርፓራሜትሮች ተጨማሪ ማስተካከያ አጠቃላይነትን ሊያሻሽል ይችላል፣ በተለይም ከመጠን በላይ መገጣጠም አሳሳቢ ከሆነ።

አዳዲስ አገናኞችን ለመተንበይ የሰለጠነውን ሞዴል በመጠቀም

በሠለጠነ ሞዴላችን አሁን በግራፉ ውስጥ ባሉ አንጓዎች መካከል የመገናኘት እድልን መተንበይ እንችላለንለሁሉም ሊሆኑ የሚችሉ ጥንድ አንጓዎች ትንበያዎችን እንፈጥራለን፣ ይህም ሊሆኑ የሚችሉ አዳዲስ ግንኙነቶችን እንድንለይ ያስችለናል።

  1. የእጩ መስቀለኛ መንገድ ጥንዶችን ማመንጨት ፡ መጀመሪያ ሁሉንም ሊሆኑ የሚችሉ ጥንድ ኖዶችን እናመነጫለን፣ እራስ-ቀለበቶችን (ከእራሱ መስቀለኛ መንገድ ወደ ራሱ የሚገናኙትን) ሳያካትት። ይህ የአገናኝ ፕሮባቢሊቲዎችን ለመተንበይ የምንፈልገውን የእጩ ኖድ ጥንዶች ይሰጠናል።
  2. የእጩ ግራፍ መፍጠር፡- ከዚያ በኋላ የዲጂኤል ግራፍ ከእነዚህ እጩዎች ጠርዞች ጋር እንፈጥራለን፣ እና ሞዴሉን ከመጀመሪያው ግራፍ በመስቀለኛ ክፍል ውስጥ እንጠቀማለን። በእጩ ግራፍ ndata['h'] ባህሪ ውስጥ የተከማቹ እነዚህ መክተቻዎች ለአገናኝ ትንበያ ግብዓቶች ሆነው ያገለግላሉ።


የእነዚህ እርምጃዎች ኮድ ይኸውና፡-

 # 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)


አሁን ለሁሉም እጩ ጥንዶች ትንበያዎች አሉን ፣ በማንኛውም ልዩ አንጓዎች መካከል ያለውን የግንኙነት ዕድል ማረጋገጥ እንችላለን ። ለምሳሌ በመጀመሪያ የመረጃ ቋት ውስጥ በቀጥታ ያልተገናኙትን በመስቀለኛ መንገዱ 1773 እና 7005 መካከል ያለውን የግንኙነት ነጥብ እና እድል እንመርምር፡-

 # 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}%')


ውጤቱ ይህ ነው፡-

 Pair index: tensor([11066978]) Pair link score: 0.7675977945327759 Link probability: 68.30010414123535%


በእኛ ሞዴል መሠረት በተጠቃሚ 1773 እና 7005 መካከል ያለው ግንኙነት 68.3% ዕድል አለ.

ማጠቃለያ

በዚህ ልጥፍ ውስጥ የግራፍ ነርቭ ኔትወርኮችን እና ዲጂኤልን ለአገናኝ ትንበያ መጠቀማቸውን በማሳየት በማህበራዊ ግራፍ ውስጥ አዳዲስ አገናኞችን ለመተንበይ ሞዴል በተሳካ ሁኔታ ገንብተናልበአንጻራዊ ሁኔታ አነስተኛ የውሂብ ስብስብ በመጠቀም በአካባቢያዊ ማሽን ላይ በብቃት እንድንሰራ አስችሎናል. ነገር ግን፣ ግራፎች በሚሊዮኖች ወይም በቢሊዮኖች የሚቆጠሩ ኖዶች እና ጠርዞች ሲጨምሩ፣ እነሱን ማስተናገድ የበለጠ የላቀ መፍትሄዎችን ይፈልጋል፣ ለምሳሌ በጂፒዩ ስብስቦች ላይ የሚሰራጭ ስልጠና።


እንደ ቀጣዩ ደረጃ፣ እነዚህን ቴክኒኮች በምርት ደረጃ የውሂብ ስብስቦች ላይ እንድትተገብሩ የሚያስችሎትን መጠነ ሰፊ ግራፎችን ለማስተናገድ እና የአገናኝ ትንበያን በደመና አካባቢዎች ውስጥ ለመተግበር አቀራረቦችን እንመረምራለን።