百度飞桨图网络7日打卡学习心得2

一、学习pgl进行简单的图构建
0. 下载pgl

!pip install pgl # 安装PGL
  1. 导入的相关库

导入所需库

import pgl # paddle的图框架
from pgl import graph  # 图相关操作的接口
import numpy as np# 导入所需库
import pgl # paddle的图框架
from pgl import graph  # 图相关操作的接口
import numpy as np
print(pgl.__version__)

1.2.1
2. 利用pgl的graph创建图结构
2.1 创建节点与边的关系
n个节点 ==> (n,2)维度的边关系–即:一个节点对应另一个节点的边关系, 当然也可以换成(n, f)的维度:表示一个节点与多个节点的边关系
In [4]
#了解图所需参数:节点+边关系
#节点
node_numbers = 20
#边关系(edge_list):尝试使用20*2的随机数产生–生成20条边:一个节点对应一个节点的边
edge_list = np.random.randint(0, 20, (20, 2)) # 此时随机产生的边关系可能并不含有0~19这20个数字
#edge_list = np.random.randint(0, 20, (20, 4)) # 1个节点对3个节点的边关系
edge_list[:, 0] = np.arange(0, 20) # 通过指定第0轴中的第0个元素置为指定的0~19的数字,来保证节点不遗失–即:20个节点总是至少有一条边
#展示当前节点与边情况

print('Node_NUM: ', node_numbers)
print('EDGE_LIST: ', edge_list)
Node_NUM:  20
EDGE_LIST:  [[ 0 13]
 [ 1  4]
 [ 2  7]
 [ 3  6]
 [ 4  3]
 [ 5 12]
 [ 6  7]
 [ 7 16]
 [ 8 18]
 [ 9 16]
 [10 11]
 [11 19]
 [12 19]
 [13 17]
 [14 16]
 [15 16]
 [16  2]
 [17 19]
 [18 12]
 [19 17]]

2.2 自定义每一个节点所拥有的特征向量
先确定特征向量的大小(feature_d)–这里考虑一维数据即:每一个节点的特征数
创建特征向量–并展示分布–shape[node_num, feature_d], node_num:节点数
In [5]
#要清楚–每一个节点都带有一定的特征信息
#由多个特征信息组成特征向量
#特征向量大小==每个节点特征个数
feature_d = 16
#根据当前的节点数20,随机创建所有节点的特征信息矩阵

feature = np.random.randn(node_numbers, feature_d).astype('float32')
print(feature[0:2])   # 展示少量特征
[[ 1.3299007  -0.76496845  0.680783    1.4546347   0.91677517 -1.6007569
  -0.681052    0.9236283   0.16727315  0.21182841  0.8838279   0.9806639
  -0.8833934  -1.2996548  -0.17225277 -0.78129226]
 [ 0.05030902 -0.41785973 -1.3661176  -0.96176106 -0.91084456 -0.12318828
   0.18187527  1.1756123  -0.01437144 -1.1311716  -0.32757905  1.1704419
   0.11990328  0.7991894  -0.60065347  1.2929827 ]]

2.3 补充边关系的特征向量–即权重图中边的权重

#这里为了强化图的概念,创建权重图,所以要按照边个数配置边的权重向量
#边的权重向量 即:边的特征–edge_feature
#len(edge_list) * 1 的特征向量

edge_feature = np.random.randn(len(edge_list), 1).astype('float32')
print(edge_feature[0:2])
[[ 0.52089363]
 [-0.64734554]]

2.4 利用pgl.graph.Graph创建一张图
需要节点数
节点的边关系
节点的特征/矩阵
边的特征向量/矩阵
In [7]
#利用设置好的节点数,边关系,节点特征向量,边特征向量(图的边权重)创建一个权重图
g = graph.Graph(num_nodes=node_numbers, # 传入节点参数
edges=edge_list, # 传入边关系
node_feat={‘feature’:feature}, # 传入name_paramters:键值对传入节点特征数据
edge_feat={‘edge_feature’:edge_feature} # 传入name_paramters:键值对传入边特征数据(图中边的权重)
)

#根据创建好的图示例对象,查看对象中的属性

print('The node_num of Graph:', g.num_nodes)  # 打印节点数
print('The nodes of Graph:\n', g.nodes)  # 打印图中的所有节点
print('The node_feature_info of Graph:\n', g.node_feat_info())  # 打印图节点的描述 -- 即相应的shape和data_type
print('\nThe edge_num of Graph:', g.num_edges)  # 打印边数
print('The edges of Graph:\n', g.edges)  # 打印图中的所有边
print('The edge_feature_info of Graph:\n', g.edge_feat_info())  # 打印图边的描述 -- 即相应的shape和data_type
The node_num of Graph: 20
The nodes of Graph:
 [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]
