PyG
data
torch_geometric.data中定义一些基本的图神经网络对象,最基本的两个是Data(同构图)和HeteroData()
Data(同构图)
Data把 结点 和 边 分开存储,类似与字典的键值对
构造函数Data对象:
class Data(x: Optional[Tensor] = None, edge_index: Optional[Tensor] = None, edge_attr: Optional[Tensor] = None, y: Optional[Union[Tensor, int, float]] = None, pos: Optional[Tensor] = None, time: Optional[Tensor] = None, **kwargs)
参数含义:
x
:是结点特征,形状为[num_nodes, num_node_features]
edge_index
:图的边连接 , COO形式([source1,source2…],[target1,target2…]),形状为[2, num_edges]
,默认数据类型:torch.long
edge_attr
:边的特征矩阵,形状为[num_edges, num_edge_features]
y
:训练目标/标签(可能有任意形状),例如结点训练目标[num_nodes, *]
or 图层面的标签[1, *]
pos
: 位置矩阵[num_nodes, num_dimensions]
。pos 保存了节点在空间中的坐标,形状为[num_nodes, num_dimensions]
,其中num_nodes
是节点的数量,num_dimensions
是空间的维度。例如,在2D空间的图中,pos 可能包含每个节点的 (x, y) 坐标;在3D空间中,则包含 (x, y, z)。- time(torch.Tensor)-每个事件的时间戳,其形状为[Num_Edges]或[Num_Nodes]。(默认:无)
- **kwargs(可选)-其他属性。
构建一个同构图
edge_index = torch.tensor([[0, 1 ,3,1,3,2,3,0],
[1, 0 ,1,3,2,3,0,3]])
x = torch.randn(4, 2)# 四个节点,每个节点有两个特征
data = Data(x=x, edge_index=edge_index)
# Data(x=[4, 2], edge_index=[2, 8])
属性(类型全部为torch.Tensor):
-
data.x:结点特征
[num_nodes, num_node_features]
-
data.edge_index:图的边连接 , COO format([source1,source2…],[target1,target2…]),
[2, num_edges]
数据类型:torch.long
# edge_index存储方式[source1,source2....],[target1,target2.....]
edge_index = torch.tensor([[0, 1 ,3,1,3,2,3,0],
[1, 0 ,1,3,2,3,0,3]])
# 如果要用[source1,target1],[ source2,target2]来存储,则需要ranspose和 contiguous
# 转成COO格式进行存储
edge_index = torch.tensor([[0, 1],
[1, 0],
[3, 2],
[2, 3],
[3,0],
[0,3]])
edge_index=edge_index.t().contiguous()
x = torch.randn(4, 2)
data = Data(x=x, edge_index=edge_index)
-
data.edge_attr:边的特征矩阵
[num_edges, num_edge_features]
-
data.y: 训练目标/标签(可能有任意形状),例如结点训练目标
[num_nodes, *]
or 图层面的标签[1, *]
-
data.pos: 位置矩阵
[num_nodes, num_dimensions]
方法:
- to_dict()→ Dict[str, Any]:返回存储的键/值对的字典,其中键是图的属性,例如特征x,边连接edige_index,值是对应的矩阵
data.to_dict()
>>{'x': tensor([[ 0.0637, -0.7537],
[ 0.0546, 0.7084],
[ 0.9085, 0.8337],
[ 0.2679, 0.2635]]),
'edge_index': tensor([[0, 1, 3, 1, 3, 2, 3, 0],
[1, 0, 1, 3, 2, 3, 0, 3]])}
- to_namedtuple()→ NamedTuple[source]:返回存储的键/值对的NamedTuple。
data.to_namedtuple()
>>GlobalStorageTuple(x=tensor([[ 0.9965, 0.9090],
[ 0.5442, 0.1322],
[ 1.7514, 1.4769],
[-1.8494, 0.2258]]), edge_index=tensor([[0, 1, 3, 1, 3, 2, 3, 0],
[1, 0, 1, 3, 2, 3, 0, 3]]))
-
Update
:用另一个数据对象中的元素更新数据对象。添加的元素将覆盖现有的元素(在重复的情况下)。 -
__getitem__(self, key)
:用于获取图的属性。允许通过属性名作为键来访问图的任何属性,如data['x']
返回节点特征矩阵。 -
__setitem__(self, key, item)
:用于设置图的属性。可以通过这个方法为图添加新的属性或修改现有的属性,如data['edge_attr'] = edge_features
。 -
__len__(self)
:返回图的节点数 -
__contains__(self, key)
:检查图是否包含给定的属性。 -
clone(self)
:返回Data
对象的深拷贝。这个方法确保原始数据和拷贝数据在内存中是完全独立的。 -
to(device, **kwargs)
:将Data
对象中的所有张量移动到指定的设备上(如cuda:0) -
apply(func, *keys)
:对Data
对象中的一个或多个属性应用函数func
。这对于数据预处理非常方便。 -
is_undirected(self)
:检查图是否是无向的。如果图的每条边都有对应的反向边,则认为图是无向的。
使用NetworkX可视化
NetworkX 是一个用 Python 语言开发的库,专门用于创建、操作复杂网络的结构、动态以及其功能的研究。
导入
import networkx as nx
G = nx.Graph()
nodes = [0,1,2,3]
G.add_nodes_from(nodes)
# (第一种形式的推导式)
edges = [(edge_index[0, i].item(), edge_index[1, i].item())
for i in range(edge_index.shape[1])]
# 第二中形式的推导式
# edges=[tuple(x.tolist())for x in edge_index]
G.add_edges_from(edges)
# 可视化图
pos = nx.spring_layout(G) # 布局算法
nx.draw(G, pos, with_labels=True, font_weight='bold', node_size=700,
node_color='skyblue', font_size=10, edge_color='gray')
# 邻接矩阵
adj_matrix = nx.adjacency_matrix(G)
# 度矩阵
degree_matrix = np.diag(list(dict(G.degree).values()))