文章目錄
- 一、GCN是什么
- 二、資料集-Cora Dataset
- 1. 資料集介紹
- 2. 準備資料
- 三、劃分訓練集、測驗集和驗證集
- 四、模型訓練
- 1. Loss計算
- 2. 訓練模型
- 3. 結果可視化
- 五、同系列作品
🚀 我的環境:
- 語言環境:Python3.6.5
- 編譯器:jupyter notebook
- 深度學習環境:TensorFlow2.4.1
- 資料和代碼:📌【傳送門】
🚀 來自專欄:《深度學習100例》
如果你是一名深度學習小白可以先看看我這個專門為你寫的專欄:《小白入門深度學習》
一、GCN是什么

-
卷積神經網路(Convolutional Neural Network, CNN):用于和圖片打交道
-
圖卷積神經網路(Graph Convolution Networks, GCN):用于和結構化不規則的資料打交道,例如社交網路、知識圖譜等,
-
在CNN中,我們輸入的資料通常是圖片;
-
在GCN中,我們輸入的資料通常是這樣的:
[nodes,edges],nodes為圖中節點的集合,nodes為圖中邊的集合,

本案例將講解如何利用GCN實作論文分類,
二、資料集-Cora Dataset
1. 資料集介紹
Cora Dataset一個機器學習論文分類資料集,它包含三個檔案:
-
README: 對資料集的介紹; -
cora.cites: 論文之間的參考關系圖,檔案中每行包含兩個Paper ID, 第一個ID是被參考的Paper ID; 第二個是參考的Paper ID,格式如下: -
cora.content: 包含了2708篇論文的資訊,每個樣本都是一篇科學論文,每一個樣本(每行)的資料格式如下:id+word_attributes+label,id是論文的唯一標識;word_attributes是一個維度為1433的詞向量,詞向量的每個元素對應一個詞,0表示該元素對應的詞不在Paper中,1表示該元素對應的詞在Paper中,class_label是論文的類別,每篇Paper被映射到如下7個分類之一:Case_Based、Genetic_Algorithms、Neural_Networks、Probabilistic_Methods、Reinforcement_Learning、Rule_Learning、Theory,
import pandas as pd
import numpy as np
# 匯入資料:分隔符為Tab
raw_data_content = pd.read_csv('data/cora/cora.content',sep = '\t',header = None)
raw_data_content.head()
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 31336 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | Neural_Networks |
| 1 | 1061127 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Rule_Learning |
| 2 | 1106406 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Reinforcement_Learning |
| 3 | 13195 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Reinforcement_Learning |
| 4 | 37879 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Probabilistic_Methods |
5 rows × 1435 columns
raw_data_content.shape
(2708, 1435)
raw_data_cites = pd.read_csv('data/cora/cora.cites',sep = '\t',header = None)
raw_data_cites.head()
| 0 | 1 | |
|---|---|---|
| 0 | 35 | 1033 |
| 1 | 35 | 103482 |
| 2 | 35 | 103515 |
| 3 | 35 | 1050679 |
| 4 | 35 | 1103960 |
raw_data_content.shape
(2708, 1435)
2. 準備資料
# ================================================================
# 將raw_data_cites中的論文ID進行統一編號并轉化為陣列
# 如果這部分你難以理解,可以試試輸出其中的變數
# ================================================================
# 給論文ID進行統一的編號,并將映射放入字典idx_map中
idx = np.array(raw_data_content.iloc[:, 0], dtype=np.int32)
idx_map = {j: i for i, j in enumerate(idx)}
# 將資料放入edge_indexs陣列當中
edge_indexs = np.array(list(map(idx_map.get, raw_data_cites.values.flatten())), dtype=np.int32)
edge_indexs = edge_indexs.reshape(raw_data_cites.shape)
edge_indexs
array([[ 163, 402],
[ 163, 659],
[ 163, 1696],
...,
[1887, 2258],
[1902, 1887],
[ 837, 1686]])
features = raw_data_content.iloc[:,1:-1].astype(np.float32)
labels = pd.get_dummies(raw_data_content.iloc[:, -1])
import scipy.sparse as sp
def normalize_adj(adjacency):
"""計算 L=D^-0.5 * (A+I) * D^-0.5"""
adjacency += sp.eye(adjacency.shape[0]) # 增加自連接
degree = np.array(adjacency.sum(1))
d_hat = sp.diags(np.power(degree, -0.5).flatten())
return d_hat.dot(adjacency).dot(d_hat).tocsr().todense()
"""
這里生成的是(2708, 2708)值全部為0的矩陣,
關于 sp.coo_matrix 函式的解釋請看:https://blog.csdn.net/qq_38251616/article/details/120361746
"""
adjacency = sp.coo_matrix((np.ones(len(edge_indexs)),(edge_indexs[:, 0], edge_indexs[:, 1])),
shape=(features.shape[0], features.shape[0]),
dtype="float32")
adjacency = normalize_adj(adjacency)
adjacency.shape
(2708, 2708)
adjacency
matrix([[0.25, 0. , 0. , ..., 0. , 0. , 0. ],
[0. , 1. , 0. , ..., 0. , 0. , 0. ],
[0. , 0. , 1. , ..., 0. , 0. , 0. ],
...,
[0. , 0. , 0. , ..., 1. , 0. , 0. ],
[0. , 0. , 0. , ..., 0. , 0.2 , 0. ],
[0. , 0. , 0. , ..., 0. , 0. , 0.25]])
# features: 代表圖中的節點
# adjacency:代表圖中的邊
graph = [features, adjacency]
三、劃分訓練集、測驗集和驗證集
這里使用[0, 2000)個資料作為訓練集合,[2000, 2300)個資料作為驗證集,[2300, 2708)個資料作為測驗集,實作上使用掩碼(train_mask、val_mask、test_mask)的形式來區分訓練集、驗證集和測驗集,
train_index = np.arange(2300)
val_index = np.arange(2300, 2500)
test_index = np.arange(2500, 2708)
train_mask = np.zeros(edge_indexs.shape[0], dtype = np.bool)
val_mask = np.zeros(edge_indexs.shape[0], dtype = np.bool)
test_mask = np.zeros(edge_indexs.shape[0], dtype = np.bool)
train_mask[train_index] = True
val_mask[val_index] = True
test_mask[test_index] = True
edge_indexs.shape[0],edge_indexs.shape[0],edge_indexs.shape[0]
(5429, 5429, 5429)
train_mask,val_mask,test_mask
(array([ True, True, True, ..., False, False, False]),
array([False, False, False, ..., False, False, False]),
array([False, False, False, ..., False, False, False]))
四、模型訓練
"""
這里匯入的是自己自定義的1個檔案,
如果打算運行本專案,
請前往 https://mtyjkh.blog.csdn.net/article/details/120222803 下載整個專案檔案
"""
from graph import GraphConvolutionLayer, GraphConvolutionModel
import time
import matplotlib.pyplot as plt
import tensorflow as tf
gpus = tf.config.list_physical_devices("GPU")
if gpus:
tf.config.experimental.set_memory_growth(gpus[0], True) #設定GPU顯存用量按需使用
tf.config.set_visible_devices([gpus[0]],"GPU")
1. Loss計算
在Loss函式中,我們只對訓練資料(train_mask為True)進行計算,
loss_object = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
def loss(model, x, y, train_mask, training):
"""
損失函式
"""
y_ = model(x, training=training)
# tf.where()將回傳train_mask中為true的元素的索引
# tf.gather_nd()將從 y/y_ 中取出index標注的部分
test_mask_logits = tf.gather_nd(y_, tf.where(train_mask))
masked_labels = tf.gather_nd(y , tf.where(train_mask))
return loss_object(y_true=masked_labels, y_pred=test_mask_logits)
def grad(model, inputs, targets, train_mask):
"""
梯度計算函式
"""
with tf.GradientTape() as tape:
loss_value = loss(model, inputs, targets, train_mask, training=True)
return loss_value, tape.gradient(loss_value, model.trainable_variables)
2. 訓練模型
def test(mask):
logits = model(graph)
test_mask_logits = tf.gather_nd(logits, tf.where(mask))
masked_labels = tf.gather_nd(labels, tf.where(mask))
ll = tf.math.equal(tf.math.argmax(masked_labels, -1), tf.math.argmax(test_mask_logits, -1))
accuarcy = tf.reduce_mean(tf.cast(ll, dtype=tf.float64))
return accuarcy
model = GraphConvolutionModel()
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-2, decay=5e-5)
# 記錄程序值,以便最后可視化
train_loss = []
train_accuracy = []
val_accuracy = []
test_accuracy = []
num_epochs = 150
for epoch in range(num_epochs):
#計算梯度
loss_value, grads = grad(model, graph, labels, train_mask)
#更新模型
optimizer.apply_gradients(zip(grads, model.trainable_variables))
accuarcy = test(train_mask)
val_acc = test(val_mask)
test_acc = test(test_mask)
train_loss.append(loss_value)
train_accuracy.append(accuarcy)
val_accuracy.append(val_acc)
test_accuracy.append(test_acc)
print("Epoch {} loss={} accuracy={} val_acc={} test_acc={}".format(epoch, loss_value, accuarcy, val_acc, test_acc))
Epoch 0 loss=1.947021484375 accuracy=0.4056521739130435 val_acc=0.37 test_acc=0.34615384615384615
Epoch 1 loss=1.763957142829895 accuracy=0.43 val_acc=0.4 test_acc=0.40865384615384615
Epoch 2 loss=1.6049641370773315 accuracy=0.5026086956521739 val_acc=0.45 test_acc=0.4519230769230769
Epoch 3 loss=1.451796054840088 accuracy=0.63 val_acc=0.55 test_acc=0.5336538461538461
......
Epoch 147 loss=0.0192192904651165 accuracy=0.9973913043478261 val_acc=0.74 test_acc=0.8076923076923077
Epoch 148 loss=0.01902584359049797 accuracy=0.9978260869565218 val_acc=0.74 test_acc=0.8028846153846154
Epoch 149 loss=0.018838025629520416 accuracy=0.9982608695652174 val_acc=0.74 test_acc=0.8028846153846154
可以看到,經過200次迭代后,最終GCN網路在驗證集上的準確率達到99.8%,在測驗集中的Accuracy達到了80.0%,
3. 結果可視化
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(train_accuracy, label='Training Accuracy')
plt.plot(val_accuracy, label='Validation Accuracy')
plt.plot(test_accuracy, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation and Test Accuracy')
plt.subplot(1, 2, 2)
plt.plot(train_loss, label='Training Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

參考鏈接
- 官方原始碼:https://github.com/tkipf/gcn
五、同系列作品
🚀 深度學習新人必看:《小白入門深度學習》
- 小白入門深度學習 | 第一篇:配置深度學習環境
- 小白入門深度學習 | 第二篇:編譯器的使用-Jupyter Notebook
- 小白入門深度學習 | 第三篇:深度學習初體驗
- 小白入門深度學習 | 第四篇:配置PyTorch環境
🚀 往期精彩-卷積神經網路篇:
- 深度學習100例-卷積神經網路(CNN)實作mnist手寫數字識別 | 第1天
- 深度學習100例-卷積神經網路(CNN)彩色圖片分類 | 第2天
- 深度學習100例-卷積神經網路(CNN)服裝影像分類 | 第3天
- 深度學習100例-卷積神經網路(CNN)花朵識別 | 第4天
- 深度學習100例-卷積神經網路(CNN)天氣識別 | 第5天
- 深度學習100例-卷積神經網路(VGG-16)識別海賊王草帽一伙 | 第6天
- 深度學習100例-卷積神經網路(VGG-19)識別靈籠中的人物 | 第7天
- 深度學習100例-卷積神經網路(ResNet-50)鳥類識別 | 第8天
- 深度學習100例-卷積神經網路(AlexNet)手把手教學 | 第11天
- 深度學習100例-卷積神經網路(CNN)識別驗證碼 | 第12天
- 深度學習100例-卷積神經網路(Inception V3)識別手語 | 第13天
- 深度學習100例-卷積神經網路(Inception-ResNet-v2)識別交通標志 | 第14天
- 深度學習100例-卷積神經網路(CNN)實作車牌識別 | 第15天
- 深度學習100例-卷積神經網路(CNN)識別神奇寶貝小智一伙 | 第16天
- 深度學習100例-卷積神經網路(CNN)注意力檢測 | 第17天
- 深度學習100例-卷積神經網路(VGG-16)貓狗識別 | 第21天
- 深度學習100例-卷積神經網路(LeNet-5)深度學習里的“Hello Word” | 第22天
- 深度學習100例-卷積神經網路(CNN)3D醫療影像識別 | 第23天
- 深度學習100例 | 第24天-卷積神經網路(Xception):動物識別
- 深度學習100例 | 第25天-卷積神經網路(CNN):手寫數字識別-中文版
- 深度學習100例 | 第26天-卷積神經網路(CNN):乳腺癌識別
🚀 往期精彩-回圈神經網路篇:
- 深度學習100例-回圈神經網路(RNN)實作股票預測 | 第9天
- 深度學習100例-回圈神經網路(LSTM)實作股票預測 | 第10天
🚀 往期精彩-生成對抗網路篇:
- 深度學習100例-生成對抗網路(GAN)手寫數字生成 | 第18天
- 深度學習100例-生成對抗網路(DCGAN)手寫數字生成 | 第19天
- 深度學習100例-生成對抗網路(DCGAN)生成動漫小姐姐 | 第20天
🚀 往期精彩-目標檢測系列:
- 深度學習100例 | 第51天-目標檢測演算法(YOLOv5)(一)
🚀 本文選自專欄:《深度學習100例》
💖先贊后看,再收藏,養成好習慣!💖
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302429.html
標籤:AI
