深度学习-图神经网络-超图概念及在Hyper-YOLO的应用(小白也看懂)

为什么需要超图?

在一个复杂系统中,某些节点(实体)之间的互动可能不是仅限于两个节点之间的关系,而是多个节点同时参与的更复杂的关系(超边)。简单说就是为了更好的描述事物之间的关系,为了方便数学建模。

超图 表示为一个二元组:

G=(V,E)

其中 V 是有限顶点集合,E是有限超边集合。加权超图,增加了超边的权重:

G=(V,E,w)

w(e)表示超边e的权重,w(e)\geqslant 0超边的权重是给每个超边分配一个实数值,以表示其重要性或影响力。

顶点集的大小被称为超图的阶数 order of the hypergraph,边集的大小被称为超图的大小 size of the hypergraph。

重要概念:

顶点的度d(v),指包含该顶点的所有超边的权重之和。

超边的度\delta (e),就是该边包含的顶点个数:\delta (e)= \left | e \right |

相邻、关联
1、相邻,点对点:如果存在包含两个顶点的超边,则超图中的两个顶点是相邻的(adjacent)。

就是说两个顶点在同一个超边上,就是相邻。

     边对边:如果{ x } 是超边,则 x与其自身相邻。

2、关联,边对边:两边相交关联的( incident),两超边的顶点交集非空。

     点对边:v\in e, 称 v 与 e 关联。用于关联矩阵


超图的关联矩阵表示法                        

超图 G 除了用二元组或三元组外,还可以用关联矩阵来表示。

关联矩阵 A,用于表征顶点和超边之间的关联关系,形式如下:

  • 行表示顶点,列表示超边,元素值为1表示顶点在该超边中,0表示不在。
  • 或者行表示边,列表示顶点,一样,两种方式。

利用关联矩阵H,顶点的度可表示为:

超边的度可表示为:

超图邻接矩阵A:

其中,W表示权重对角矩阵,D_v表示顶点度对角矩阵,对角线元素为每个顶点的度。

具体例子:下面是一个 3\times 5 关联矩阵,3边5点。

对偶矩阵,即关联矩阵的转置(如下图就是上面矩阵转置)。也很容易看出,任何导出子超图的关联矩阵(H的子超图,部分超图)是H的关联矩阵的子矩阵。

超图邻接矩阵A:

定义:

这个矩阵是对称方阵(维度等于超图顶点数),它也是多重图的矩阵。一般关联矩阵用得比较多。这个定义可能有点抽象,直接记住计算公式

其中,W表示权重对角矩阵,D_v表示顶点度对角矩阵(对角线元素为每个顶点的度)。例如上面超图的邻接矩阵,经过计算为:

拉普拉斯矩阵

超图的拉普拉斯矩阵L定义为:

L=D_e-A^TA

其中 D_e 是超边的度矩阵,对角线元素为每个超边的大小。

超图熵
代数上的超图熵(algebraic hypergraph entropy) :

空间域超图卷积

空间域卷积是通过顶点的邻接信息来聚合信息,通常是将邻接的信息聚合到中心节点。

其中,X^l 与 X^(l+1) 表示第 l 层与第(l+1)层的输入,D是顶点度矩阵(n阶方阵),B是超边的度矩阵(m阶方阵),\sigma是非线性激活函数,P表示第 l 层与第(l+1)层的权重矩阵,是可学习的权重矩阵。H 是 (n\times m) 超图的关联矩阵(n个顶点,m条超边)。W是超图的权重对角阵。

超图卷积的物理含义
超图卷积的物理含义可以理解为:在一个复杂系统中,某些节点(实体)之间的互动可能不是仅限于两个节点之间的关系,而是多个节点同时参与的更复杂的关系(超边)。超图卷积通过聚合这些高维关系的信息,为每个节点提供更丰富的特征表示,从而更好地捕捉系统中的复杂互动。

频域超图卷积

频域卷积是基于拉普拉斯算子进行频域分析,通常用于频率特征的提取。

公式
在频域,超图卷积可通过以下方式定义:

H{}'=UDU^TH

其中 U是拉普拉斯矩阵的特征向量,D是特征值矩阵。

HyperGCN 中的谱域图卷积通过利用超图的结构及其拉普拉斯矩阵来聚合特征信息,这为半监督学习提供了有效的方法。典型的谱域图卷积公式如下:

其中:

  • H是输入特征矩阵。
  • H′是输出特征矩阵。

进行基于谱域的图卷积的计算步骤如下:

