使用Keras构建具有自定义结构和层次图卷积神经网络(GCNN)

简介: 使用Keras构建具有自定义结构和层次图卷积神经网络(GCNN)

如何构建具有自定义结构和层次的神经网络:Keras中的图卷积神经网络(GCNN)

640.png

在生活中的某个时刻我们会发现,在Tensorflow Keras中预先定义的层已经不够了!我们想要更多的层!我们想要建立一个具有创造性结构的自定义神经网络!幸运的是,通过定义自定义层和模型,我们可以在Keras中轻松地执行此任务。在这个循序渐进的教程中,我们将构建一个包含并行层的神经网络,其中包括一个图卷积层。那么什么是图上的卷积呢?

图卷积神经网络

在传统的神经网络层中,我们在层输入矩阵X和可训练权值矩阵w之间进行矩阵乘法,然后应用激活函数f。因此,下一层的输入(当前层的输出)可以表示为f(XW)。在图卷积神经网络中,我们假设把相似的实例在图中连接起来(如引文网络、基于距离的网络等),并且我们还假设来自相邻节点的特征在监督任务中可能有用。假设A是图的邻接矩阵,那么我们要在卷积层中执行的操作就是f(AXW)。对于图中的每个节点,我们将从其他相连节点聚合特征,然后将这个聚合特征乘以权重矩阵,然后将其激活。图卷积的这个公式是最简单的。对于我们的教程来说,这很好,但是graphCNN更棒!

好的!现在,我们准备开始了!

步骤1.准备工作

首先,我们需要导入一些包。

#Import packages
from tensorflow import __version__ as tf_version, float32 as tf_float32, Variable
from tensorflow.keras import Sequential, Model
from tensorflow.keras.backend import variable, dot as k_dot, sigmoid, relu
from tensorflow.keras.layers import Dense, Input, Concatenate, Layer
from tensorflow.keras.losses import SparseCategoricalCrossentropy
from tensorflow.keras.utils import plot_model
from tensorflow.random import set_seed as tf_set_seed
from numpy import __version__ as np_version, unique, array, mean, argmax
from numpy.random import seed as np_seed, choice
from pandas import __version__ as pd_version, read_csv, DataFrame, concat
from sklearn import __version__ as sk_version
from sklearn.preprocessing import normalizeprint("tensorflow version:", tf_version)
print("numpy version:", np_version)
print("pandas version:", pd_version)
print("scikit-learn version:", sk_version)

你应该把接收到的导入包版本作为输出。在我的例子中,输出是:

tensorflow version: 2.2.0
numpy version: 1.18.5
pandas version: 1.0.4
scikit-learn version: 0.22.2.post1