The node_feature_info of Graph:
 [('feature', [None, 16], dtype('float32'))]

The edge_num of Graph: 20
The edges of Graph:
 [[ 0 13]
 [ 1  4]
 [ 2  7]
 [ 3  6]
 [ 4  3]
 [ 5 12]
 [ 6  7]
 [ 7 16]
 [ 8 18]
 [ 9 16]
 [10 11]
 [11 19]
 [12 19]
 [13 17]
 [14 16]
 [15 16]
 [16  2]
 [17 19]
 [18 12]
 [19 17]]
The edge_feature_info of Graph:
 [('edge_feature', [None, 1], dtype('float32'))]

二、创建一个图卷积神经网络并进行训练

#由于pgl不支持动态图,所以采用静态图模式编写
#静态图一般的大致思路:
#1. 首先一开始确定工作环境–gpu or cpu
#2. 然后创建program,通常为三个:start(作为运行器(执行器)的开始), train(用于训练), test(用于测试等)
#3. 设计网络,并实例网络;同时配置好data_feed
#4. 之后紧接着,利用exe执行器, 运行program,并开始将模型和参数data_feed投入 => 通过输入得到输出

#再导入fluid-所设计的运算方法等几乎都在这里
import paddle
from paddle import fluid

  1. 确定工作环境
    use_gpu=True==>使用GPU
    In [10]
    #确定工作环境
    use_gpu = True # 这里不设置gpu工作
    place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
  2. 要想使用图结构进行训练,需要创建一个fit(适合)的图容器来装载
    利用pgl.graph_wrapper.GraphWrapper来创建

所需参数:
name: 即容器名称——也可以说是新的图的名称–容器一定程度上也算一张图
node_feat:传入指定的节点特征信息–通常是一个目标图中的node_feat_info()
edge_feat:则是边特征信息——edge_feat_info()

传入参数展示:
node_feat_info()>>[(‘feature’, [None, 16], dtype(‘float32’))]
edge_feat_info()
>>[(‘edge_feature’, [None, 1], dtype(‘float32’))]
就是一些key值,形状,数据类型

In [11]
#为了图网络的运行和配置
#我们首先需要利用我们之前的图创建一个初始化的容器
#容器所需参数:name, 已知图结构的node_info 和 edge_info
gw = pgl.graph_wrapper.GraphWrapper(name=‘graph’, # 容器(图)名称
node_feat=g.node_feat_info(), # 利用上边的g图的节点信息创建
edge_feat=g.edge_feat_info()) # 利用上边的g图的边信息创建一个g的容器
3. 图卷积的构建
一个图消息机制,发送接收得到图的输出数据
经过一个fc层输出,通过一个act进行非线性因子的添加
In [12]
#图卷积网络构建
#思路:
#处理好图机制–消息机制的运用,计算消息输出
#然后经过一个fc层,实现数据的过渡
#利用act激活函数添加非线性因子,是模型更有适应性
#同时通过name参数,配置网络层的名称
def gcn_layer(gw, nfeat, efeat, hidden_size, name, act):
‘’’
gw: 一个图容器
nfeat: 节点特征数据–特征向量或矩阵
efeat:边特征数据
hidden_size: 隐藏层大小–即通过图之后的输出数据的shape[非第0轴]的大小
因为图卷积是通过数据经过图计算,再经过一个全连接层进行过度得到图卷积效果的
name:图卷积层的名称,用于layer查讯等如:resnet_model[‘conv’]
act: 激活方式
‘’’

# 图需要用到一个消息机制:需要一个发送和接受函数来实现
# 发送部分 -- 发送部分是传入图容器的send()中的, 不是直接接收特征信息
def send_func(src_feat, dst_feat, edge_feat):
    '''
        src_feat: 源特征--输入特征/节点特征
        dst_feat: 距离特征
        edge_feat: 边特征--边与节点的权重
    '''
    # 将节点特征与边特征相关(这里不考虑dst_feat)--作为消息接收后发送的特征消息(数据),用于消息机制的接收
    return src_feat['h'] * edge_feat['e']

# 接收部分
def recv_func(sended_feat):
    '''
        sended_feat: 来自发送部分处理的特征
    '''
    # 利用sequence_pool,进行sum类型的池化,实现特征向量的融合(相加)
    return fluid.layers.sequence_pool(sended_feat, pool_type='sum')

# 利用设计好的消息体制方法,进行网络的配置:先发送数据(接收输入信息,发送新消息给图处理), 然后接收消息
# 首先接收消息,处理后返回新特征(消息/信息)
msg = gw.send(send_func,   # 发送处理方法
              nfeat_list=[('h', nfeat)],  # 节点特征键值对--注意,键值名称与我们设计的发送部分要一致
              efeat_list=[('e', efeat)]) # 边特征

