来源:DeepHub IMBA

本文约3600字,建议阅读5分钟

本文为你介绍了如何构建具有自定义结构和层次的神经网络:Keras中的图卷积神经网络(GCNN)。

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

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

图卷积神经网络

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

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

步骤1.准备工作

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

#Import packagesfrom tensorflow import __version__ as tf_version, float32 as tf_float32, Variablefrom tensorflow.keras import Sequential, Modelfrom tensorflow.keras.backend import variable, dot as k_dot, sigmoid, relufrom tensorflow.keras.layers import Dense, Input, Concatenate, Layerfrom tensorflow.keras.losses import SparseCategoricalCrossentropyfrom tensorflow.keras.utils import plot_modelfrom tensorflow.random import set_seed as tf_set_seedfrom numpy import __version__ as np_version, unique, array, mean, argmaxfrom numpy.random import seed as np_seed, choicefrom pandas import __version__ as pd_version, read_csv, DataFrame, concatfrom sklearn import __version__ as sk_versionfrom 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.0numpy version: 1.18.5pandas version: 1.0.4scikit-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 parametersinput_shape = (data.shape[1], )output_classes = len(unique(labels))iterations = 50epochs = 100batch_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)

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

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

# 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中形成一个唯一的层。这个神经网络如下所示:

让我们测试一下这个模型

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

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

在编写这一模型时,需要进一步注意。由于卷积层需要整个邻接矩阵,所以我们需要传递整个特征矩阵(带标签的和没带标签的实例),但是模型应该只训练带标签的实例。因此,我们定义了一个自定义的损失函数,其中稀疏分类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执行半监督学习:来自未标记实例的信息和来自标记实例的信息一起被用来构建一个基于图的转导模型。

参考网站:

https://tkipf.github.io/graph-convolutional-networks/
https://www.tensorflow.org/api_docs/python/tf/keras
编辑:王菁

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

  1. 使用Python构建参数化FNN(一)——构建可自定义结构的FNN

    提示:转载请注明出处,若本文无意侵犯到您的合法权益,请及时与作者联系. 使用Python构建全连接神经网络(二)--构建可自定义结构的全连接神经网络 一. 神经元与神经层的输出计算 二. 实现一个2* ...

  2. Keras【Deep Learning With Python】CNN卷积神经网络(看不懂你打我系列)

    文章目录 前言 1 CNN概述 2 我的分析 3 代码实现 4 代码分析 6 结果 前言 本文分为CNN讲解和keras实现CNN(mnist数据集)两部分. 1 CNN概述 卷积神经网络(Convo ...

  3. keras从入门到放弃(十二)卷积神经网络

    卷积神经网络 卷积是指将卷积核应用到某个张量的所有点上,通过将 卷积核在输入的张量上滑动而生成经过滤波处理的张量. 介绍的目标识别与分类,就是在前面问题的基础 上进行扩展,实现对于图像等分类和识别. ...

  4. 卷积神经网络的结构_射击训练:卷积神经网络识别解剖结构标志位点

    本文2100字,阅读大约需要7分钟 在医学图像分析中,我们需要识别解剖结构的标志位点,识别出的位点可用于临床分析以及解剖结构分割等用途.深度学习的发展,给这样的方法带来了一些新的可能,已有不少的研究. ...

  5. 图卷积神经网络GCN原理+图结构学习+GAT+VGAE

    https://baijiahao.baidu.com/s?id=1678519457206249337&wfr=spider&for=pc GCN是一种卷积神经网络,它可以直接在图上 ...

  6. 轻量级图卷积网络LightGCN介绍和构建推荐系统示例

    来源:DeepHub IMBA 本文约4500字,建议阅读9分钟 今天介绍的这个模型被称作:Light Graph Convolution Network 或 LightGCN¹. 推荐系统是当今业界 ...

  7. 深度学习(四):卷积神经网络(CNN)模型结构,前向传播算法和反向传播算法介绍。

    在前面我们讲述了DNN的模型与前向反向传播算法.而在DNN大类中,卷积神经网络(Convolutional Neural Networks,以下简称CNN)是最为成功的DNN特例之一.CNN广泛的应用 ...

  8. PyMC3和Lasagne构建神经网络(ANN)和卷积神经网络(CNN)

    转自http://www.sohu.com/a/162460147_505915 源地址https://twiecki.io/blog/2016/07/05/bayesian-deep-learnin ...

  9. [Python图像识别] 五十.Keras构建AlexNet和CNN实现自定义数据集分类详解

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

最新文章

  1. 激活函数之softmax介绍及C++实现
  2. java连接mysql数据库(jsp显示和控制台显示)
  3. Android手机在获取root权限下的抓包过程
  4. ARKit从入门到精通(4)-ARKit全框架API大全
  5. php-fpm 负荷高,记录简单处理服务器php-fpm占用过多的问题(主题影响负载)
  6. git查看分支记录_git原理
  7. 什么是无监督学习(监督学习,半监督学习,无监督聚类)?
  8. 【转】设计模式六大原则——SOLID
  9. 3 分钟了解 JSON Schema
  10. 【亲测有效】运行docker ps 出现Got permission denied问题的解决方案
  11. java 编写 servlet 程序_Java技术分享:如何编写servlet程序
  12. mybatis 中collection中需要 open close separator
  13. 微信语音技术原理_微信语音多群直播原理-一起学堂
  14. 毕业设计 - 基于JAVA的小区/园区停车管理系统(简便易上手)
  15. 【Firefox设置百度搜索引擎】
  16. quartz定时任务集群版
  17. 接口文档要写在概要设计里吗_概要设计报告怎么写
  18. 11.4王者荣耀服务器维护中,4月11日全服不停机更新公告
  19. WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用
  20. 路由器端口映射失败排查方法

热门文章

  1. 部分背包的贪婪算法 java_使用JAVA实现算法——贪心算法解决背包问题
  2. SQL 语句转换格式函数Cast、Convert
  3. 实验进行中:.NET WebAssembly支持
  4. 反向代理or后端nginx 生产用于缓存视频需要解决的问题
  5. 项目进度管理和项目成本管理作业
  6. Oracle控制文件的重建
  7. 我发现现在在电视编剧也挺宅的
  8. 深入剖析ISAServer 网页缓存及配置
  9. mysql savepoint 丢失_关于MySQL中savepoint语句使用时所出现的错误
  10. 卡尔曼滤波(kalman)相关理论以及与HMM、最小二乘法关系 转