在本教程中,我们将使用CORA数据集:(https://relational.fit.cvut.cz/dataset/CORA)

Cora数据集由2708份科学出版物组成,这些出版物被分为七个类别。引文网络由5429个链接组成。数据集中的每个发布都由值为0/1的词向量描述,该词向量表示字典中对应词的出现或消失。这部词典由1433个独特的单词组成。


让我们加载数据,创建邻接矩阵,把特征矩阵准备好。

# Load cora datadtf_data = read_csv("https://raw.githubusercontent.com/ngshya/datasets/master/cora/cora_content.csv").sort_values(["paper_id"], ascending=True)
dtf_graph = read_csv("https://raw.githubusercontent.com/ngshya/datasets/master/cora/cora_cites.csv")
# Adjacency matrix
array_papers_id = unique(dtf_data["paper_id"])
dtf_graph["connection"] = 1
dtf_graph_tmp = DataFrame({"cited_paper_id": array_papers_id, "citing_paper_id": array_papers_id, "connection": 0})
dtf_graph = concat((dtf_graph, dtf_graph_tmp)).sort_values(["cited_paper_id", "citing_paper_id"], ascending=True)
dtf_graph = dtf_graph.pivot_table(index="cited_paper_id", columns="citing_paper_id", values="connection", fill_value=0).reset_index(drop=True)
A = array(dtf_graph)
A = normalize(A, norm='l1', axis=1)
A = variable(A, dtype=tf_float32)
# Feature matrix
data = array(dtf_data.iloc[:, 1:1434])
# Labels
labels = array(
  dtf_data["label"].map({
  'Case_Based': 0,
  'Genetic_Algorithms': 1,
  'Neural_Networks': 2,
  'Probabilistic_Methods': 3,
  'Reinforcement_Learning': 4,
  'Rule_Learning': 5,
  'Theory': 6
  })
)
# Check dimensions
print("Features matrix dimension:", data.shape, "| Label array dimension:", labels.shape, "| Adjacency matrix dimension:", A.shape)

最后,我们定义一些对神经网络的训练有用的参数。

# Training parameters
input_shape = (data.shape[1], )
output_classes = len(unique(labels))
iterations = 50
epochs = 100
batch_size = data.shape[0]
labeled_portion = 0.10

正如你可以从上面的代码中推断出的那样,对于每个模型,我们将执行50次迭代,在每次迭代中,我们将随机选择一个标记为10%的集合(训练集),并对模型进行100个epoch的训练。


需要指出的是,本教程的范围不是训练CORA数据集上最精确的模型。相反,我们只是想提供一个使用keras自定义层实现自定义模型的示例!

模型1:序列层的神经网络

作为基准,我们使用具有序列层的标准神经网络(熟悉的keras序列模型)。

# Model 1: standard sequential neural
networktf_set_seed(1102)
np_seed(1102)
model1 = Sequential([
  Dense(32, input_shape=input_shape, activation='relu'),
  Dense(16, activation='relu'),
  Dense(output_classes, activation='softmax')
], name="Model_1")
model1.save_weights("model1_initial_weights.h5")model1.summary()
plot_model(model1, 'model1.png', show_shapes=True)

我们可以绘制模型来查看序列结构。

640.png

让我们看看这个模型是如何运行的。

# Testing model 1
tf_set_seed(1102)
np_seed(1102)
acc_model1 = []
for _ in range(iterations):
mask = choice([True, False], size=data.shape[0], replace=True, p=[labeled_portion, 1-labeled_portion])
  labeled_data = data[mask, :]
  unlabeled_data = data[~mask, :]
  labeled_data_labels = labels[mask]
  unlabeled_data_labels = labels[~mask]model1.load_weights("model1_initial_weights.h5")model1.compile(
  optimizer='adam',
  loss=SparseCategoricalCrossentropy(from_logits=False),
  metrics=['accuracy']
)
model1.fit(labeled_data, labeled_data_labels, epochs=epochs, batch_size=batch_size, verbose=0)
acc_model1.append(sum(argmax(model1.predict(unlabeled_data, batch_size=batch_size), axis=1) == unlabeled_data_labels) / len(unlabeled_data_labels) * 100)
print("\nAverage accuracy on unlabeled set:", mean(acc_model1), "%")

你可以得出准确率为55%

模型2:并行层的神经网络

让我们对前面的模型做一个小修改。这一次,我们希望拥有一个具有两个并行隐藏层的网络。我们使用Keras函数API。可以构建具有非线性拓扑的模型、具有共享层的模型以及具有多个输入或输出的模型。基本上,我们需要给每一层分配一个变量,然后引用这个变量来连接不同的层,从而创建一个有向无环图(DAG)。然后通过输入层和输出层来建立模型。

# Model 2: neural network with parallel
layerstf_set_seed(1102)
np_seed(1102)
m2_input_layer = Input(shape=input_shape)
m2_dense_layer_1 = Dense(32, activation='relu')(m2_input_layer)
m2_dense_layer_2 = Dense(16, activation='relu')(m2_input_layer)
m2_merged_layer = Concatenate()([m2_dense_layer_1, m2_dense_layer_2])
m2_final_layer = Dense(output_classes, activation='softmax')(m2_merged_layer)
model2 = Model(inputs=m2_input_layer, outputs=m2_final_layer, name="Model_2")
model2.save_weights("model2_initial_weights.h5")
model2.summary()
plot_model(model2, 'model2.png', show_shapes=True)

并行的两个层m2_dense_layer_1和m2_dense_layer_2依赖于相同的输入层m2_input_layer,然后串联起来在m2_merged_layer中形成一个唯一的层。这个神经网络如下所示:

640.png

让我们测试一下这个模型

# Testing model 2
tf_set_seed(1102)
np_seed(1102)
acc_model2 = []
for _ in range(iterations):
mask = choice([True, False], size=data.shape[0], replace=True, p=[labeled_portion, 1-labeled_portion])
  labeled_data = data[mask, :]
  unlabeled_data = data[~mask, :]
  labeled_data_labels = labels[mask]
  unlabeled_data_labels = labels[~mask]model2.load_weights("model2_initial_weights.h5")
  model2.compile(
  optimizer='adam',
  loss=SparseCategoricalCrossentropy(from_logits=False),
  metrics=['accuracy']
)
model2.fit(labeled_data, labeled_data_labels, epochs=epochs, batch_size=batch_size, shuffle=False, verbose=0)
acc_model2.append(sum(argmax(model2.predict(unlabeled_data, batch_size=batch_size), axis=1) == unlabeled_data_labels) / len(unlabeled_data_labels) * 100)
print("\nAverage accuracy on unlabeled set:", mean(acc_model2), "%")

平均准确度接近60% (+5)!

模型3:具有图卷积层的神经网络

到目前为止,我们已经了解了如何使用Keras Functional API创建自定义网络结构。那如果我们需要使用用户自定义的操作自定义的层呢?在我们的例子中,我们想要定义一个简单的图卷积层,如本教程开始部分所解释的那样。为此,我们需要从类层创建一个子类,定义的_init_方法,构建和调用。

# Graph convolutional layer
class GraphConv(Layer):
def __init__(self, num_outputs, A, activation="sigmoid", **kwargs):
  super(GraphConv, self).__init__(**kwargs)
  self.num_outputs = num_outputs
  self.activation_function = activation
  self.A = Variable(A, trainable=False)
def build(self, input_shape):
  # Weights
  self.W = self.add_weight("W", shape=[int(input_shape[-1]), self.num_outputs])
  # bias
  self.bias = self.add_weight("bias", shape=[self.num_outputs])
def call(self, input):
  if self.activation_function == 'relu':
  return relu(k_dot(k_dot(self.A, input), self.W) + self.bias)
  else:
  return sigmoid(k_dot(k_dot(self.A, input), self.W) + self.bias)

在初始化期间,你可以要求并保存任何有用的参数(例如激活函数,输出神经元数)。在我们的例子中,我们还需要邻接矩阵a。在构建方法中,层的可训练权重被初始化。在call方法中,声明了前向传递计算。


在前面的模型中,我们定义了一个具有并行层的网络。

# Model 3: neural network with graph convolutional layer
tf_set_seed(1102)
np_seed(1102)
m3_input_layer = Input(shape=input_shape)
m3_dense_layer = Dense(32, activation='relu')(m3_input_layer)
m3_gc_layer = GraphConv(16, A=A, activation='relu')(m3_input_layer)
m3_merged_layer = Concatenate()([m3_dense_layer, m3_gc_layer])
m3_final_layer = Dense(output_classes, activation='softmax')(m3_merged_layer)
model3 = Model(inputs=m3_input_layer, outputs=m3_final_layer, name="Model_3")
model3.save_weights("model3_initial_weights.h5")
model3.summary()
plot_model(model3, 'model3.png', show_shapes=True)

它看起来像以前的模型,但有一层是卷积的:每个实例的固有特征与从邻域计算出的聚合特征连接在了一起。

640.png

在编写这一模型时,需要进一步注意。由于卷积层需要整个邻接矩阵,所以我们需要传递整个特征矩阵(带标签的和没带标签的实例),但是模型应该只训练带标签的实例。因此,我们定义了一个自定义的损失函数,其中稀疏分类cossentropy只计算在标记的实例。此外,我们将未标记实例的标签随机化,以确保在训练期间不会使用它们。

# Testing model 3
tf_set_seed(1102)
np_seed(1102)
acc_model3 = []
for i in range(iterations):
  mask = choice([True, False], size=data.shape[0], replace=True, p=[labeled_portion, 1-labeled_portion])
  unlabeled_data_labels = labels[~mask]
  # Randomize the labels of unlabeled instances
  masked_labels = labels.copy()
  masked_labels[~mask] = choice(range(7), size=sum(~mask), replace=True)  
model3.load_weights("model3_initial_weights.h5")
  model3.compile(
  optimizer='adam',
  loss=lambda y_true, y_pred: SparseCategoricalCrossentropy(from_logits=False)(y_true[mask], y_pred[mask]),
  metrics=['accuracy']
)
model3.fit(data, masked_labels, epochs=epochs, batch_size=batch_size, shuffle=False, verbose=0)  
predictions = argmax(model3.predict(data, batch_size=batch_size), axis=1)
acc_model3.append(sum(predictions[~mask] == unlabeled_data_labels) / len(unlabeled_data_labels) * 100)
print("\nAverage accuracy on unlabeled set:", mean(acc_model3), "%")

这个实验的平均准确率为63%(+3)。


有趣的是,在最后这个实验中,我们基本上是在用graphCNN执行半监督学习:来自未标记实例的信息和来自标记实例的信息一起被用来构建一个基于图的转导模型。

目录
相关文章
|
22天前
|
机器学习/深度学习 计算机视觉 Python
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力本文提出了一种简单且高效的卷积神经网络(ConvNets)注意力模块——SimAM。与现有模块不同,SimAM通过优化能量函数推断特征图的3D注意力权重,无需添加额外参数。SimAM基于空间抑制理论设计,通过简单的解决方案实现高效计算,提升卷积神经网络的表征能力。代码已在Pytorch-SimAM开源。
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
本文旨在通过深入浅出的方式,为读者揭示卷积神经网络(CNN)的神秘面纱,并展示其在图像识别领域的实际应用。我们将从CNN的基本概念出发,逐步深入到网络结构、工作原理以及训练过程,最后通过一个实际的代码示例,带领读者体验CNN的强大功能。无论你是深度学习的初学者,还是希望进一步了解CNN的专业人士,这篇文章都将为你提供有价值的信息和启发。
|
15天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络:从理论到实践
【10月更文挑战第35天】在人工智能的浪潮中,深度学习技术以其强大的数据处理能力成为科技界的宠儿。其中,卷积神经网络(CNN)作为深度学习的一个重要分支,在图像识别和视频分析等领域展现出了惊人的潜力。本文将深入浅出地介绍CNN的工作原理,并结合实际代码示例,带领读者从零开始构建一个简单的CNN模型,探索其在图像分类任务中的应用。通过本文,读者不仅能够理解CNN背后的数学原理,还能学会如何利用现代深度学习框架实现自己的CNN模型。
|
14天前
|
机器学习/深度学习 人工智能 算法框架/工具
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【10月更文挑战第36天】探索卷积神经网络(CNN)的神秘面纱,揭示其在图像识别领域的威力。本文将带你了解CNN的核心概念,并通过实际代码示例,展示如何构建和训练一个简单的CNN模型。无论你是深度学习的初学者还是希望深化理解,这篇文章都将为你提供有价值的见解。
|
15天前
|
机器学习/深度学习 人工智能 自动驾驶
深入解析深度学习中的卷积神经网络(CNN)
深入解析深度学习中的卷积神经网络(CNN)
32 0
|
19天前
|
机器学习/深度学习 人工智能 TensorFlow
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【10月更文挑战第32天】本文将介绍深度学习中的一个重要分支——卷积神经网络(CNN),以及其在图像识别领域的应用。我们将通过一个简单的代码示例,展示如何使用Python和TensorFlow库构建一个基本的CNN模型,并对其进行训练和测试。
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch代码实现神经网络
这段代码示例展示了如何在PyTorch中构建一个基础的卷积神经网络(CNN)。该网络包括两个卷积层,分别用于提取图像特征,每个卷积层后跟一个池化层以降低空间维度;之后是三个全连接层,用于分类输出。此结构适用于图像识别任务,并可根据具体应用调整参数与层数。
|
3月前
|
机器学习/深度学习 数据可视化 Python
如何可视化神经网络的神经元节点之间的连接?附有Python预处理代码
该博客展示了如何通过Python预处理神经网络权重矩阵并将其导出为表格,然后使用Chiplot网站来可视化神经网络的神经元节点之间的连接。
57 0
如何可视化神经网络的神经元节点之间的连接?附有Python预处理代码

热门文章

最新文章

下一篇
无影云桌面