同一超边中的节点相似,共享同一标签,我们都要考虑其所有邻居以及其自身所包含的特征信息。
普通的图卷积就是将节点和边之间的映射用矩阵的形式进行表达并且是在其某个一阶的子图上进行的操作。
超图卷积的本质在于,先利用拉普拉斯变换转化为简单图后再进行图卷积。
1. 对于每一个超边,只选取信号特征最大2个节点,这两个节点之间的边来代表超边。
2. 超边加上权重,这样就将超图变为简单带权图了。
3. 可以计算出超图的拉普拉斯矩阵和进行卷积。

什么是超图注意力?
        1、超图的注意力目标是学习一个动态关联矩阵。获得能够更好地揭示顶点间内在关系地动态转移矩阵。
       2、要使在H上用注意力机制模块,必须假定边和顶点是可比的。这取决于超图如何构造。
       3、例如可以将中心节点和k个最近邻节点共同形成一个超边。当节点和超边可以比较时,可以得到超图的注意力机制。


超图分类,如:

空超图 Empty hypergraph:没有边的超图;
非简单超图 Non-simple (or multiple) hypergraph :允许有环 loops(有单个顶点的超边)或重复边的超图;
简单超图 Simple hypergraph :不包含循环和重复边的超图;
k一致超图 k-uniform hypergraph:每条超边都正好包含 k 个顶点的超图;
d正则超图 d-regular hypergraph:每个顶点的度数都是 𝑑 的超图;
无环超图 Acyclic hypergraph:不包含任何环的超图。

超图的特性
1、每个超图都有一个对应的对偶超图。对偶超图就是通过将原超图的顶点和边进行交换。
如超图的关联矩阵H是一个表示顶点和边之间关系的布尔矩阵,与它的转置H^T对偶。

2、边的交集有大小
在普通图中,所有边的大小都是2,但在超图中,边的大小可以是任意数值。

3、边可以嵌套

4、超图与二分图(bipartite graph)有着一对一的对应关系。超图的布尔关联矩阵H也可以看作二元关系的特征矩阵。

其他概念或属性

1. 空超边(Empty Hyperedges)
如果关联矩阵中的某一列全部为零,这表示该超边是空的,也就是没有任何顶点与它关联。空超边在一些复杂的超图中是允许存在的。

2. 孤立顶点(Isolated Vertices)
如果关联矩阵中的某一行全部为零,这表示该顶点是孤立的,也就是该顶点没有连接到任何超边。

3. 多重超图(Multihypergraphs)
允许重复的超边,这意味着在关联矩阵中,可能会有重复的列(表示相同的超边重复出现)。

4. 自环(Self-Loops)
自环表示图中的某条边可以连接到自己。在通常的图结构中,边通常是连接两个不同的顶点,而在允许自环的结构中,边可以连接到同一个顶点,这是一种特殊的连接方式。

5. 方向(Direction)
有些图中的边可以被赋予方向性,也就是边的连接有输入和输出的顶点。在这种情况下,某些顶点被视为“输入”,而另一些顶点则是“输出”。这种定向连接在网络模型中经常使用,比如表示信息流、交通流等。

6. 顺序(Order)
在某些超图中,顶点可能具有特定的顺序。这种顺序可能是全序或部分序。对于图而言,这相当于定向边的概念,但在超图中,顺序的复杂性更高,因为超边可以连接多个顶点。

7. 属性(Attributes)
一般来说,我们可以在图或超图的顶点、边或“关联关系”上附加属性。这些属性可以是不同的数据类型,例如权重、标签、标识符、类型、字符串等。

8、步行(walk)是指一系列相邻边的序列 W=〈e0,e1,…,eN〉,其中每对相邻边是相交的。步行的长度 N 是步行中边的数量。

9、s-步行 是指在超图中两条边之间的最短路径,它的特点是需要更宽的连接。具体来说,两个顶点或超边之间的 s-距离 是它们之间最短 s-步行 的长度。

10、子超图 subhypergraph 是去掉某些顶点的超图。

11、部分超图 partial hypergraph是去掉一些边的超图。

12、如果每个顶点的度都为k,则超图H是k-正则的。一致超图的对偶是正则的,反之亦然。

此外还有 分段超图 section hypergraphs,盖夫曼图 Gaifman graph),对称超图,横切面等概念。

同构

超图同态 homomorphism是指从一个超图的顶点集到另一个超图的顶点集的映射,如此使得每条边映射到另一条边。

超图已被广泛用于机器学习中,常作为一种数据结构或一种正则化属性分类器 classifier regularization。 这些应用包括推荐系统 recommender system (社团作为超边)、图像检索 image retrieval(相关性作为超边) 、和生物信息学(生物、化学分子间相互作用作为超边)。

比较典型的超图机器学习方法包括:超图谱聚类法 spectral clustering(用拉普拉斯超图 hypergraph Laplacian 扩展光谱图理论 spectral graph theory)和超图半监督学习 semi-supervised learning(通过引入超图结构来对结果进行限定)。对于大尺寸的超图,可以使用Apache Spark构建的分布式框架。

