一、說明
二、圖網絡簡述
????????圖神經網絡是一種用于以圖形式呈現的數據的神經網絡。圖形是由頂點(節點)和邊組成的空間結構。有許多結構表示為圖形:三維空間(x,y,z)中的結構,如物質分子(例如咖啡因)、蛋白質(由氨基酸組成)、DNA、計算機網絡以及社交網絡等結構。以下是一些使用 Wolfram Mathematica 制作的例子:
? ? ? ? 咖啡因的分子結構
? ? ? ? 蛋白
? ? ? ? 蛋白質中原子的 XYZ 坐標
社交網絡
? ? ? ? 社交網絡社區
????????基本上,每個節點代表一個人、一個原子、一個金融交易,這些節點通過邊連接,在這些實體之間建立關系。在人與人之間,這可能是領帶的強度、社交距離、親密程度。在分子結構中的原子中,這些邊緣可能是共價鍵。在金融交易中,這些邊緣可以定義某人與欺詐交易的距離。
????????考慮到社交網絡的例子(如上圖),我們有密集連接的人集群,可能與“影響者”有關,也有薄弱環節(弱紐帶),它們連接不同的人群,允許信息的多樣性。當我們親自或通過社交媒體相互交談時,我們的信息會通過這個社交網絡傳播,并且可能會受到其內容的變形和誤解的影響。原子及其電磁特性也會發生同樣的情況:其他原子離得越近,它們受這些電磁特性的影響就越大。因此,經過一段距離后,這種影響會逐漸消失。此外,如果允許這種影響滲透到所有網絡結構中,則由于飽和,整個網絡可能會收斂到單一狀態。
三、圖網絡的向量模型
????????但是,我們如何才能用數學方式來表示這些復雜的關系,以便能夠對這些相互作用進行建模呢?首先,我們應該定義每個參與者之間的聯系。這是通過鄰接矩陣完成的,其中相同的個體被放置在該矩陣的行和列中:
? ? ? ? 基于鄰接矩陣的網絡結構
????????此鄰接矩陣中的每個數字 1 都表示一個連接。我們有一個 5 x 5 矩陣,其中節點 1 到 5 分別放置在線和列中。所以,如果你拿個體 2,他只與個體 5 相連。個體 1 連接到個體 3 和 5,依此類推。為了繪制這個網絡,我使用了以下代碼:
import numpy as np
import networkx as nxAdj = np.array([[0, 0, 1, 0, 1],[0, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 0, 1, 0, 1], [1, 1, 0, 0, 0]]
)
g = nx.from_numpy_array(Adj)
pos = nx.circular_layout(g)fig, ax = plt.subplots(figsize=(8,8))
nx.draw(g, pos, with_labels=True, labels={i: i+1 for i in range(g.number_of_nodes())}, node_color='#f78c31', ax=ax, edge_color='gray', node_size=1000, font_size=20, font_family='DejaVu Sans')
????????現在我們將鄰接矩陣乘以由行數組成的向量。因此,我們將得到一個 5 x 5 矩陣乘以 5 x 1 向量。這意味著 n x p 乘以 p x m 將得到一個?n?x m?向量。在本例中,5 x 1 向量:
H = Adj @ np.array([1,2,3,4,5]).reshape(-1,1)
????????請注意,為了進行此乘法,您需要將?p x m?向量轉置為 [1,2,3,4,5],并逐個元素乘以鄰接矩陣和總和的那行的每個元素。結果是相連鄰域的總和。按住?H?一會兒。?
????????現在我們將找到對角線度矩陣,它由對角線中的鄰域大小組成,即矩陣中每一列的總和:
D = np.zeros(Adj.shape)
np.fill_diagonal(D, Adj.sum(axis=0))
對角線度矩陣
現在,我們將為每個邊分配一個權重。我們通過將恒等矩陣除以對角度矩陣來做到這一點。
D_inv = np.linalg.inv(D)
倒置度矩陣
通過將倒置的?D?乘以鄰接矩陣,我們將得到一個平均的鄰接矩陣:
? ? ? ? 平均鄰接矩陣
????????當我們處理一個沒有單個值的節點,而是特征向量的集合時,平均的概念非常重要,就像圖卷積網絡一樣。
????????但是,我們真正想要操作的是消息傳遞算法,如下所示:
????????反復應用的帽子將允許信息在圖網絡中流動。假設波浪號等于鄰接矩陣加單位矩陣,我們有:
g = nx.from_numpy_array(Adj)
Adj_tilde = Adj + np.eye(g.number_of_nodes())
????????現在我們需要創建 D 波浪號的平方根。我們創建一個零矩陣,并將鄰接矩陣波浪號的線和值相加。
D_tilde = np.zeros_like(A_tilde)
np.fill_diagonal(D_tilde, A_tilde.sum(axis=1).flatten())
????????然后我們計算 D 波浪號的平方反比根:
D_tilde_invroot = np.linalg.inv(sqrtm(D_tilde))
????????現在我們已經有了 A 波浪號,以及 D 波浪號的平方反比根,我們可以計算出 A 帽子:
A-hat(帽子)的程序表示:
A_hat = D_tilde_invroot @ A_tilde @ D_tilde_invroot
????????請注意,numpy 中的?@?與?matmul?的意思相同。
A-hat 帽子的結果
????????現在我們將實現消息傳遞算法。讓我們從我們擁有的消息向量 (H) 開始,檢查它在圖網絡中的流動方式。我們知道:
H = Adj @ np.array([1,2,3,4,5]).reshape(-1,1)
????????現在我們讓信息流在圖網絡中:
epochs = 9
information = [H.flatten()]
for i in range(epochs):H = A_hat @ Hinformation.append(H.flatten())
四、圖神經網的可視化?
????????讓我們看看這個熱圖中的信息流。注意每個個體(x 軸)如何隨時間(y 軸)獲取或丟失信息。
import matplotlib.pyplot as pltplt.imshow(information, cmap='Reds', interpolation='nearest')
plt.show()
????????讓我們把它畫出來:
fig, ax = plt.subplots(figsize=(12, 12))
from time import timefor i in range(0,len(information)):colors = information[i]nx.draw(g, pos, with_labels=True, labels=node_labels, node_color=colors*2, ax=ax, edge_color='gray', node_size=1500, font_size=30, font_family='serif',vmin= np.array(information).min(), vmax=np.array(information).max())plt.title("Epoch={}".format(i))plt.savefig('/home/user/Downloads/message/foo{}.png'.format(time()), bbox_inches='tight', transparent=True)import glob
from PIL import Imagefp_in = "/home/user/Downloads/message/foo*.png"
fp_out = "/home/user/Downloads/message100_try.gif"img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,save_all=True, duration=1200, loop=0)
????????從視覺上看,圖網絡中的信息流在每個時期都如下所示:
????????在下圖中,我們可以看到網絡的每個節點隨時間推移有多少信息。請注意節點 1、3、4 和 5 的收斂:
????????有關消息傳遞算法在基于代理的模型中的實際應用,請參閱我在 COMSES 上使用 Python 和 NetLogo 制作的模型:魯本斯·津布雷斯