# 对发送得到的消息进行接收,然后输出图的结果
output = gw.recv(msg,   # 发送过来的信息
                recv_func)  # 接收处理方法

# 将图的输出经过全连接层,实现过渡,并通过act激活,添加非线性因子
output = fluid.layers.fc(
                        output,    # fc层的输入
                        size=hidden_size,  # fc层大小--即输出特征大小
                        bias_attr=False,  # 不适用偏置bias
                        act=act,      # 激活函数
                        name=name     # 网络层的名称
                        )
return output
  1. 创建一个两层的图卷积–串行执行
    In [13]
    #利用设计好的gcn,多创建几个网络,串行执行–得到深网络
    output = gcn_layer(gw, # 之前创建的容器
    gw.node_feat[‘feature’], # 输入节点的特征数据–原始图中的信息
    gw.edge_feat[‘edge_feature’], # 输入边的特征数据
    hidden_size=8, # 输出大小
    name=‘gcn_layer1’, # 层名称
    act=‘relu’) # 激活函数
    print(output.shape, output.dtype) # 输出上一层的输出情况
    output = gcn_layer(gw,
    output, # 利用上一图卷积层的输出,作为下一层的输入消息
    gw.edge_feat[‘edge_feature’],
    hidden_size=1,
    name=‘gcn_layer2’,
    act=‘relu’)
    (-1, 8) VarType.FP32
    /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/pgl/graph_wrapper.py:151: UserWarning: The edge features in argument efeat_list should be fetched from a instance of pgl.graph_wrapper.GraphWrapper, because we have sorted the edges and the order of edges is changed.
    Therefore, if you use external edge features, the order of features of each edge may not match its edge, which can cause serious errors.
    If you use the efeat_list correctly, please ignore this warning.
    "The edge features in argument efeat_list should be fetched "
  2. 创建节点的标签值–用于后边的训练拟合
    一个节点至少对应一个标签,这里简单一对一,所以一共20个节点
    In [14]
    #创建点二分的label[0, 1]用于分类,0或1
    y = [0,1,1,1,0,0,0,1,0,1,1,1,0,1,0,0,1,1,0,1]
    label = np.array(y, dtype=“float32”)
    label = np.expand_dims(label, -1) # [len(y), 1]
    print(label[0:5])
    [[0.]
    [1.]
    [1.]
    [1.]
    [0.]]
    *6. 在静态图下搭建训练过程
    配置data_feed
    配置loss
    配置optimeter
    创建执行器exe,并执行default_startup_program
    配置feed_dict,即执行器所需的参数信息
    配置训练过程–for epoch in …
    In [15]
    #静态图下的训练

#首先准备数据接口data_feed
#label_feed==label数据接口创建
node_label = fluid.layers.data(name=‘node_label’, # data_name
shape=[None, 1], # data_shape
dtype=‘float32’, # data_type
append_batch_size=False) # 不开启批转换–即不去刻意添加批的维度

#选择模型的损失函数
loss = fluid.layers.sigmoid_cross_entropy_with_logits(x=output, # 模型输出结果
label=node_label) # 标签值

#损失处理
loss = fluid.layers.mean(loss) # 均值处理

#选择模型优化器
adam = fluid.optimizer.Adam(learning_rate=0.01) # 学习率设置
#优化器调整
adam.minimize(loss) # 计算批损失下的优化梯度

#以上准备完成后,创建执行器(运行器)
exe = fluid.Executor(place) # 运行在place上的执行器
exe.run(fluid.default_startup_program()) # 运行start_program

#获取执行需要的参数信息–这里首先是图的参数
feed_dict = gw.to_feed(g) # 利用图容器加载之前的g图中的参数信息–边和节点信息等

#开始训练:目的是使得节点的分类与定的label中的分类情况一一对应
epoches = 10 # 训练轮次
for epoch in range(epoches):
feed_dict[‘node_label’] = label # 节点的类别信息, 添加到feed_dict中(之前创建的label)

# 执行器运行,并计算损失
train_loss = exe.run(fluid.default_main_program(),  # program指定
                     feed=feed_dict,  # 投入的参数字典--主要是形状、type等信息
                     fetch_list=[loss],  # 需要计算的参数--loss
                     return_numpy=True)  # 返回numpy类型的数据

print('Epoches: {0} | Loss: {1:.4f}'.format(epoch+1, train_loss[0].item()))

Epoches: 1 | Loss: 0.6310
Epoches: 2 | Loss: 0.6107
Epoches: 3 | Loss: 0.5990
Epoches: 4 | Loss: 0.5903
Epoches: 5 | Loss: 0.5838
Epoches: 6 | Loss: 0.5807
Epoches: 7 | Loss: 0.5779
Epoches: 8 | Loss: 0.5755
Epoches: 9 | Loss: 0.5733
Epoches: 10 | Loss: 0.5713

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刹那永恒HB

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值