简单的超图定义代码


from typing import List
import numpy as np
import os
import json

class Vertex:
    def __init__(self, name: str = None, weight: float = None):
        self.name = name
        self.weight = weight

class Edge:
    def __init__(self, name: str = None, weight: float = None, vertices: List[Vertex] = None):
        """
        :param name: 名字
        :param weight: 权重
        :param vertices: 顶点集合
        """
        self.name = name
        self.weight = weight
        self.vertices = vertices

class Hypergraph(object):
    def __init__(self, vertices: List[Vertex] = None, edges: List[Edge] = None):
        self.vertices = vertices
        self.edges = edges
        if vertices is None or edges is None:
            self.num_vertices = 0
            self.num_edges = 0
            self.incident_matrix = None
            self.vertices_degree = None
            self.edges_degree = None
            self.vertex_degree_diagonal_matrix = None
            self.edge_degree_diagonal_matrix = None
        else:
            self.num_vertices = len(vertices)
            self.num_edges = len(edges)
            self.incident_matrix = self.calculate_incident_matrix()
            self.vertices_degree = self.calculate_vertex_degree()
            self.edges_degree = self.calculate_edge_degree()
            self.vertex_degree_diagonal_matrix = self.calculate_diagonal_matrix_of_vertex_degree()
            self.edge_degree_diagonal_matrix = self.calculate_diagonal_matrix_of_edge_degree()

    def init_hypergraph_from_files(self, dataset_dir: str):
        self.vertices, self.edges = hypergraph_construction(dataset_dir)
        self.num_vertices = len(self.vertices)
        self.num_edges = len(self.edges)
        self.incident_matrix = self.calculate_incident_matrix()
        self.vertices_degree = self.calculate_vertex_degree()
        self.edges_degree = self.calculate_edge_degree()
        self.vertex_degree_diagonal_matrix = self.calculate_diagonal_matrix_of_vertex_degree()
        self.edge_degree_diagonal_matrix = self.calculate_diagonal_matrix_of_edge_degree()

    def calculate_incident_matrix(self):
        """
        Calculate the incident matrix of the hypergraph.
        :return: The incident matrix of the hypergraph.
        """
        incident_matrix = np.zeros(shape=(self.num_vertices, self.num_edges), dtype=int)
        for i in range(self.num_vertices):
            vertex = self.vertices[i]
            for j in range(self.num_edges):
                edge = self.edges[j]
                if vertex in edge.vertices:
                    incident_matrix[i, j] = 1

        return incident_matrix

    def calculate_vertex_degree(self):
        """
        Calculate the degree of vertices in the hypergraph.
        :return: The degree of vertices in the hypergraph.
        """
        edge_weights = np.zeros(shape=(self.num_edges,), dtype=np.float64)
        for i in range(self.num_edges):
            edge = self.edges[i]
            edge_weights[i] = edge.weight

        edge_weights = edge_weights.reshape(-1, 1)
        vertex_degree_array = np.dot(self.incident_matrix, edge_weights)

        return vertex_degree_array.reshape(vertex_degree_array.size, )

    def calculate_edge_degree(self):
        """
        Calculate the degree of edges in the hypergraph.
        :return: The degree of edges in the hypergraph.
        """
        edges_degree = self.incident_matrix.sum(axis=0)
        return edges_degree

    def calculate_diagonal_matrix_of_vertex_degree(self):
        """
        Create a diagonal matrix with the degrees of vertex as the diagonal elements.
        :return: The diagonal matrix.
        """
        return np.diag(self.vertices_degree)

    def calculate_diagonal_matrix_of_edge_degree(self):
        """
        Create a diagonal matrix with the degrees of edge as the diagonal elements.
        :return: The diagonal matrix.
        """
        return np.diag(self.edges_degree)


def hypergraph_construction(dataset_dir: str) -> (List[Vertex], List[Edge]):
    vertices = []
    edges = []

    # 假设数据集包含一个 JSON文件,其中包含顶点和超边的信息
    #json_file_path = os.path.join(dataset_dir, 'hypergraph_data.json')

    with open(dataset_dir, 'r') as file:
        data = json.load(file)

        # 处理顶点
        if 'vertices' in data:
            for v in data['vertices']:
                vertex = Vertex(name=v['name'], weight=v.get('weight', 1.0))
                vertices.append(vertex)

                # 处理超边
        if 'edges' in data:
            for e in data['edges']:
                edge_vertices = []
                for v_name in e['vertices']:
                    vertex = next((v for v in vertices if v.name == v_name), None)
                    if vertex is not None:
                        edge_vertices.append(vertex)

                edge = Edge(name=e['name'], weight=e.get('weight', 1.0), vertices=edge_vertices)
                edges.append(edge)

    return vertices, edges

"""

{  
    "vertices": [  
        {"name": "v1", "weight": 1.0},  
        {"name": "v2", "weight": 0.5},  
        {"name": "v3", "weight": 1.5},  
        {"name": "v4", "weight": 1.0},  
        {"name": "v5", "weight": 2.0},  
        {"name": "v6", "weight": 1.0},  
        {"name": "v7", "weight": 0.8},  
        {"name": "v8", "weight": 1.0}  
    ],  
    "edges": [  
        {"name": "e1", "vertices": ["v1", "v2", "v3"], "weight": 1.0},  
        {"name": "e2", "vertices": ["v1", "v4"], "weight": 2.0},  
        {"name": "e3", "vertices": ["v2", "v3", "v5", "v6"], "weight": 1.5}  
    ]  
}

"""

if __name__ == '__main__':
   ma = Hypergraph()
   ma.init_hypergraph_from_files('hypergraph_data.json')

基于超图的跨级别和跨位置表示网络

Hyper-YOLO 框架中,主干网络被划分为五个离散阶段。这些阶段的特征图被表示为 {B1,B2,B3,B4,B5}。对五个基础特征进行通道级的拼接,合成跨级别视觉特征。使用距离阈值从每个特征点构建一个 ε-球,该 ε-球将作为超边,如下图所示。ε-球是一个超边,包含距离中心特征点在一定阈值内的所有特征点。

数学定义:

表示指定顶点 v的邻居顶点集。∥x−y∥是距离函数。

空间域超图卷积计算过程如下(添加了残差):

超图信息传递的矩阵表达式

其中 N_v(e)N_e(v)是两个邻居指示函数:

N_v(e)=\left \{ v|v\in e,v\in V \right \} 和 N_e(v)=\left \{ e|v\in e,e\in E \right \}

D_v 和 D_e 分别表示顶点度对角阵、超边对角度矩阵。

H 是超图关联矩阵,\Theta 是一个可训练参数。

基于超图的跨级别和跨位置表示网络(HyperC2Net)

其中 ∥∥ 表示矩阵拼接操作,Φ是融合函数。

Hyper-YOLO 框架

Hyper-YOLO 开源代码

超图相比于普通的图超图具有以下优势:
1、超图结构相对于一般图结构具有较强的数据样本间非线性高阶关联的刻画和挖掘能力;
2、超图结构相对于一般图结构能够更加准确地建模多元关系;
3、超图结构在处理多模态、异构数据时更加灵活,更方便多模态的融合与扩展;
4、超图结构相比于一般图结构在聚类过程上更有优势; 

延伸学习

超图相似度,相似度函数

正核和相似度(略)、 超图态射(略)、超图的分割(略)。

### Hyper-YOLO 技术详情 #### 基础概念与框架概述 Hyper-YOLO是一种增强型目标检测框架,其设计旨在通过引入超图计算来提高对复杂场景的理解能力和检测精度。此框架不仅继承了YOLO系列快速推理的优点,还进一步提升了模型性能,在COCO数据集上的APval指标相较于其他版本有明显改进[^3]。 #### 架构组成 Hyper-YOLO架构由多个重要组件构成: - **基础块(MANet)**:作为网络的基础构建单元,负责提取图像特征并传递给后续层处理。 - **颈部结构(HyperC2Net)**:位于骨干网之后,用于融合多尺度特征信息,加强不同层次间的信息交流,有助于捕捉更丰富的上下文细节[^1]。 这些组成部分共同作用,使得Hyper-YOLO能够在保持实时性的前提下实现更高的准确性。 #### 超图理论的应用 为了更好地理解对象间的关联性和空间分布特性,Hyper-YOLO利用了超图这一数学工具。在一个标准的无向图中,每条边连接一对节点;而在超图里,则允许一条“超边”同时连接超过两个以上的节点。这种扩展定义让超图能够表达更为复杂的交互模式,对于描述现实世界中的群体行为特别有用[^4]。 在实际应用过程中,Hyper-YOLO会基于输入图片的内容动态创建相应的超图表示形式,并据此调整预测逻辑,最终达到优化检测效果的目的。 ```python import torch.nn as nn class MANet(nn.Module): def __init__(self, in_channels=3): super(MANet, self).__init__() # 定义卷积层和其他必要的操作 def forward(self, x): pass # 实现前向传播过程 class HyperC2Net(nn.Module): def __init__(self): super(HyperC2Net, self).__init__() # 设计跨阶段特征聚合机制 def forward(self, features): pass # 处理来自各个阶段的特征映射 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

最好Tony

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

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

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

打赏作者

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

抵扣说明:

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

余额充值