<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>EpsilonZ&#39;s Blog</title>
  
  <subtitle>Compile the world, save the world.</subtitle>
  <link href="https://epsilonzyj.github.io/blog/atom.xml" rel="self"/>
  
  <link href="https://epsilonzyj.github.io/blog/"/>
  <updated>2026-06-12T05:48:31.730Z</updated>
  <id>https://epsilonzyj.github.io/blog/</id>
  
  <author>
    <name>EpsilonZ</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Raspberry Pi部署k8s</title>
    <link href="https://epsilonzyj.github.io/blog/posts/rpi-k8s.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/rpi-k8s.html</id>
    <published>2026-05-01T15:39:24.000Z</published>
    <updated>2026-06-12T05:48:31.730Z</updated>
    
    <content type="html"><![CDATA[<h1 id="先确定你的部署方式"><a href="#先确定你的部署方式" class="headerlink" title="先确定你的部署方式"></a>先确定你的部署方式</h1><p>你要先决定：</p><ul><li>方案 A：单机 Kubernetes<ul><li>只有一台树莓派，先搭一个单节点集群学习。</li></ul></li><li>方案 B：多机 Kubernetes<ul><li>比如：<ul><li>1 台 master/control-plane</li><li>1~N 台 worker</li></ul></li></ul></li></ul><p>下面是 <strong>最通用的 kubeadm 方式</strong> ，默认：</p><ul><li>系统：Raspberry Pi OS 64-bit / Ubuntu Server 64-bit</li><li>架构：arm64</li><li>容器运行时：containerd</li><li>网络插件：Flannel</li><li>Kubernetes：v1.29 系列</li></ul><h1 id="准备工作：每台树莓派都要做"><a href="#准备工作：每台树莓派都要做" class="headerlink" title="准备工作：每台树莓派都要做"></a>准备工作：每台树莓派都要做</h1><p>如果你以后要做多节点，这一部分所有节点都要执行。如果你只有一台，也一样执行。</p><h2 id="第-1-步：查看系统信息"><a href="#第-1-步：查看系统信息" class="headerlink" title="第 1 步：查看系统信息"></a>第 1 步：查看系统信息</h2><p>先执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">uname</span> -m</span><br><span class="line"><span class="built_in">cat</span> /etc/os-release</span><br><span class="line">hostname -I</span><br></pre></td></tr></table></figure><p>需要重点看：<code>uname -m</code> 是否是 <code>aarch64</code>，并记住当前树莓派 IP</p><h2 id="第-2-步：更新系统"><a href="#第-2-步：更新系统" class="headerlink" title="第 2 步：更新系统"></a>第 2 步：更新系统</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt upgrade -y</span><br></pre></td></tr></table></figure><p>安装常用工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install -y curl wget vim git net-tools htop ca-certificates gnupg lsb-release apt-transport-https</span><br></pre></td></tr></table></figure><h2 id="第-3-步：设置主机名"><a href="#第-3-步：设置主机名" class="headerlink" title="第 3 步：设置主机名"></a>第 3 步：设置主机名</h2><p>如果你只有一台机器，可以命名为：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> hostnamectl set-hostname rpi-master</span><br></pre></td></tr></table></figure><p>如果是多台：</p><ul><li>master：<code>rpi-master</code></li><li>worker1：<code>rpi-node1</code></li><li>worker2：<code>rpi-node2</code></li></ul><p>查看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hostname</span><br></pre></td></tr></table></figure><h2 id="第-4-步：配置-hosts"><a href="#第-4-步：配置-hosts" class="headerlink" title="第 4 步：配置 hosts"></a>第 4 步：配置 hosts</h2><p>编辑：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> nano /etc/hosts</span><br></pre></td></tr></table></figure><p>如果你是单节点，至少保留本机解析。<br>如果是多节点，建议写成这样：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">192.168.1.10 rpi-master</span><br><span class="line">192.168.1.11 rpi-node1</span><br><span class="line">192.168.1.12 rpi-node2</span><br></pre></td></tr></table></figure><p>把 IP 换成你自己的。</p><h1 id="关闭-swap"><a href="#关闭-swap" class="headerlink" title="关闭 swap"></a>关闭 swap</h1><p>Kubernetes 要求关闭 swap。先临时关闭：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> swapoff -a</span><br></pre></td></tr></table></figure><p>再永久关闭：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;/ swap / s/^/#/&#x27;</span> /etc/fstab</span><br></pre></td></tr></table></figure><p>检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">free -h</span><br></pre></td></tr></table></figure><p>确认 <code>Swap</code> 一栏是 0。</p><h1 id="开启内核模块和网络转发"><a href="#开启内核模块和网络转发" class="headerlink" title="开启内核模块和网络转发"></a>开启内核模块和网络转发</h1><p>这是 Kubernetes 网络能正常工作的关键。</p><h2 id="第-1-步：加载内核模块"><a href="#第-1-步：加载内核模块" class="headerlink" title="第 1 步：加载内核模块"></a>第 1 步：加载内核模块</h2><p>执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee /etc/modules-load.d/k8s.conf</span></span><br><span class="line"><span class="string">overlay</span></span><br><span class="line"><span class="string">br_netfilter</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>然后加载：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> modprobe overlay</span><br><span class="line"><span class="built_in">sudo</span> modprobe br_netfilter</span><br></pre></td></tr></table></figure><h2 id="第-2-步：设置内核参数"><a href="#第-2-步：设置内核参数" class="headerlink" title="第 2 步：设置内核参数"></a>第 2 步：设置内核参数</h2><p>执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee /etc/sysctl.d/k8s.conf</span></span><br><span class="line"><span class="string">net.bridge.bridge-nf-call-iptables = 1</span></span><br><span class="line"><span class="string">net.bridge.bridge-nf-call-ip6tables = 1</span></span><br><span class="line"><span class="string">net.ipv4.ip_forward = 1</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>应用配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sysctl --system</span><br></pre></td></tr></table></figure><p>验证：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sysctl net.ipv4.ip_forward</span><br></pre></td></tr></table></figure><p>应该输出：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">net.ipv4.ip_forward = 1</span><br></pre></td></tr></table></figure><h1 id="配置树莓派-cgroup"><a href="#配置树莓派-cgroup" class="headerlink" title="配置树莓派 cgroup"></a>配置树莓派 cgroup</h1><p>这一步非常重要，否则 kubelet 容易出问题。树莓派系统一般需要手工加启动参数。</p><h2 id="第-1-步：编辑启动参数"><a href="#第-1-步：编辑启动参数" class="headerlink" title="第 1 步：编辑启动参数"></a>第 1 步：编辑启动参数</h2><p>先判断文件在哪，常见是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/boot/firmware/cmdline.txt</span><br></pre></td></tr></table></figure><p>也有可能是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/boot/cmdline.txt</span><br></pre></td></tr></table></figure><p>你可以先试：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> /boot/firmware/cmdline.txt</span><br><span class="line"><span class="built_in">ls</span> /boot/cmdline.txt</span><br></pre></td></tr></table></figure><p>编辑对应文件，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> nano /boot/firmware/cmdline.txt</span><br></pre></td></tr></table></figure><p><strong>注意：这个文件通常只有一整行，不要换行。</strong>在这一行末尾追加：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1</span><br></pre></td></tr></table></figure><p>例如原来是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">console=serial0,115200 console=tty1 root=PARTUUID=xxxx rootfstype=ext4 fsck.repair=<span class="built_in">yes</span> rootwait</span><br></pre></td></tr></table></figure><p>改成：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">console=serial0,115200 console=tty1 root=PARTUUID=xxxx rootfstype=ext4 fsck.repair=<span class="built_in">yes</span> rootwait cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1</span><br></pre></td></tr></table></figure><h2 id="第-2-步：重启"><a href="#第-2-步：重启" class="headerlink" title="第 2 步：重启"></a>第 2 步：重启</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> reboot</span><br></pre></td></tr></table></figure><p>重启后检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> /proc/cgroups</span><br></pre></td></tr></table></figure><h1 id="安装并配置-containerd"><a href="#安装并配置-containerd" class="headerlink" title="安装并配置 containerd"></a>安装并配置 containerd</h1><p>即使你有 Docker，也建议明确配置 <code>containerd</code>。</p><h2 id="第-1-步：安装-containerd"><a href="#第-1-步：安装-containerd" class="headerlink" title="第 1 步：安装 containerd"></a>第 1 步：安装 containerd</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y containerd</span><br></pre></td></tr></table></figure><h2 id="第-2-步：生成默认配置"><a href="#第-2-步：生成默认配置" class="headerlink" title="第 2 步：生成默认配置"></a>第 2 步：生成默认配置</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/containerd</span><br><span class="line">containerd config default | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/containerd/config.toml &gt;/dev/null</span><br></pre></td></tr></table></figure><h2 id="第-3-步：修改-cgroup-驱动"><a href="#第-3-步：修改-cgroup-驱动" class="headerlink" title="第 3 步：修改 cgroup 驱动"></a>第 3 步：修改 cgroup 驱动</h2><p>编辑配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> nano /etc/containerd/config.toml</span><br></pre></td></tr></table></figure><p>找到这一行：</p><figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">SystemdCgroup</span> = <span class="literal">false</span></span><br></pre></td></tr></table></figure><p>改成：</p><figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">SystemdCgroup</span> = <span class="literal">true</span></span><br></pre></td></tr></table></figure><h2 id="第-4-步：重启并设置开机启动"><a href="#第-4-步：重启并设置开机启动" class="headerlink" title="第 4 步：重启并设置开机启动"></a>第 4 步：重启并设置开机启动</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart containerd</span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> containerd</span><br></pre></td></tr></table></figure><p>检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl status containerd</span><br></pre></td></tr></table></figure><p>如果看到 <code>active (running)</code> 就正常。</p><h1 id="安装-Kubernetes-组件"><a href="#安装-Kubernetes-组件" class="headerlink" title="安装 Kubernetes 组件"></a>安装 Kubernetes 组件</h1><p>安装：<code>kubelet</code>,<code>kubeadm</code>,<code>kubectl</code></p><h2 id="第-1-步：添加-Kubernetes-官方仓库"><a href="#第-1-步：添加-Kubernetes-官方仓库" class="headerlink" title="第 1 步：添加 Kubernetes 官方仓库"></a>第 1 步：添加 Kubernetes 官方仓库</h2><p>安装依赖：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y apt-transport-https ca-certificates curl gpg</span><br></pre></td></tr></table></figure><p>添加 key：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/apt/keyrings</span><br><span class="line">curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg</span><br></pre></td></tr></table></figure><p>添加源：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /&#x27;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/kubernetes.list</span><br></pre></td></tr></table></figure><h2 id="第-2-步：安装组件"><a href="#第-2-步：安装组件" class="headerlink" title="第 2 步：安装组件"></a>第 2 步：安装组件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y kubelet kubeadm kubectl</span><br><span class="line"><span class="built_in">sudo</span> apt-mark hold kubelet kubeadm kubectl</span><br></pre></td></tr></table></figure><p>查看版本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kubeadm version</span><br><span class="line">kubectl version --client</span><br><span class="line">kubelet --version</span><br></pre></td></tr></table></figure><h1 id="配置-Docker-与-containerd-关系"><a href="#配置-Docker-与-containerd-关系" class="headerlink" title="配置 Docker 与 containerd 关系"></a>配置 Docker 与 containerd 关系</h1><p>如果你只是拿 Docker 平时自己用，可以保留。但 Kubernetes 主要走 <code>containerd</code>。建议检查 containerd socket：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> /run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><p>如果存在，一般就没问题。</p><h1 id="拉取-Kubernetes-镜像"><a href="#拉取-Kubernetes-镜像" class="headerlink" title="拉取 Kubernetes 镜像"></a>拉取 Kubernetes 镜像</h1><p>先看 kubeadm 需要哪些镜像：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm config images list</span><br></pre></td></tr></table></figure><p>然后拉取：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm config images pull --cri-socket unix:///run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><p>如果下载慢或者失败，需要换国内镜像。对应的命令如下所示：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm config images pull --cri-socket unix:///run/containerd/containerd.sock --image-repository registry.aliyuncs.com/google_containers</span><br></pre></td></tr></table></figure><h1 id="初始化-Kubernetes-控制平面"><a href="#初始化-Kubernetes-控制平面" class="headerlink" title="初始化 Kubernetes 控制平面"></a>初始化 Kubernetes 控制平面</h1><p>如果你现在只有一台树莓派，这一步就是最关键的一步。先查看本机 IP：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hostname -I</span><br></pre></td></tr></table></figure><p>假设你的树莓派 IP 是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">192.168.1.10</span><br></pre></td></tr></table></figure><p>执行初始化：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm init \</span><br><span class="line">  --apiserver-advertise-address=192.168.1.10 \</span><br><span class="line">  --pod-network-cidr=10.244.0.0/16 \</span><br><span class="line">  --cri-socket unix:///run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><p>说明：</p><ul><li><code>--apiserver-advertise-address</code>：你的 master IP</li><li><code>--pod-network-cidr=10.244.0.0/16</code>：给 Flannel 用</li><li><code>--cri-socket</code>：指定 containerd</li></ul><p>初始化可能要几分钟。成功后你会看到类似：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Your Kubernetes control-plane has initialized successfully!</span><br></pre></td></tr></table></figure><p>并且下面会给你一段 <code>kubeadm join ...</code> 命令。<strong>一定复制保存</strong>，后续 worker 节点加入要用。如果拉取失败，可以采用国内镜像，对应命令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm init \</span><br><span class="line">  --apiserver-advertise-address=192.168.1.10 \</span><br><span class="line">  --pod-network-cidr=10.244.0.0/16 \</span><br><span class="line">  --cri-socket unix:///run/containerd/containerd.sock \</span><br><span class="line">  --image-repository registry.aliyuncs.com/google_containers</span><br></pre></td></tr></table></figure><p>同时需要编辑配置文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> nano /etc/containerd/config.toml</span><br></pre></td></tr></table></figure><p>将其中的<code>sandbox_image = &quot;...&quot;</code>改成<code>sandbox_image = &quot;registry.aliyuncs.com/google_containers/pause:3.10.2&quot;</code>，接着重启 containerd 和 kubelet：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart containerd</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart kubelet</span><br></pre></td></tr></table></figure><p>检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl status containerd --no-pager</span><br><span class="line"><span class="built_in">sudo</span> systemctl status kubelet --no-pager</span><br></pre></td></tr></table></figure><h1 id="配置-kubectl"><a href="#配置-kubectl" class="headerlink" title="配置 kubectl"></a>配置 kubectl</h1><p>初始化成功后，执行下面命令，让当前用户能直接用 <code>kubectl</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$HOME</span>/.kube</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> -i /etc/kubernetes/admin.conf <span class="variable">$HOME</span>/.kube/config</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chown</span> $(<span class="built_in">id</span> -u):$(<span class="built_in">id</span> -g) <span class="variable">$HOME</span>/.kube/config</span><br></pre></td></tr></table></figure><p>测试：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes</span><br></pre></td></tr></table></figure><p>这时大概率会看到节点是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">NotReady</span><br></pre></td></tr></table></figure><p>这是正常的，因为你还没装网络插件。</p><h1 id="安装-CNI-网络插件（Flannel）"><a href="#安装-CNI-网络插件（Flannel）" class="headerlink" title="安装 CNI 网络插件（Flannel）"></a>安装 CNI 网络插件（Flannel）</h1><p>执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml</span><br></pre></td></tr></table></figure><p>然后查看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods -A</span><br></pre></td></tr></table></figure><p>等几十秒到几分钟，再查看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes</span><br></pre></td></tr></table></figure><p>如果正常，节点会变成：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Ready</span><br></pre></td></tr></table></figure><h1 id="如果你只有一台树莓派：允许-master-运行业务-Pod"><a href="#如果你只有一台树莓派：允许-master-运行业务-Pod" class="headerlink" title="如果你只有一台树莓派：允许 master 运行业务 Pod"></a>如果你只有一台树莓派：允许 master 运行业务 Pod</h1><p>默认 control-plane 节点有污点，不让普通 Pod 调度上去。单机学习环境可以去掉：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl taint nodes --all node-role.kubernetes.io/control-plane-</span><br></pre></td></tr></table></figure><p>然后再看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes</span><br></pre></td></tr></table></figure><p>这样你的单机节点既是 master，也能跑应用。</p><h1 id="部署一个测试应用"><a href="#部署一个测试应用" class="headerlink" title="部署一个测试应用"></a>部署一个测试应用</h1><p>先部署 nginx：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl create deployment nginx --image=nginx</span><br></pre></td></tr></table></figure><p>暴露服务：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl expose deployment nginx --port=80 --<span class="built_in">type</span>=NodePort</span><br></pre></td></tr></table></figure><p>查看 Pod：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods -o wide</span><br></pre></td></tr></table></figure><p>查看 Service：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get svc</span><br></pre></td></tr></table></figure><p>你会看到类似：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx   NodePort   10.x.x.x   &lt;none&gt;   80:3xxxx/TCP</span><br></pre></td></tr></table></figure><p>然后访问：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://你的树莓派IP:3xxxx</span><br></pre></td></tr></table></figure><p>比如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://192.168.1.10:31234</span><br></pre></td></tr></table></figure><p>如果能打开 nginx 欢迎页，说明整个 Kubernetes 已经跑起来了。</p><p>如果无法拉取 nginx ，可以先使用一台可以正常拉取的电脑，运行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker pull --platform linux/arm64 nginx:latest</span><br><span class="line">docker save -o nginx-arm64.tar nginx:latest</span><br><span class="line">scp nginx-arm64.tar pi@&lt;worker-ip&gt;:~</span><br></pre></td></tr></table></figure><p>然后在树莓派上加载：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ctr -n k8s.io images import nginx-arm64.tar</span><br></pre></td></tr></table></figure><p>再删除pod：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete pod nginx-7f8fbb96d-65tt2</span><br><span class="line">kubectl get pods -w</span><br></pre></td></tr></table></figure><p>同还有一个关键点，需要让pod优先使用本地镜像，先删除旧的deployment和svc：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete deployment nginx</span><br><span class="line">kubectl delete svc nginx</span><br></pre></td></tr></table></figure><p>然后创建一个yaml:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt; nginx-local.yaml &lt;&lt;<span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">apiVersion: apps/v1</span><br><span class="line">kind: Deployment</span><br><span class="line">metadata:</span><br><span class="line">  name: nginx</span><br><span class="line">spec:</span><br><span class="line">  replicas: 1</span><br><span class="line">  selector:</span><br><span class="line">    matchLabels:</span><br><span class="line">      app: nginx</span><br><span class="line">  template:</span><br><span class="line">    metadata:</span><br><span class="line">      labels:</span><br><span class="line">        app: nginx</span><br><span class="line">    spec:</span><br><span class="line">      containers:</span><br><span class="line">      - name: nginx</span><br><span class="line">        image: docker.io/library/nginx:latest</span><br><span class="line">        imagePullPolicy: IfNotPresent</span><br><span class="line">        ports:</span><br><span class="line">        - containerPort: 80</span><br><span class="line">---</span><br><span class="line">apiVersion: v1</span><br><span class="line">kind: Service</span><br><span class="line">metadata:</span><br><span class="line">  name: nginx</span><br><span class="line">spec:</span><br><span class="line">  <span class="built_in">type</span>: NodePort</span><br><span class="line">  selector:</span><br><span class="line">    app: nginx</span><br><span class="line">  ports:</span><br><span class="line">  - port: 80</span><br><span class="line">    targetPort: 80</span><br><span class="line">    nodePort: 31678</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><p>应用</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f nginx-local.yaml</span><br><span class="line">kubectl get pods -w</span><br></pre></td></tr></table></figure><h1 id="如果你有多台树莓派：worker-加入集群"><a href="#如果你有多台树莓派：worker-加入集群" class="headerlink" title="如果你有多台树莓派：worker 加入集群"></a>如果你有多台树莓派：worker 加入集群</h1><p>在其他树莓派上，重复前面的步骤：</p><ul><li>更新系统</li><li>关闭 swap</li><li>配置 cgroup</li><li>安装 containerd</li><li>安装 kubelet kubeadm kubectl</li></ul><p><strong>但不要执行 <code>kubeadm init</code></strong>，而是在 worker 节点执行 master 初始化后给你的 join 命令，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm <span class="built_in">join</span> 192.168.1.10:6443 \</span><br><span class="line">  --token abcdef.1234567890abcdef \</span><br><span class="line">  --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \</span><br><span class="line">  --cri-socket unix:///run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><p>回到 master 查看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes -o wide</span><br></pre></td></tr></table></figure><p>如果成功，你会看到：</p><ul><li><code>rpi-master Ready</code></li><li><code>rpi-node1 Ready</code></li><li><code>rpi-node2 Ready</code></li></ul><h1 id="常用管理命令"><a href="#常用管理命令" class="headerlink" title="常用管理命令"></a>常用管理命令</h1><h2 id="查看节点"><a href="#查看节点" class="headerlink" title="查看节点"></a>查看节点</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes -o wide</span><br></pre></td></tr></table></figure><h2 id="查看所有-Pod"><a href="#查看所有-Pod" class="headerlink" title="查看所有 Pod"></a>查看所有 Pod</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods -A</span><br></pre></td></tr></table></figure><h2 id="查看服务"><a href="#查看服务" class="headerlink" title="查看服务"></a>查看服务</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get svc -A</span><br></pre></td></tr></table></figure><h2 id="查看-deployment"><a href="#查看-deployment" class="headerlink" title="查看 deployment"></a>查看 deployment</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get deployment -A</span><br></pre></td></tr></table></figure><h2 id="查看详细信息"><a href="#查看详细信息" class="headerlink" title="查看详细信息"></a>查看详细信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl describe node rpi-master</span><br><span class="line">kubectl describe pod &lt;pod名&gt; -n &lt;命名空间&gt;</span><br></pre></td></tr></table></figure><h2 id="查看日志"><a href="#查看日志" class="headerlink" title="查看日志"></a>查看日志</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl logs &lt;pod名&gt;</span><br></pre></td></tr></table></figure><p>如果 Pod 有多个容器：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl logs &lt;pod名&gt; -c &lt;容器名&gt;</span><br></pre></td></tr></table></figure><h1 id="开机启动"><a href="#开机启动" class="headerlink" title="开机启动"></a>开机启动</h1><p>一般以下服务都应自动启动：</p><h2 id="containerd"><a href="#containerd" class="headerlink" title="containerd"></a>containerd</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> containerd</span><br></pre></td></tr></table></figure><h2 id="kubelet"><a href="#kubelet" class="headerlink" title="kubelet"></a>kubelet</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> kubelet</span><br></pre></td></tr></table></figure><p>检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">systemctl is-enabled containerd</span><br><span class="line">systemctl is-enabled kubelet</span><br></pre></td></tr></table></figure><h1 id="如果你想确认-Kubernetes-是否真的可用"><a href="#如果你想确认-Kubernetes-是否真的可用" class="headerlink" title="如果你想确认 Kubernetes 是否真的可用"></a>如果你想确认 Kubernetes 是否真的可用</h1><p>执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kubectl create deployment hello --image=nginx</span><br><span class="line">kubectl expose deployment hello --port=80 --<span class="built_in">type</span>=NodePort</span><br><span class="line">kubectl get pods,svc</span><br></pre></td></tr></table></figure><p>删除测试：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete svc hello</span><br><span class="line">kubectl delete deployment hello</span><br></pre></td></tr></table></figure><h1 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h1><h2 id="问题-1：kubeadm-init-失败"><a href="#问题-1：kubeadm-init-失败" class="headerlink" title="问题 1：kubeadm init 失败"></a>问题 1：<code>kubeadm init</code> 失败</h2><p>看 kubelet 日志：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> journalctl -u kubelet -f</span><br></pre></td></tr></table></figure><p>常见原因：</p><ul><li>swap 没关</li><li>cgroup 参数没加</li><li>containerd 没启动</li><li><code>SystemdCgroup = true</code> 没配</li></ul><h2 id="问题-2：节点一直-NotReady"><a href="#问题-2：节点一直-NotReady" class="headerlink" title="问题 2：节点一直 NotReady"></a>问题 2：节点一直 <code>NotReady</code></h2><p>通常是网络插件没装好。</p><p>查看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods -A</span><br></pre></td></tr></table></figure><p>重点看：</p><ul><li><code>kube-flannel</code></li><li><code>coredns</code></li></ul><p>如果 flannel 没起来，节点通常不会 Ready。</p><h2 id="问题-3：镜像拉取失败"><a href="#问题-3：镜像拉取失败" class="headerlink" title="问题 3：镜像拉取失败"></a>问题 3：镜像拉取失败</h2><p>先看需要拉哪些镜像：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm config images list</span><br></pre></td></tr></table></figure><p>再手工拉：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm config images pull --cri-socket unix:///run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><h2 id="问题-4：端口访问不到-NodePort"><a href="#问题-4：端口访问不到-NodePort" class="headerlink" title="问题 4：端口访问不到 NodePort"></a>问题 4：端口访问不到 NodePort</h2><p>检查：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl get svc</span><br><span class="line"><span class="built_in">sudo</span> ss -lntp</span><br></pre></td></tr></table></figure><p>确认：</p><ul><li>服务类型是 <code>NodePort</code></li><li>防火墙没拦截</li><li>访问的是树莓派真实 IP</li></ul><h1 id="从零开始的最简命令版"><a href="#从零开始的最简命令版" class="headerlink" title="从零开始的最简命令版"></a>从零开始的最简命令版</h1><p>如果你只想先在 <strong>一台树莓派</strong> 快速跑起来，可以按下面顺序直接做。</p><h2 id="1）基础配置"><a href="#1）基础配置" class="headerlink" title="1）基础配置"></a>1）基础配置</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update &amp;&amp; <span class="built_in">sudo</span> apt upgrade -y</span><br><span class="line"><span class="built_in">sudo</span> apt install -y curl wget vim git net-tools htop ca-certificates gnupg lsb-release apt-transport-https</span><br><span class="line"><span class="built_in">sudo</span> swapoff -a</span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;/ swap / s/^/#/&#x27;</span> /etc/fstab</span><br></pre></td></tr></table></figure><h2 id="2）模块和内核参数"><a href="#2）模块和内核参数" class="headerlink" title="2）模块和内核参数"></a>2）模块和内核参数</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee /etc/modules-load.d/k8s.conf</span></span><br><span class="line"><span class="string">overlay</span></span><br><span class="line"><span class="string">br_netfilter</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> modprobe overlay</span><br><span class="line"><span class="built_in">sudo</span> modprobe br_netfilter</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee /etc/sysctl.d/k8s.conf</span></span><br><span class="line"><span class="string">net.bridge.bridge-nf-call-iptables = 1</span></span><br><span class="line"><span class="string">net.bridge.bridge-nf-call-ip6tables = 1</span></span><br><span class="line"><span class="string">net.ipv4.ip_forward = 1</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> sysctl --system</span><br></pre></td></tr></table></figure><h2 id="3）编辑-boot-firmware-cmdline-txt-或-boot-cmdline-txt"><a href="#3）编辑-boot-firmware-cmdline-txt-或-boot-cmdline-txt" class="headerlink" title="3）编辑 /boot/firmware/cmdline.txt 或 /boot/cmdline.txt"></a>3）编辑 <code>/boot/firmware/cmdline.txt</code> 或 <code>/boot/cmdline.txt</code></h2><p>末尾加：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1</span><br></pre></td></tr></table></figure><p>然后：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> reboot</span><br></pre></td></tr></table></figure><h2 id="4）安装-containerd"><a href="#4）安装-containerd" class="headerlink" title="4）安装 containerd"></a>4）安装 containerd</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y containerd</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/containerd</span><br><span class="line">containerd config default | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/containerd/config.toml &gt;/dev/null</span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;s/SystemdCgroup = false/SystemdCgroup = true/&#x27;</span> /etc/containerd/config.toml</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart containerd</span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> containerd</span><br></pre></td></tr></table></figure><h2 id="5）安装-Kubernetes"><a href="#5）安装-Kubernetes" class="headerlink" title="5）安装 Kubernetes"></a>5）安装 Kubernetes</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/apt/keyrings</span><br><span class="line">curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /&#x27;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/kubernetes.list</span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y kubelet kubeadm kubectl</span><br><span class="line"><span class="built_in">sudo</span> apt-mark hold kubelet kubeadm kubectl</span><br></pre></td></tr></table></figure><h2 id="6）初始化"><a href="#6）初始化" class="headerlink" title="6）初始化"></a>6）初始化</h2><p>把下面 IP 改成你自己的：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm init \</span><br><span class="line">  --apiserver-advertise-address=192.168.1.10 \</span><br><span class="line">  --pod-network-cidr=10.244.0.0/16 \</span><br><span class="line">  --cri-socket unix:///run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><h2 id="7）配置-kubectl"><a href="#7）配置-kubectl" class="headerlink" title="7）配置 kubectl"></a>7）配置 kubectl</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$HOME</span>/.kube</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> -i /etc/kubernetes/admin.conf <span class="variable">$HOME</span>/.kube/config</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chown</span> $(<span class="built_in">id</span> -u):$(<span class="built_in">id</span> -g) <span class="variable">$HOME</span>/.kube/config</span><br></pre></td></tr></table></figure><h2 id="8）安装-flannel"><a href="#8）安装-flannel" class="headerlink" title="8）安装 flannel"></a>8）安装 flannel</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml</span><br></pre></td></tr></table></figure><h2 id="9）单机允许调度"><a href="#9）单机允许调度" class="headerlink" title="9）单机允许调度"></a>9）单机允许调度</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl taint nodes --all node-role.kubernetes.io/control-plane-</span><br></pre></td></tr></table></figure><h2 id="10）验证"><a href="#10）验证" class="headerlink" title="10）验证"></a>10）验证</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes</span><br><span class="line">kubectl get pods -A</span><br><span class="line">kubectl create deployment nginx --image=nginx</span><br><span class="line">kubectl expose deployment nginx --port=80 --<span class="built_in">type</span>=NodePort</span><br><span class="line">kubectl get svc</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">在Raspberry Pi上部署k8s的过程记录。</summary>
    
    
    
    <category term="Web Dev" scheme="https://epsilonzyj.github.io/blog/categories/Web-Dev/"/>
    
    <category term="Cloud" scheme="https://epsilonzyj.github.io/blog/categories/Web-Dev/Cloud/"/>
    
    
    <category term="Web Dev" scheme="https://epsilonzyj.github.io/blog/tags/Web-Dev/"/>
    
    <category term="Kubernetes" scheme="https://epsilonzyj.github.io/blog/tags/Kubernetes/"/>
    
  </entry>
  
  <entry>
    <title>在Xcode Cloud上为React Native+Expo项目设置CI/CD</title>
    <link href="https://epsilonzyj.github.io/blog/posts/expo-ios-cicd.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/expo-ios-cicd.html</id>
    <published>2025-11-12T10:34:25.000Z</published>
    <updated>2026-06-12T05:48:31.714Z</updated>
    
    <content type="html"><![CDATA[<p><em>注：本文为AI生成，但由于可以解决问题，因此记录为备份</em></p><p>关于在本地使用React Native + Expo写的项目iOS端如何编译的可能有用的AI回答<a href="./expo-ios-cicd/more.pdf">文件</a>.</p><h3 id="在-Xcode-Cloud-上为-React-Native-Expo-项目设置-CI-CD"><a href="#在-Xcode-Cloud-上为-React-Native-Expo-项目设置-CI-CD" class="headerlink" title="在 Xcode Cloud 上为 React Native + Expo 项目设置 CI/CD"></a>在 Xcode Cloud 上为 React Native + Expo 项目设置 CI/CD</h3><p>将 React Native + Expo 项目集成到 Xcode Cloud 的持续集成与持续交付 (CI/CD) 流程中是完全可行的。其核心在于配置自定义构建脚本，以告知 Xcode Cloud 的构建环境如何处理 JavaScript 依赖（如 npm/yarn）和原生 iOS 依赖（CocoaPods）。</p><p>通过以下步骤，您可以实现从代码提交到 TestFlight 自动分发的完整自动化流程。</p><hr><h3 id="前提条件"><a href="#前提条件" class="headerlink" title="前提条件"></a>前提条件</h3><p>在开始之前，请确保您已准备好以下各项：</p><ol><li><strong>Apple Developer Program 成员资格</strong>：访问 Xcode Cloud 是付费开发者账户的权益。</li><li><strong>项目源码托管</strong>：您的项目代码必须托管在 Xcode Cloud 支持的 Git 仓库服务上，如 GitHub, Bitbucket, 或 GitLab。</li><li><strong>Xcode</strong>：确保您的 Mac 上安装了最新版本的 Xcode。</li><li><strong>原生 iOS 项目</strong>：Xcode Cloud 直接构建的是原生 <code>.xcodeproj</code> 或 <code>.xcworkspace</code> 文件。因此，您需要将 Expo 项目“预构建”以生成 <code>ios</code> 目录。</li></ol><hr><h3 id="核心理念：使用自定义脚本搭建桥梁"><a href="#核心理念：使用自定义脚本搭建桥梁" class="headerlink" title="核心理念：使用自定义脚本搭建桥梁"></a>核心理念：使用自定义脚本搭建桥梁</h3><p>Xcode Cloud 的构建环境是为原生 Apple 开发而设计的，默认情况下，它并不知道如何处理 Node.js、npm/yarn 包或 CocoaPods。为了解决这个问题，我们需要创建一个自定义构建脚本。当 Xcode Cloud 克隆您的代码仓库后，它会自动执行这个脚本来安装所有必要的非原生依赖，为后续的原生 Xcode 构建做好准备。</p><hr><h3 id="分步指南"><a href="#分步指南" class="headerlink" title="分步指南"></a>分步指南</h3><h4 id="第-1-步：生成原生-iOS-项目"><a href="#第-1-步：生成原生-iOS-项目" class="headerlink" title="第 1 步：生成原生 iOS 项目"></a>第 1 步：生成原生 iOS 项目</h4><p>如果您的 Expo 项目仍处于“托管工作流”（Managed Workflow）下，即项目根目录中没有 <code>ios</code> 和 <code>android</code> 文件夹，您需要先生成原生项目文件。</p><p>在您的项目根目录下打开终端，运行以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx expo prebuild --platform ios</span><br></pre></td></tr></table></figure><p>此命令会根据您的 <code>app.json</code> / <code>app.config.js</code> 配置生成一个 <code>ios</code> 文件夹，其中包含了 Xcode 所需的 <code>.xcworkspace</code> 文件。</p><p><strong>重要提示</strong>：运行 <code>prebuild</code> 是一项重大更改。请确保在执行前已提交所有代码，并建议在一个新的分支上进行此操作。命令执行后，将新生成的 <code>ios</code> 目录、以及对 <code>.gitignore</code> 等文件的修改一并提交到您的 Git 仓库。</p><h4 id="第-2-步：创建自定义构建脚本"><a href="#第-2-步：创建自定义构建脚本" class="headerlink" title="第 2 步：创建自定义构建脚本"></a>第 2 步：创建自定义构建脚本</h4><p>这是整个流程中最关键的一步。Xcode Cloud 会在特定时机自动查找并执行名为 <code>ci_scripts</code> 文件夹下的特定脚本。我们将使用 <code>ci_post_clone.sh</code> 脚本，它在 Xcode Cloud 克隆完您的仓库后立即执行。</p><ol><li><p><strong>创建目录</strong>：在您的项目根目录（与 <code>.xcodeproj</code> 文件同级）下创建一个名为 <code>ci_scripts</code> 的文件夹。</p></li><li><p><strong>创建脚本文件</strong>：在 <code>ci_scripts</code> 文件夹内，创建一个新文件，并将其命名为 <code>ci_post_clone.sh</code>。</p></li><li><p><strong>编写脚本内容</strong>：将以下内容粘贴到 <code>ci_post_clone.sh</code> 文件中。此脚本将安装 Homebrew（如果不存在）、Node.js、Yarn，并安装所有 JavaScript 和 CocoaPods 依赖。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/zsh</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 打印当前所在阶段</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🚀 Stage: Post-clone is running...&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置 Homebrew 路径并安装（适用于 Apple Silicon 和 Intel Mac 的通用设置）</span></span><br><span class="line"><span class="keyword">if</span> [ -d <span class="string">&quot;/opt/homebrew&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="comment"># Apple Silicon</span></span><br><span class="line">    <span class="built_in">export</span> HOMEBREW_PREFIX=<span class="string">&quot;/opt/homebrew&quot;</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    <span class="comment"># Intel</span></span><br><span class="line">    <span class="built_in">export</span> HOMEBREW_PREFIX=<span class="string">&quot;/usr/local&quot;</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="string">&quot;<span class="variable">$HOMEBREW_PREFIX</span>/bin:<span class="variable">$PATH</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Node.js 和 Yarn</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🍺 Installing Node.js and Yarn via Homebrew...&quot;</span></span><br><span class="line">brew install node yarn</span><br><span class="line"></span><br><span class="line"><span class="comment"># 打印 Node 和 Yarn 版本以供调试</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Node version: <span class="subst">$(node -v)</span>&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Yarn version: <span class="subst">$(yarn -v)</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 JavaScript 依赖</span></span><br><span class="line"><span class="comment"># CI_PRIMARY_REPOSITORY_PATH 是 Xcode Cloud 指向项目根目录的环境变量</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;📦 Installing JavaScript dependencies...&quot;</span></span><br><span class="line"><span class="built_in">cd</span> <span class="variable">$CI_PRIMARY_REPOSITORY_PATH</span></span><br><span class="line">yarn install</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 CocoaPods 依赖</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🍫 Installing CocoaPods dependencies...&quot;</span></span><br><span class="line"><span class="built_in">cd</span> <span class="variable">$CI_PRIMARY_REPOSITORY_PATH</span>/ios</span><br><span class="line">pod install</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;✅ Stage: Post-clone finished successfully.&quot;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p><strong>授予执行权限</strong>：该脚本文件必须具有可执行权限。在终端中运行以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x ci_scripts/ci_post_clone.sh</span><br></pre></td></tr></table></figure></li><li><p><strong>提交脚本</strong>：将 <code>ci_scripts</code> 文件夹及其中的 <code>ci_post_clone.sh</code> 文件提交到您的 Git 仓库。</p></li></ol><h4 id="第-3-步：在-Xcode-Cloud-中配置工作流"><a href="#第-3-步：在-Xcode-Cloud-中配置工作流" class="headerlink" title="第 3 步：在 Xcode Cloud 中配置工作流"></a>第 3 步：在 Xcode Cloud 中配置工作流</h4><p>现在，您的项目已经准备就绪。接下来是在 Xcode 中设置 Xcode Cloud。</p><ol><li><p><strong>打开项目</strong>：用 Xcode 打开您项目中的 <code>ios/*.xcworkspace</code> 文件。</p></li><li><p><strong>打开 Xcode Cloud 标签</strong>：在 Xcode 的左侧导航栏中，选择“Report Navigator”（报告导航器，图标像一个对话气泡），然后选择顶部的 “Cloud” 标签。</p></li><li><p><strong>开始配置</strong>：Xcode 可能会提示您“Set up Xcode Cloud”。点击并按照向导进行操作。</p><ul><li><strong>授权</strong>：授权 Xcode 访问您的 Git 仓库。</li><li><strong>创建工作流 (Workflow)</strong>：Xcode 会分析您的项目并建议一个默认工作流。</li></ul></li><li><p><strong>编辑工作流配置</strong>：</p><ul><li><strong>常规 (General)</strong>：为您的工作流命名，并选择产品（您的 App）。</li><li><strong>环境 (Environment)</strong>：选择最新的稳定版 Xcode 和 macOS。可以根据需要设置环境变量。</li><li><strong>开始条件 (Start Conditions)</strong>：配置触发构建的条件。例如，您可以设置为当代码推送到 <code>main</code> 或 <code>develop</code> 分支时自动开始构建。</li><li><strong>操作 (Actions)</strong>：<ul><li><strong>Archive</strong>：这是核心操作。确保选择正确的平台（iOS）和 Scheme。Xcode Cloud 会自动发现并使用您的 <code>ci_post_clone.sh</code> 脚本，无需在此处额外配置。</li></ul></li><li><strong>部署后操作 (Post-Actions)</strong>：<ul><li><strong>TestFlight (Internal/External Testing)</strong>：配置此项可实现构建成功后自动将 App 上传到 App Store Connect 并分发给内部或外部测试人员。</li></ul></li></ul></li><li><p><strong>保存并开始第一次构建</strong>：保存您的工作流配置。您可以手动触发第一次构建，或通过向您配置的启动分支（如 <code>main</code>）推送一次提交来触发。</p></li></ol><hr><h3 id="常见问题与最佳实践"><a href="#常见问题与最佳实践" class="headerlink" title="常见问题与最佳实践"></a>常见问题与最佳实践</h3><ul><li><strong>构建缓慢</strong>：由于 Xcode Cloud 的构建环境是临时的，每次构建都需要重新通过 Homebrew 安装 Node.js 和其他依赖，这会比 <code>eas build</code> 或本地构建慢。这是使用 Xcode Cloud 处理 React Native 项目的正常现象。</li><li><strong>管理密钥/环境变量</strong>：如果您的项目需要 API 密钥或其他敏感信息，请不要硬编码在代码中。应在 Xcode Cloud 工作流配置的“Environment”部分，将它们添加为<strong>秘密 (Secret)</strong> 环境变量。选中 “Secret” 复选框可防止其值在构建日志中暴露。</li><li><strong>调试构建失败</strong>：如果构建失败，请仔细查看 Xcode Cloud 提供的构建日志。日志会详细记录 <code>ci_post_clone.sh</code> 脚本的每一步输出，通常可以从中找到错误原因，例如依赖安装失败或脚本语法错误。</li><li><strong>选择 Xcode Cloud 还是 EAS Build？</strong><ul><li><strong>EAS Build</strong>：由 Expo 团队提供，是为 React Native 和 Expo 项目量身定制的 CI/CD 服务。它通常开箱即用，配置更简单，构建速度更快。</li><li><strong>Xcode Cloud</strong>：是苹果官方的 CI/CD 方案。如果您的团队已经深度集成在苹果生态中，或者您的项目除了 React Native App 外还包含其他原生目标（如 watchOS App、小组件等），或者公司政策要求使用第一方工具，那么 Xcode Cloud 是一个绝佳的选择。</li></ul></li></ul><p>通过以上配置，您的 React Native + Expo 项目就可以享受苹果原生 CI/CD 带来的便利，实现高效、可靠的自动化构建与分发。</p>]]></content>
    
    
    <summary type="html">在Xcode Cloud上为React Native+Expo项目设置CI/CD</summary>
    
    
    
    <category term="iOS dev" scheme="https://epsilonzyj.github.io/blog/categories/iOS-dev/"/>
    
    
    <category term="iOS dev" scheme="https://epsilonzyj.github.io/blog/tags/iOS-dev/"/>
    
  </entry>
  
  <entry>
    <title>How to use python effectively step by step</title>
    <link href="https://epsilonzyj.github.io/blog/posts/python-env.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/python-env.html</id>
    <published>2025-11-07T08:56:44.000Z</published>
    <updated>2026-06-12T05:48:31.727Z</updated>
    
    <content type="html"><![CDATA[<h2 id="环境下载"><a href="#环境下载" class="headerlink" title="环境下载"></a>环境下载</h2><h3 id="本文背景"><a href="#本文背景" class="headerlink" title="本文背景"></a>本文背景</h3><p>个人认为下载配置python开发环境一直是一件非常基础的事情，网络上相关博客有很多。虽然可能会出现按照一些博客配置会出现一些奇奇怪怪的问题且文中没给出解决方案，但是”just Google it!”照样可以解决，不用谷歌用百度大多数情况下也能解决，在这个时代，再不济还能问AI。</p><p>上面一般为我个人解决问题的一些通用途径。然而事实就是，似乎AI的出现，让很多人既丧失了使用搜索引擎搜索信息的能力，同时也没有掌握使用AI的技巧。前段时间有一个能源动力的同学向我询问python配置方法，一时心血来潮，便有了这篇文章，详细阐述了我在当年还是小白的时候遇到过的各种在不同操作系统上配置python时可能出现的所有我还是小白时见过的问题。虽然这篇文章和教如何进行信息检索没什么关系，但希望对于部分还并不会信息检索的同学能有一些信息检索的概念，能清楚最后需要掌握到什么程度。</p><h3 id="先聊点别的"><a href="#先聊点别的" class="headerlink" title="先聊点别的"></a>先聊点别的</h3><p>直接上python官网下载python使用确实是一种方法，但是这种仅适合单纯学习python语法等，并不适合真正项目开发，因为面对不同实验需要使用不同版本的python解释器，总不得每次使用版本不同就每次都从官网下载一个python吧？虽然有点烦，但是如果是服务器环境，那种没有桌面只有命令行的情况下怎么办呢？总不得各种curl指令然后使用一些奇技淫巧给下载下来吧。另外，真实开发中/跑实验时，如深度学习实验，不可能真的一个python的语法从头开始写，显然是需要下载各种依赖包，比方说pytorch等。这个时候又怎么搞呢？虽然pip一下似乎也可以，但是电脑环境会弄得非常乱。另外，如果不同版本的解释器同时都存在于电脑环境中，你如何确定运行你的项目时是需要的版本的解释器呢？</p><p>这个时候，就很需要一个重要的发明，用来隔离不同python版本的环境，同时也用来管理各种依赖包。幸运的是，这种软件早已被发明出来了，但是有太多软件，如miniconda，anaconda，uv，pip等等。如何进行选择呢？</p><p>既然是对于小白向学生向，那uv之类的就可以不考虑了，conda管理模式更适合。这里就讲一下miniconda和anaconda有什么区别：</p><ul><li>Miniconda：更轻量的包管理器，没有预下载的软件、依赖包等，似乎是没有GUI界面</li><li>Anaconda：比较重量的软件，下载安装的同时会下载很多其它内容</li></ul><h3 id="如何下载"><a href="#如何下载" class="headerlink" title="如何下载"></a>如何下载</h3><p>对于Linux用户，建议就直接使用miniconda吧，下载非常简单，以Ubuntu为例，直接在命令行运行以下指令等待时间即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install miniconda</span><br></pre></td></tr></table></figure><p>对于Mac用户，也很简单，类似的操作即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">brew install miniconda</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或者安装anaconda</span></span><br><span class="line">brew install anaconda</span><br></pre></td></tr></table></figure><p>如果你非常的不幸是Windows用户，那么可能需要折腾一会了，这里安装步骤就直接挂链接了，按照链接去安装下载配置即可。跳转链接：<a href="https://zhuanlan.zhihu.com/p/358641541">🔗</a>（如果单击没用，就使用Ctrl+单击即可）</p><p><em>注意，建议软件安装在较大的盘中，一方面下载的依赖包一般会非常大，另一方面在运行依赖包时，通常会在对应的环境目录下产生大量缓存，因此下载时1G的依赖包可能在运行后会膨胀，从而导致存储占用变大。</em></p><h2 id="怎么使用"><a href="#怎么使用" class="headerlink" title="怎么使用"></a>怎么使用</h2><h3 id="验证是否下载成功"><a href="#验证是否下载成功" class="headerlink" title="验证是否下载成功"></a>验证是否下载成功</h3><p>首先先验证conda是否下载成功，使用命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">conda -v</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或</span></span><br><span class="line">conda --version</span><br></pre></td></tr></table></figure><p>如果出现版本号那么就是没问题的，如果是出现红彤彤的一连串字，或者出现“无法识别conda”，或者有“conda不是内部或外部指令”，或者里面有“Error”等字样，那么恭喜你，开始了第一步踩坑。</p><h3 id="如何解决第一步坑"><a href="#如何解决第一步坑" class="headerlink" title="如何解决第一步坑"></a>如何解决第一步坑</h3><p>首先，打开任务栏上的Windows图标，点击关机。然后重新打开电脑，也许就解决了。虽然说关机可以解决50%的问题，但这个关机其实是有依据的，极大可能是因为你配置完环境，系统还没将环境的目录加载到系统中。而每次开机时，系统开机时会重新读取各种环境的配置的文件进行重新加载，这个时候你配置的新的内容就会被加载到系统中，所以可以解决问题。</p><p>如果再次运行指令还是显示同样问题，那么这个坑属于之前环境没配好，大概率是添加错了文件路径，重新配一遍就行了。</p><h3 id="开始使用conda"><a href="#开始使用conda" class="headerlink" title="开始使用conda"></a>开始使用conda</h3><p>一般正常的情况下，现在打开终端，通常会有如下的显示：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(base)C:xxxxx&gt; </span><br></pre></td></tr></table></figure><p>即前面会多一个前缀<code>(base)</code>，这种是属于正确的情况。但是大概率，安装完后打开终端会发现没有这玩意，那么恭喜你，第二个坑你又踩中了。</p><h3 id="如何解决自动加载conda环境的问题"><a href="#如何解决自动加载conda环境的问题" class="headerlink" title="如何解决自动加载conda环境的问题"></a>如何解决自动加载conda环境的问题</h3><p>这个没有显示(base)应该是属于没有自动加载base环境，其实也可以解决，怎么弄呢，按照网上的教程和博客，正常来说，会教你这么一条指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda activate base</span><br></pre></td></tr></table></figure><p>确实很正确，没有自动加载，那么我手动加载不就行了，然后你会发现怎么似乎输出和网上的教程不一样，有很多看不懂的输出，而且也没多出前缀，出现了一堆东西，里面有一个叫</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda init</span><br></pre></td></tr></table></figure><p>然后你搜索博客，发现网上教你直接运行这个命令，缺出现了下面的一堆乱七八糟的输出，怎么又和网上不一样，what can i say!</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">no changexxxxxxxxx</span><br><span class="line">no change     xxxxxxxxx</span><br><span class="line">no changexxxxxxxxx</span><br><span class="line">No action taken.</span><br></pre></td></tr></table></figure><p>那么很好，你进入了连环坑，并且这个坑似乎目前为止只有Windows系统才有。</p><h3 id="如何解决conda-init的问题"><a href="#如何解决conda-init的问题" class="headerlink" title="如何解决conda init的问题"></a>如何解决<code>conda init</code>的问题</h3><h4 id="为什么会遇到这个问题"><a href="#为什么会遇到这个问题" class="headerlink" title="为什么会遇到这个问题"></a>为什么会遇到这个问题</h4><p>这个问题是因为，在运行conda init后，在每次中断启动时都会运行conda init，而这种是有风险的。如果conda init是一个恶意脚本，每次运行终端时都会运行，那么系统显然就不安全了。为了避免这种情况，直接就禁止运行这个脚本了。</p><h4 id="如何进行解决"><a href="#如何进行解决" class="headerlink" title="如何进行解决"></a>如何进行解决</h4><p>作为运行者，我们知道这个指令运行的是什么，或者说我们就是要强制系统运行。怎么办呢，这个时候就要修改权限了。首先先提升权限，使用管理员身份打开powershel l（否则权限不够无法运行下面的指令），运行如下指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">get-ExecutionPolicy   <span class="comment"># 查看系统执行策略状态 </span></span><br><span class="line">set-executionpolicy remotesigned <span class="comment"># 修改执行策略状态</span></span><br></pre></td></tr></table></figure><p>然后你会看到下图所示的内容，按照下图一样输入<code>Y</code>即可：</p><p><img src="./python-env/1.png" alt=""></p><p>这个时候再运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda init</span><br></pre></td></tr></table></figure><p>就正常了，然后关闭终端重新打开。</p><h3 id="如何使用conda创建环境"><a href="#如何使用conda创建环境" class="headerlink" title="如何使用conda创建环境"></a>如何使用conda创建环境</h3><p>在经过上述的操作后，一般来说就能正常显示<code>(base)</code>前缀了。但是base环境一般安装的不是你想要的环境，需要重新创建新的环境，那么怎么操作呢？很简单，使用如下指令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">conda create -n 你想要取的名字</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如：你想要取名test，就输入下面的指令</span></span><br><span class="line">conda create -n <span class="built_in">test</span></span><br></pre></td></tr></table></figure><p>然后出现<code>([Y]/n)</code>的地方都直接回车，或者输入<code>Y</code>再回车即可。</p><p>当然这样创建出来的环境中是没有python的，怎么创建有python的环境呢，那么运行下面的指令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">conda create -n 你想取的名字 python=想下载的版本</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如</span></span><br><span class="line">conda create -n <span class="built_in">test</span> python=3.9 <span class="comment"># 会从3.9的版本中挑选一个子版本下载</span></span><br><span class="line">conda create -n <span class="built_in">test</span> python=3.9.2 <span class="comment"># 下载的是3.9.2版本的python</span></span><br></pre></td></tr></table></figure><h3 id="进入创建的环境"><a href="#进入创建的环境" class="headerlink" title="进入创建的环境"></a>进入创建的环境</h3><p>创建环境后，需要进入指定环境，使用如下指令即可</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">conda activate 环境名</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如</span></span><br><span class="line">conda activate <span class="built_in">test</span></span><br></pre></td></tr></table></figure><p>如果你忘了环境名怎么办，使用如下指令可以列出现有的所有环境的名字以及路径</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda <span class="built_in">env</span> list</span><br></pre></td></tr></table></figure><p>刚刚创建环境的时候忘记下载python了，现在该怎么办呢？先进入对应环境，然后运行下面的指令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">conda install python=指定版本</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如</span></span><br><span class="line">conda install python=3.9</span><br></pre></td></tr></table></figure><h3 id="下载依赖包"><a href="#下载依赖包" class="headerlink" title="下载依赖包"></a>下载依赖包</h3><p>下载依赖包，和上面下载python是完全一样的，直接运行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">conda install 依赖包名=指定版本</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如</span></span><br><span class="line">conda install numpy=1.21.4</span><br></pre></td></tr></table></figure><p>当然并不是所有的依赖包都可以使用conda进行安装，不过推荐使用conda，因为conda会自动检测包依赖问题并进行对应的版本升级或降级。(这个问题在后面经常会遇到，比方说下载的包A需要依赖包C，下载的包B也需要依赖包C，环境中可能也存在依赖包C，但是A所需要的依赖包C必须是某个指定版本，B要的是另一个版本，而现在的环境中是第三个版本，这种时候就非常头疼，而conda一般会自动解决，下面提到的pip就比较困难。)</p><p>对于一些包，并不能使用conda下载，如pytorch等，那么就需要使用pip了。但注意，pip是在下载python时下载下来的，所以如果你的环境中还没有python就无法使用pip指令。pip指令下载包也很简单，如下所示：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pip install 包名=包版本</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如</span></span><br><span class="line">pip install torch=2.1</span><br></pre></td></tr></table></figure><p>注意，其实下载包的时候，并不都需要指定版本，完全可以使用下面的指令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">pip install 包名</span><br><span class="line">conda install 包名</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如</span></span><br><span class="line">pip install torch</span><br><span class="line">conda install numpy</span><br></pre></td></tr></table></figure><p>在pip安装的时候，一般不会有询问界面；而conda安装包的时候，会有询问是否安装的行为，也是<code>([Y]/n)</code>这种，直接回车或者输入<code>Y</code>后回车即可。</p><p>但是在真正下载时，常常会发现，根据时间提示，一个包似乎要下载好几天，如果多几个包的话，可能不到一个G的东西需要下一个月。如果真的很天真的去等待，会发现事实上下载了一会儿就自己断掉了。那么恭喜你，又进了一个坑。</p><h3 id="如何换源"><a href="#如何换源" class="headerlink" title="如何换源"></a>如何换源</h3><p>为什么会出现上述现象，很简单，因为conda/pip的源在国外，服务器在国外，如果没有一些网络工具，要访问国外的服务器速度会非常非常慢。这个时候该怎么办呢？</p><p>其实解决方案在前面下载anaconda时就给出了，直接进行换源，将conda使用清华源、中科大源等镜像站即可。常见的国内源有：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">清华镜像anaconda源：</span><br><span class="line">channels:</span><br><span class="line">https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/</span><br><span class="line">https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/</span><br><span class="line">https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/ ssl_verify: true</span><br><span class="line"></span><br><span class="line">上海交大anaconda镜像源：</span><br><span class="line">channels:</span><br><span class="line">https://mirrors.sjtug.sjtu.edu.cn/anaconda/pkgs/main/</span><br><span class="line">https://mirrors.sjtug.sjtu.edu.cn/anaconda/pkgs/free/</span><br><span class="line">https://mirrors.sjtug.sjtu.edu.cn/anaconda/cloud/conda-forge/ ssl_verify: true</span><br><span class="line"></span><br><span class="line">中科大anaconda镜像源</span><br><span class="line">channels:</span><br><span class="line">https://mirrors.ustc.edu.cn/anaconda/pkgs/main/</span><br><span class="line">https://mirrors.ustc.edu.cn/anaconda/pkgs/free/</span><br><span class="line">https://mirrors.ustc.edu.cn/anaconda/cloud/conda-forge/ ssl_verify: true</span><br></pre></td></tr></table></figure><p>以添加清华源为例，输入以下指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/</span><br></pre></td></tr></table></figure><p>而移除源的指令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 要移除的单个源</span></span><br><span class="line">conda config --remove channels 要移除的单个源</span><br><span class="line"><span class="comment"># 移除全部源</span></span><br><span class="line">conda config --remove channels </span><br></pre></td></tr></table></figure><p>当然pip下载也是同样的问题，需要进行换源。</p><p>如果是临时使用，即只在本次下载中换源，则使用下面的指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install 包名 -i https://mirrors.bfsu.edu.cn/pypi/web/simple --trusted-host mirrors.bfsu.edu.cn</span><br></pre></td></tr></table></figure><p>如果是需要一直使用，那么以阿里云镜像为例，使用下面的指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip config <span class="built_in">set</span> global.index-url https://mirrors.aliyun.com/pypi/simple/</span><br></pre></td></tr></table></figure><h3 id="根据文件下载依赖包"><a href="#根据文件下载依赖包" class="headerlink" title="根据文件下载依赖包"></a>根据文件下载依赖包</h3><p>在运行别人源码的时候，为了保证环境一致，需要配置完全相同的环境，从python版本到包版本，才<strong>有可能</strong>运行成功。通常，作为学术规范和道德（划掉），一般都会有一个<code>requirements.txt</code>文件，这个文件中记录了各个包的版本，或者仅记录各个依赖包，文件格式大体如下：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">xxxxx=2.1</span><br><span class="line">xxxxx</span><br><span class="line">xxxxx</span><br><span class="line">xxxxx</span><br><span class="line">xxxxx=1.5</span><br><span class="line">xxxxx</span><br><span class="line">xxxxx=3.4</span><br><span class="line">xxxxx</span><br><span class="line">xxxxx</span><br><span class="line">············</span><br></pre></td></tr></table></figure><p>对于包特别多的，显然不会自己一行一行命令去敲，这太低效了。有没有什么简单的方法呢？</p><p>有的，兄弟有的：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install -r requirements.txt</span><br></pre></td></tr></table></figure><h3 id="查看本环境中的依赖包版本"><a href="#查看本环境中的依赖包版本" class="headerlink" title="查看本环境中的依赖包版本"></a>查看本环境中的依赖包版本</h3><p>这个非常简单，直接运行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda list</span><br></pre></td></tr></table></figure><p>即可。</p><p>如果你都是使用pip安装的包，可以运行下面的指令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip list</span><br></pre></td></tr></table></figure><h3 id="安装错依赖包版本了怎么办-如何卸载包"><a href="#安装错依赖包版本了怎么办-如何卸载包" class="headerlink" title="安装错依赖包版本了怎么办/如何卸载包"></a>安装错依赖包版本了怎么办/如何卸载包</h3><p>对于conda，重新conda install就行了，反正它自己会去解决版本冲突问题的。当然，别忘记在指令中加入你所需要的版本才会正确下载对应版本的包。</p><p>对于pip，有点麻烦，先要卸载再下载（也许也可以直接下载？没试过）</p><p>卸载包的指令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip uninstall 包名</span><br></pre></td></tr></table></figure><p>conda卸载也同理</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda uninstall 包名</span><br></pre></td></tr></table></figure><h3 id="如何将环境中的依赖包名存储到文件"><a href="#如何将环境中的依赖包名存储到文件" class="headerlink" title="如何将环境中的依赖包名存储到文件"></a>如何将环境中的依赖包名存储到文件</h3><p>正如上文所说的，为了遵守道德（划掉），需要创建一个reqiurements.txt文件。一种偷懒的方法是自己创建文件，写一下主要的包名和版本，其它的让别人自己解决去。</p><p>另一种是采用指令，直接输出所有的包版本，使用如下指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip freeze &gt; requirements.txt</span><br></pre></td></tr></table></figure><p>稍微来解释一下这个指令是什么意思，pip freeze可以获取到所有的包名和版本并输出到控制台，而<code>&gt;</code>是将控制台的内容重定向到后面跟着的文件名中输出，这么一解释自然就知道为什么这条指令可以创建相应文件了。</p><p>当然两种方法不好说谁好谁坏，第一种方法漏掉很多包，让其他人配置的时候很麻烦，要一遍一遍运行程序，当报包缺失的时候再解决，很头疼。但第二种难道就好了吗？其实也不是，由于各机器硬件环境不同，操作系统不同，以及安装时通常没给出python版本，即使给了这么多包，但是指定了各个版本后，极大可能在下载时会出现大量依赖包版本冲突，并没有比第一种方法好多少。</p><h3 id="如何删除环境"><a href="#如何删除环境" class="headerlink" title="如何删除环境"></a>如何删除环境</h3><p>对于anaconda，打开Anaconda navigator软件，点击左侧的Environments按钮，选中你所要删除的环境，点击remove按钮即可。如下图:</p><p><img src="./python-env/2.png" alt=""></p><p>对于conda删除环境，其实有对应的指令，但是笔者发现在anaconda中这个指令并不能彻底删除对应环境，因此不做介绍了，而且GUI界面更适合小白操作。</p><h3 id="（防止不知道）如何查看当前环境中python版本"><a href="#（防止不知道）如何查看当前环境中python版本" class="headerlink" title="（防止不知道）如何查看当前环境中python版本"></a>（防止不知道）如何查看当前环境中python版本</h3><p>一种直接使用conda查看环境依赖包的指令，直接从中去找python字段，但太低效了。</p><p>直接</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python --version</span><br></pre></td></tr></table></figure><p>即可</p><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>python相对而言是一个很简单很方便的编程语言，而对于python项目/实验，环境是及其重要的。在运行他人项目时，遇到环境配置配几个小时没配好是很正常的现象，两三天都配不出也是属于常见的事情了。因此，在学习python时，熟练使用各种命令，熟练配置环境，是非常重要的一环。</p>]]></content>
    
    
    <summary type="html">一文讲通python环境配置所有问题</summary>
    
    
    
    <category term="Env" scheme="https://epsilonzyj.github.io/blog/categories/Env/"/>
    
    <category term="Programming Language" scheme="https://epsilonzyj.github.io/blog/categories/Env/Programming-Language/"/>
    
    
    <category term="Python" scheme="https://epsilonzyj.github.io/blog/tags/Python/"/>
    
    <category term="Env" scheme="https://epsilonzyj.github.io/blog/tags/Env/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：HDSE</title>
    <link href="https://epsilonzyj.github.io/blog/posts/HDSE.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/HDSE.html</id>
    <published>2025-11-05T07:38:12.000Z</published>
    <updated>2026-06-12T05:48:31.699Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Yuankai Luo, Hongkang Li, Lei Shi, Xiao-Ming Wu</li><li>日期: 2024</li><li>出处: NeurIPS</li><li>PDF: <a href="https://proceedings.neurips.cc/paper_files/paper/2024/file/68a3919db3858f548dea769f2dbba611-Paper-Conference.pdf">https://proceedings.neurips.cc/paper_files/paper/2024/file/68a3919db3858f548dea769f2dbba611-Paper-Conference.pdf</a></li><li>开源代码: <a href="https://github.com/LUOyk1999/HDSE">https://github.com/LUOyk1999/HDSE</a></li></ul><hr><h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>图变换器需要强归纳偏置来推导有意义的注意力分数。然而，当前方法往往难以捕获更远的距离、层次结构或社区结构，而这些结构在各种图中都很常见，如分子图、社交网络和引用网络。本文提出了一种层次距离结构编码（Hierarchical Distance Structural Encoding, HDSE）方法，用于模拟图中的节点距离，重点关注其多级层次性质。我们引入了一个新框架，将HDSE无缝集成到现有图变换器的注意力机制中，允许与其他位置编码同时应用。为了将带有HDSE的图变换器应用于大规模图，我们进一步提出了一种高级HDSE，有效将线性变换器偏向图的层次结构。我们从理论上证明了HDSE在表达能力和泛化能力方面的优越性。实验上，我们证明了带有HDSE的图变换器在图分类、7个图级别数据集的回归任务以及11个大规模图的节点分类任务中表现出色。</p><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><h1 id="研究问题概述"><a href="#研究问题概述" class="headerlink" title="研究问题概述"></a>研究问题概述</h1><p>Luo等(2024)指出，图变换器需要强大的归纳偏置(inductive biases)来获得有意义的注意力得分，但现有方法存在以下几个关键问题：</p><ol><li><strong>层次结构捕捉不足</strong>：当前方法往往难以捕捉图中的长距离、层次结构或社区结构，而这些结构在分子图、社交网络和引用网络等各类图中普遍存在。</li><li><strong>与MPNNs对比的局限性</strong>：与消息传递图神经网络(MPNNs)相比，图变换器虽然能避免MPNNs的过度平滑(oversmoothing)和过度压缩(over-squashing)问题，但缺乏强归纳偏置。</li><li><strong>位置编码挑战</strong>：发展有效的位置编码具有挑战性，因为图数据中的层次结构识别与其他欧几里得域有显著差异，导致图变换器容易过拟合，在数据有限时表现不如MPNNs。</li><li><strong>计算复杂度高</strong>：全局全对注意力机制的时间复杂度和空间复杂度随节点数量呈二次增长，限制了图变换器在具有数百万节点的图上的应用。</li><li><strong>社区结构处理困难</strong>：大规模图(如社交网络和引用网络)通常具有社区结构，这些结构具有紧密相连的组和明显的层次属性，但图变换器往往缺乏在各个层次上融入层次结构信息的能力。<h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><h1 id="层次距离结构编码-HDSE-方法详解"><a href="#层次距离结构编码-HDSE-方法详解" class="headerlink" title="层次距离结构编码(HDSE)方法详解"></a>层次距离结构编码(HDSE)方法详解</h1>Luokai等(2024)提出的层次距离结构编码(Hierarchical Distance Structural Encoding, HDSE)方法专门为增强图转换器在捕捉图中层次结构方面的能力而设计。以下是该方法的核心内容：<h2 id="1-图层次距离-GHD-定义"><a href="#1-图层次距离-GHD-定义" class="headerlink" title="1. 图层次距离(GHD)定义"></a>1. 图层次距离(GHD)定义</h2><img src="./HDSE/HDSE.png" alt=""><br>首先，论文引入了图层次距离(Graph Hierarchy Distance, GHD)作为衡量图节点之间距离的新指标，特别关注其多级层次特性：<br><strong>定义1（图层次距离）</strong>：给定图G中的两个节点u, v和图层次<script type="math/tex">(G_i, \phi_i)_{i \geq 0}</script>，k级层次距离GHD定义为：<script type="math/tex; mode=display">GHD_0(u, v) = SPD(u, v) \quad (2)</script><script type="math/tex; mode=display">GHD_k(u, v) = SPD(\phi_{k-1} \circ \ldots \circ \phi_0(u), \phi_{k-1} \circ \ldots \circ \phi_0(v)) \quad (2)</script>其中<script type="math/tex">SPD(\cdot, \cdot)</script>表示两个节点之间的最短路径距离（若节点不连通则为∞），<script type="math/tex">\phi_{k-1} \circ \ldots \circ \phi_0(\cdot)</script>将<script type="math/tex">G_0</script>中的节点映射到<script type="math/tex">G_k</script>中的节点。<br>GHD满足距离度量的四个性质：零当且仅当节点相同、恒为正、对称性及三角不等式。如图1所示，<script type="math/tex">GHD_0</script> <script type="math/tex">(v_1, v_{11}) = 7</script>，而<script type="math/tex">GHD_1(v_1, v_{11}) = 2</script>，表明在更高层次上节点间的距离关系被简化，这有助于捕捉图中的层次结构。<h2 id="2-层次距离结构编码-HDSE"><a href="#2-层次距离结构编码-HDSE" class="headerlink" title="2. 层次距离结构编码(HDSE)"></a>2. 层次距离结构编码(HDSE)</h2>基于GHD，论文提出层次距离结构编码(HDSE)，对于每对节点$i, j \in V$定义为：<script type="math/tex; mode=display">D_{i,j} = [GHD_0, GHD_1, \ldots, GHD_K]_{i,j} \in \mathbb{R}^{K+1} \quad (3)</script>其中$GHD_k$是k级层次距离矩阵，$K \in \mathbb{N}$控制考虑的最大层次级别。<br>HDSE相比传统的最短路径距离(SPD)具有更强的表达能力。通过GD-WL测试可以证明，HDSE能够区分更多不同结构的图。如图2所示，HDSE可以区分立方体图(Desargues)和十二面体图(Dodecahedron)，而仅使用SPD的GD-WL测试无法区分这两个图。<br><img src="./HDSE/HDSE-example.png" alt=""><h2 id="3-HDSE在图转换器中的集成"><a href="#3-HDSE在图转换器中的集成" class="headerlink" title="3. HDSE在图转换器中的集成"></a>3. HDSE在图转换器中的集成</h2>为了将HDSE整合到现有图转换器的注意力机制中，论文提出了一种新颖框架：<br>首先，使用端到端可训练函数$\text{Bias}: \mathbb{R}^{K+1} \rightarrow \mathbb{R}$学习偏置的结构权重：<script type="math/tex; mode=display">H_{i,j} = \text{MLP}\{e^0_{\text{clip}^0_{i,j}}, \ldots, e^K_{\text{clip}^K_{i,j}}\}, \quad H_{i,j} \in \mathbb{R} \quad (4)</script>其中：<script type="math/tex; mode=display">\text{clip}^k_{i,j} = \min(L, GHD^k_{i,j}), \quad 0 \leq k \leq K</script>这里<script type="math/tex">[e_0^k, e_1^k, \ldots, e_L^k]_{0\le k \le K} \in \mathbb{R}^{d \times (L+1)}</script>收集了<script type="math/tex">L+1</script>个可学习的特征嵌入向量，分别对应<script type="math/tex">k</script>层次的不同距离。<br>然后将学习到的偏置权重集成到图转换器的自注意力机制中：<script type="math/tex; mode=display">\text{Attention}(X) = \text{softmax}\left(\frac{A + H}{\sqrt{d'}}\right)V, \quad A = QK^\top \quad (5)</script>这种集成方式与主干架构无关，可以无缝集成到现有图转换器的自注意力机制中。论文从理论上证明了HDSE在表达能力和泛化能力方面的优越性。<h2 id="4-大规模图的高级HDSE"><a href="#4-大规模图的高级HDSE" class="headerlink" title="4. 大规模图的高级HDSE"></a>4. 大规模图的高级HDSE</h2>对于大规模图（从百万到十亿节点），全局全对注意力机制的计算复杂性问题变得尤为突出。受Linformer的启发，论文提出了高级HDSE，将线性转换器偏向图的层次结构：<script type="math/tex; mode=display">D^c_{i,j} = \left[GHD^c\left(\prod_{l=0}^{c-1} P^l\right), \ldots, GHD^K\left(\prod_{l=0}^{c-1} P^l\right)\right]_{i,j}, \quad 1 \leq c \leq K \quad (7)</script>其中：</li></ol><ul><li>$GHD^m$ 表示 $m$ 级图层次距离矩阵（graph hierarchy distance）</li><li>$P^l$ 是投影矩阵，每行是独热向量，表示输入节点所属的 $l$ 级集群</li><li>$\prod_{l=0}^{c-1} P^l$ 是投影矩阵的连乘积</li><li>$D^c \in \mathbb{R}^{|V^0| \times |V^c| \times (K+1-c)}$，其中 $V^0$ 是原始图的节点集，$V^c$ 是第 $c$ 级粗化图的节点集<blockquote><p>$GHD^m\left(\prod_{l=0}^{c-1} P^l\right)$, $c \leq m \leq K$ 计算的是输入节点到c级图层次中的集群的距离</p></blockquote></li></ul><p>注意：</p><ul><li>在2.1节中，论文定义了投影矩阵$P̂^k ∈ {0,1}^{|V^k|×|V^{k+1}|}$，其中$P̂^k_{ij} = 1$当且仅当在k级图中的节点$v^k_i$属于k+1级图中的节点$v^{k+1}_j$所在的簇</li><li>归一化版本的投影矩阵定义为$P^k = P̂^k C_k^{-1/2}$，其中$C_k$是对角矩阵，其对角线元素表示簇的大小 </li><li>每个投影矩阵$P^l$的行是一个one-hot向量，表示输入节点属于l级的哪个簇</li><li>投影矩阵的乘积$∏_{l=0}^{c-1} P^l$代表从原始图$G^0$到高阶粗粒度图$G^c$的直接映射关系<h2 id="5-理论基础"><a href="#5-理论基础" class="headerlink" title="5. 理论基础"></a>5. 理论基础</h2>论文从理论上证明了HDSE的优越性：<br><strong>命题1</strong>：使用HDSE的GD-WL测试比使用最短路径距离SPD的GD-WL测试具有更强的表达能力。论文首先证明了GD-WL使用HDSE至少能区分GD-WL使用SPD所能区分的所有图；然后通过十二面体图和立方体图的例子展示了HDSE的更强区分能力。<br><strong>命题2</strong>：具有HDSE的图转换器区分非同构图的能力至多等同于使用HDSE的GD-WL测试。在适当参数和足够多的头和层数下，具有HDSE的图转换器可以匹配使用HDSE的GD-WL测试的能力。<br><strong>推论1</strong>：存在一个使用HDSE的图转换器，比使用相同架构但使用SPD或不使用相对位置编码的图转换器更具表现力。<br><strong>命题3</strong>：对于半监督节点分类问题，当节点标签由”hierarchical core neighborhood”决定时，适当初始化的具有HDSE的单层图转换器能获得满意的泛化误差，而使用SPD或不使用相对位置编码无法保证这一点。<br>HDSE通过在图转换器中引入强归纳偏置，有效解决了transformer架构在图学习中缺乏层次结构信息的局限，在各种图任务中取得了优越的性能表现。</li></ul>]]></content>
    
    
    <summary type="html">Enhancing Graph Transformers with Hierarchical Distance Structural Encoding</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Tokenizing/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/tags/Tokenizing/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：Simple Path Structural Encoding</title>
    <link href="https://epsilonzyj.github.io/blog/posts/SPSE.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/SPSE.html</id>
    <published>2025-10-27T08:47:27.000Z</published>
    <updated>2026-06-12T05:48:31.707Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Louis Airale, Antonio Longa, Mattia Rigon, Andrea Passerini, Roberto Passerone</li><li>日期: 2025</li><li>出处: ICML</li><li>PDF: <a href="https://openreview.net/pdf?id=t3zwUqibMq">https://openreview.net/pdf?id=t3zwUqibMq</a></li><li>开源代码: <a href="https://github.com/LouisBearing/Graph-SPSE-Encoding">https://github.com/LouisBearing/Graph-SPSE-Encoding</a></li></ul><hr><h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>图变换器将全局自注意力机制扩展到图结构数据，在图学习领域取得了显著成功。最近，相对随机游走概率（RRWP）被发现通过将结构和位置信息编码到边表示中，能够进一步增强图变换器的预测能力。然而，RRWP并不总能区分属于不同局部图模式的边，这降低了其捕获图完全结构复杂性的能力。本文引入了简单路径结构编码（SPSE），一种利用简单路径计数进行边编码的新方法。我们从理论和实验上证明了SPSE克服了RRWP的局限性¹，提供了更丰富的图结构表示，特别是在捕获局部循环模式方面。为了使SPSE在计算上可行，我们提出了一个简单路径计数的有效近似算法。在各种基准测试中，包括分子图和长程图数据集，SPSE相比RRWP展示了显著的性能提升，在区分性任务中取得了统计显著的增益。这些结果表明SPSE是一种强大的边编码替代方案，可用于增强图变换器的表现力。</p><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><p>本文主要研究图变换器(Graph Transformers)中的结构编码问题，特别是针对边表示的设计方法 。传统图神经网络(GNNs)依赖局部消息传递机制，难以捕获长程依赖和结构模式。图变换器通过全局自注意力克服了这一限制，但面临着如何设计合适的结构和位置编码的挑战，特别是要捕获图的不规则结构特性。近期研究发现相对随机游走概率(RRWP)可以将结构和位置信息编码到边表示中，增强预测能力 。然而，RRWP在某些情况下无法区分属于不同局部图模式的边，限制了其捕获图完全结构复杂性的能力。</p><h2 id="RRWP存在的问题"><a href="#RRWP存在的问题" class="headerlink" title="RRWP存在的问题"></a>RRWP存在的问题</h2><p><img src="./SPSE/SPSE-RRWP.png" alt=""></p><h3 id="局限性一：无法区分不同图结构的边"><a href="#局限性一：无法区分不同图结构的边" class="headerlink" title="局限性一：无法区分不同图结构的边"></a>局限性一：无法区分不同图结构的边</h3><p>RRWP(相对随机游走概率)基于随机游走概率的边编码在某些情况下无法区分来自不同拓扑图结构的边，导致它们为非常不同的图结构分配相同的转换概率 。<br><strong>数学定义</strong>：</p><ul><li>随机游走矩阵：给定图 $G$ 和 $k ∈ N^*$ ，$k$ 步随机游走矩阵 $P^k ∈ R^{|V|×|V|}$ 给出所有节点对间长度为 $k$ 的随机游走的着陆概率：<script type="math/tex; mode=display">P^k = (D^{-1}A)^k</script>其中 $D$ 是度矩阵， $A$ 是邻接矩阵。</li><li>等价关系定义：对于 $k ≥ 1$ ，<script type="math/tex">(i, j)_G =^k_{RW} (i', j')_G' ⇐⇒ (P^k)_{ij} = (P'^k)_{i'j'}</script><br>其中 $P’^k$ 是图G’的k步随机游走矩阵 。<br><strong>命题1</strong>：令 $G = (V, E)$ 是一个偶长度循环图，即 $|V| = 2n$ ，且 $G’ = (V’, E’)$ 是一个路径图，满足 $|V’| = 2n + 1$ 。那么对于G中任意节点对(i, j)，在G’中存在节点对(i’, j’)，使得 $(i, j)_G =^RW (i’, j’)_G’$ 。<br>这个命题表明，随机游走转换概率无法区分偶长度循环图和路径图，在考虑单节点对时二者是等价的 。这意味着RRWP编码可能错过关键的结构差异。<h3 id="局限性二：缺乏唯一性"><a href="#局限性二：缺乏唯一性" class="headerlink" title="局限性二：缺乏唯一性"></a>局限性二：缺乏唯一性</h3><strong>命题2</strong>：令 $G = (V, E)$ 是一个图，$(i, j) ∈ V × V$ 是一对节点。那么存在一个非同构图 $G’ = (V’, E’)$ 和节点对 $(i’, j’) ∈ V’ × V’$，使得 $(i, j)_G =^RW (i’, j’)_G’$ 。<br>这表明RRWP编码对于节点对从来不是唯一的，不能用于标识图。<br><img src="./SPSE/SPSE-vs-RRWP.png" alt=""></li></ul><h2 id="数学公式推导"><a href="#数学公式推导" class="headerlink" title="数学公式推导"></a>数学公式推导</h2><h3 id="RRWP等价性的证明概要"><a href="#RRWP等价性的证明概要" class="headerlink" title="RRWP等价性的证明概要"></a>RRWP等价性的证明概要</h3><p>命题1的证明使用了表示距离的符号 $pk(j)$ ，表示在循环图G中任意两个相距 $j≤n$ 的节点之间的 $k$ 步游走概率。在线性图G’中，使用节点索引表示与中心节点的距离，$p’k(j)$ 表示从中心节点到距离为j的节点的k步游走概率。<br>证明分为两个主要部分：</p><ol><li>对于所有 $1 ≤ j &lt; n$ 和所有 $k ∈ N^*$ ，证明 $p’k(j) = pk(j)$ ，且 $p’k(n) = 1/2 pk(n)$</li><li>证明 $pk(n) = p’k(n,0)$ 对于所有 $k ≥ 1$ 成立，或者等价地，从先前结果有 $p’k(n,0) = 2p’k(n)$<h3 id="SPSE与循环计数的关系"><a href="#SPSE与循环计数的关系" class="headerlink" title="SPSE与循环计数的关系"></a>SPSE与循环计数的关系</h3><strong>命题3</strong>：令 $(i,j)$ 是图G中的两个相邻节点，即 $(i,j) ∈ E$ ，且 $S^k$ 是G的k步简单路径矩阵， <script type="math/tex">(S^k)_{ij} = m_k ∈ N</script> 。那么对于 $k ≥ 2$ ，G中恰好有 <script type="math/tex">m_k</script> 个长度为 $k+1$ 的循环，它们接受 <script type="math/tex">(i,j)</script> 作为边 。<br><strong>证明</strong>：<br>这个命题可以直接证明。每个包含边 $(i,j)$ 的长度为 $k+1$ 的循环是一个 $k+2$ 个节点的游走，形式为 $i, …j, i$ ，其中只有第一个节点被重复。将其限制到前 $k+1$ 个节点时，其本身是i和j之间长度为k的一条路径，因此增加了 <script type="math/tex">(S^k)_{ij}</script> 。反过来， <script type="math/tex">(S^k)_{ij}</script> 中计数的所有路径都可以通过边ji来完成，形成一个长度为k+1的循环，这证明了等式。<h3 id="SPSE的路径计数编码函数"><a href="#SPSE的路径计数编码函数" class="headerlink" title="SPSE的路径计数编码函数"></a>SPSE的路径计数编码函数</h3>SPSE使用对数函数组合来映射路径计数：<script type="math/tex; mode=display">f : x \mapsto \alpha g^n(x) + \beta</script>其中$g : x \mapsto \ln(1 + x)$，$\alpha$、$\beta$和$n$是超参数 。<br>归一化的路径计数 $f(S)$ 可以替代随机游走矩阵P作为图变换器模型的边编码输入，产生SPSE矩阵 $E^{SPSE}$ ，用于自注意力机制。</li></ol><h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><h2 id="方法概述"><a href="#方法概述" class="headerlink" title="方法概述"></a>方法概述</h2><p>Airale等人(2025)在论文中提出了一种称为简单路径结构编码(Simple Path Structural Encoding, SPSE)的新方法，用于图变换器的边结构编码。这种方法通过计算节点间不同长度的简单路径数量来编码图结构信息，为图结构提供了比随机游走概率(RRWP)更丰富的表示，特别是在捕获局部循环模式方面具有优势。</p><h2 id="数学基础与理论性质"><a href="#数学基础与理论性质" class="headerlink" title="数学基础与理论性质"></a>数学基础与理论性质</h2><p><img src="./SPSE/SPSE-SPSE.png" alt=""></p><h3 id="简单路径矩阵定义"><a href="#简单路径矩阵定义" class="headerlink" title="简单路径矩阵定义"></a>简单路径矩阵定义</h3><p>给定图 $G = (V, E, X)$，其中 $V$ 是节点集合，$E$ 是边集合，$X$ 是节点特征矩阵。对于 $k \in \mathbb{N}^{*}$，$k$-跳简单路径矩阵 <script type="math/tex">S^{k} \in \mathbb{N}^{|V| \times |V|}</script> 是一个矩阵，其中 $(S^{k})_{ij}$ 是从节点 $i$ 到节点 $j$ 的长度为 $k$ 的简单路径数量。<br>与随机游走矩阵 $P^{k} = (D^{-1}A)^k$（其中 $D$ 是度矩阵，$A$ 是邻接矩阵）不同，简单路径矩阵 $S^{k}$ 没有闭式解，计算它非常复杂。</p><h3 id="Proposition-3：SPSE与循环计数的关系"><a href="#Proposition-3：SPSE与循环计数的关系" class="headerlink" title="Proposition 3：SPSE与循环计数的关系"></a>Proposition 3：SPSE与循环计数的关系</h3><p>SPSE方法的核心理论基础是Proposition 3，它建立了简单路径计数和循环计数之间的直接联系：<br><strong>Proposition 3</strong>：令 <script type="math/tex">(i,j)</script> 是图 <script type="math/tex">G = (V,E)</script> 中的两个相邻节点，即 <script type="math/tex">(i,j) \in E</script>，<script type="math/tex">S_{k}</script> 是 <script type="math/tex">G</script> 的 <script type="math/tex">k</script>-跳简单路径矩阵，对于任意 <script type="math/tex">k \in \mathbb{N}^{*}</script>，使得 <script type="math/tex">(S_{k})_{ij} = m_{k} \in \mathbb{N}</script>。那么对于 <script type="math/tex">k \geq 2</script>，在 <script type="math/tex">G</script> 中恰好存在 <script type="math/tex">m_{k}</script> 个长度为 <script type="math/tex">k+1</script> 的循环，这些循环以 <script type="math/tex">(i,j)</script> 为一条边。<br><strong>证明</strong>：<br>这个命题可以通过直接观察来证明。每个长度为 <script type="math/tex">k+1</script> 且以边 <script type="math/tex">(i,j)</script> 为其中一条边的循环可以表示为 <script type="math/tex">i,j,i_1,i_2,...,i_{k-1},i</script> 的形式，其中 <script type="math/tex">j,i_1,i_2,...,i_{k-1}</script> 是节点，且所有节点都是唯一的（除了 <script type="math/tex">i</script>）。限制到该循环的前 <script type="math/tex">k+1</script> 个节点，它本身是一个从 <script type="math/tex">i</script> 到 <script type="math/tex">j</script> 的长度为 <script type="math/tex">k</script> 的简单路径，因此增加了 <script type="math/tex">(S_{k})_{ij}</script>。反过来，<script type="math/tex">(S_{k})_{ij}</script> 中计数的所有路径都可以通过添加边 <script type="math/tex">ji</script> 来完成一个长度为 <script type="math/tex">k+1</script> 的循环。这证明了等式。</p><h2 id="SPSE算法实现"><a href="#SPSE算法实现" class="headerlink" title="SPSE算法实现"></a>SPSE算法实现</h2><p>为了解决简单路径计数计算的复杂性，论文提出了一种高效的近似算法，基于有向无向图(DAG)分解的思想。</p><h3 id="算法1：所有节点对之间的路径计数（简化版）"><a href="#算法1：所有节点对之间的路径计数（简化版）" class="headerlink" title="算法1：所有节点对之间的路径计数（简化版）"></a>算法1：所有节点对之间的路径计数（简化版）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">1: Parameters: 根节点比例 R, 最大长度 K, 最大DFS深度 DDFS, 最大试验次数 N</span><br><span class="line">2: Input: 无向图 G = (V, E)</span><br><span class="line">3: Output: 路径计数矩阵 M ∈ ℕ^&#123;|V|×|V|×K&#125;</span><br><span class="line">4: M ← 0^&#123;|V|×|V|×K&#125; &#123;初始化计数矩阵&#125;</span><br><span class="line">5: NODES ← DRAWNODES(R, V) &#123;从V中选择R×|V|个节点&#125;</span><br><span class="line">6: for each v in NODES do</span><br><span class="line">7:     DAGS ← DAGDECOMPOSE(G, v, DDFS, N) &#123;获取以v开头的节点排列列表&#125;</span><br><span class="line">8:     for each DAG in DAGS do</span><br><span class="line">9:         M ← UPDATE(M, DAG) &#123;更新总路径计数&#125;</span><br><span class="line">10:    end for</span><br><span class="line">11: end for</span><br><span class="line">12: Return: M</span><br></pre></td></tr></table></figure><h4 id="算法1-的目标"><a href="#算法1-的目标" class="headerlink" title="算法1 的目标"></a>算法1 的目标</h4><p>这个算法的主要目的是<strong>计算图中所有节点对之间不同长度的简单路径数量</strong>，并存储在一个三维矩阵 <code>M</code> 中。由于直接计算所有路径的复杂度极高（指数级），算法采用了一种<strong>近似策略</strong>：只从部分根节点出发，通过有向无环图（DAG）分解来探索路径，从而高效估计路径计数。</p><h4 id="算法流程详解"><a href="#算法流程详解" class="headerlink" title="算法流程详解"></a>算法流程详解</h4><h5 id="1-初始化阶段"><a href="#1-初始化阶段" class="headerlink" title="1.初始化阶段"></a>1.初始化阶段</h5><ul><li><strong>输入</strong>：无向图 <code>G = (V, E)</code>（节点集合 <code>V</code>，边集合 <code>E</code>）  </li><li><strong>参数设置</strong>：  <ul><li><code>R</code>：根节点比例（比如 <code>R=0.1</code> 表示选择 10% 的节点作为根节点）  </li><li><code>K</code>：最大路径长度（只计算长度 ≤ <code>K</code> 的路径）  </li><li><code>DDFS</code>：最大 DFS 深度（控制深度优先搜索的深度）  </li><li><code>N</code>：试验次数（每个根节点尝试 <code>N</code> 次不同的路径探索）  </li></ul></li><li><strong>初始化计数矩阵</strong>：<br>创建一个三维矩阵 <code>M</code>，大小为 <code>|V| × |V| × K</code>，初始值全为 0。<br><code>M[i][j][k]</code> 将存储从节点 <code>i</code> 到节点 <code>j</code> 的长度为 <code>k</code> 的路径数量。<h5 id="2-选择根节点"><a href="#2-选择根节点" class="headerlink" title="2.选择根节点"></a>2.选择根节点</h5></li><li>从所有节点 <code>V</code> 中随机选择 <code>R × |V|</code> 个节点作为<strong>根节点</strong>（<code>NODES</code>）。  <ul><li>例如：如果图有 1000 个节点，<code>R=0.1</code>，则选择 100 个根节点。  </li><li>这样可以减少计算量，同时保持统计意义。<h5 id="3-遍历根节点"><a href="#3-遍历根节点" class="headerlink" title="3.遍历根节点"></a>3.遍历根节点</h5>对每个选中的根节点 <code>v</code>：  </li></ul></li><li><strong>调用 DAG 分解算法</strong>（算法2）：  <ul><li>以 <code>v</code> 为根节点，对图 <code>G</code> 进行 DAG 分解，得到多个节点排列列表 <code>DAGS</code>。  </li><li>每个 DAG 代表一种从 <code>v</code> 出发的路径探索顺序。  </li></ul></li><li><strong>遍历每个 DAG</strong>：  <ul><li>对每个 DAG，更新路径计数矩阵 <code>M</code>：  <ul><li>如果 DAG 中存在从 <code>i</code> 到 <code>j</code> 的长度为 <code>k</code> 的路径，则 <code>M[i][j][k] += 1</code>。  </li></ul></li><li>这样，<code>M</code> 会累加所有 DAG 中发现的路径。<h5 id="4-返回结果"><a href="#4-返回结果" class="headerlink" title="4.返回结果"></a>4.返回结果</h5></li></ul></li><li>最终返回路径计数矩阵 <code>M</code>，其中：  <ul><li><code>M[i][j][k]</code> 是从节点 <code>i</code> 到节点 <code>j</code> 的长度为 <code>k</code> 的简单路径的<strong>估计数量</strong>。  </li><li>由于是近似算法，结果可能略低于真实值（但论文证明下界估计是有效的）。<h4 id="关键设计思想"><a href="#关键设计思想" class="headerlink" title="关键设计思想"></a>关键设计思想</h4></li></ul></li></ul><ol><li><p><strong>近似计算</strong>：  </p><ul><li>不枚举所有可能的路径（计算量太大），而是从部分根节点出发，通过 DAG 分解探索路径。  </li><li>这样可以在可接受的时间内得到合理的估计。</li></ul></li><li><p><strong>DAG 分解的作用</strong>：  </p><ul><li>将无向图转化为有向无环图，避免重复计算和循环路径。  </li><li>结合 DFS 和 BFS（算法2），既能发现长路径，又能覆盖多条分支路径。</li></ul></li><li><p><strong>参数平衡</strong>：  </p><ul><li><code>R</code> 越大，估计越准确，但计算量越高。  </li><li><code>K</code> 越大，能捕获更长路径，但内存需求增加。  </li><li><code>DDFS</code> 和 <code>N</code> 控制探索的深度和多样性。<h4 id="举个具体例子"><a href="#举个具体例子" class="headerlink" title="举个具体例子"></a>举个具体例子</h4>假设图中有 4 个节点：<code>A, B, C, D</code>，边为 <code>A-B, B-C, C-D, A-D</code>。  </li></ul></li></ol><ul><li><strong>参数</strong>：<code>R=0.5, K=2, DDFS=1, N=2</code>  </li><li><strong>流程</strong>：  <ol><li>选择根节点（比如 <code>A</code> 和 <code>B</code>）。  </li><li>对根节点 <code>A</code>：  <ul><li>DAG 分解可能得到路径 <code>A→B→C</code> 和 <code>A→D</code>。  </li><li>更新 <code>M[A][B][1] += 1</code>，<code>M[A][C][2] += 1</code>，<code>M[A][D][1] += 1</code>。  </li></ul></li><li>对根节点 <code>B</code>：  <ul><li>DAG 分解可能得到路径 <code>B→A→D</code> 和 <code>B→C</code>。  </li><li>更新 <code>M[B][A][1] += 1</code>，<code>M[B][D][2] += 1</code>，<code>M[B][C][1] += 1</code>。  </li></ul></li><li>最终 <code>M</code> 中存储了所有节点对的路径计数估计。<h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4>算法1 通过<strong>随机选择根节点 + DAG 分解 + 路径计数更新</strong>，高效地估计了图中所有节点对之间的简单路径数量。虽然结果是近似的，但论文证明这种方法在计算效率和准确性之间取得了很好的平衡，特别适合用于图变换器的结构编码任务。</li></ol></li></ul><h3 id="算法2：DAG分解"><a href="#算法2：DAG分解" class="headerlink" title="算法2：DAG分解"></a>算法2：DAG分解</h3><p><img src="./SPSE/SPSE-Alg2.png" alt=""><br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">1: Parameters: 最大DFS深度 DDFS, 最大试验次数 N</span><br><span class="line">2: Input: 图 G = (V, E), 根节点 r, 直径 DMAX</span><br><span class="line">3: Output: 节点排列列表 Π</span><br><span class="line">4: 初始化 Π ← EmptyList</span><br><span class="line">5: for dDFS = 0 to DDFS do</span><br><span class="line">6:     for n = 1 to N do</span><br><span class="line">7:         初始化 π ← EmptyList</span><br><span class="line">8:         while π ≠ V do</span><br><span class="line">9:             for d = 1 to DMAX do</span><br><span class="line">10:                if d &lt; dDFS then</span><br><span class="line">11:                    π ← DFS(r, G, π) &#123;开始dDFS-1个DFS步骤&#125;</span><br><span class="line">12:                else if d = dDFS then</span><br><span class="line">13:                    π ← PARTIALBFS(r, G, π)</span><br><span class="line">14:                else</span><br><span class="line">15:                    π ← BFS(r, G, π) &#123;尽可能继续多个BFS步骤&#125;</span><br><span class="line">16:                end if</span><br><span class="line">17:            end for</span><br><span class="line">18:        end while</span><br><span class="line">19:        Π ← ADD(Π, π) &#123;将π添加到Π&#125;</span><br><span class="line">20:    end for</span><br><span class="line">21: end for</span><br><span class="line">22: Return: Π</span><br></pre></td></tr></table></figure><br>该算法通过结合深度优先搜索(DFS)和广度优先搜索(BFS)来探索不同路径。DFS能够发现长路径，但无法同时发现节点间的多条路径；BFS单独使用通常会遗漏长路径。因此，算法在达到最大DFS深度后切换到BFS，并在中间添加部分BFS步骤，以发现可能被标准DFS和BFS遗漏的路径。</p><h4 id="算法2-的目标"><a href="#算法2-的目标" class="headerlink" title="算法2 的目标"></a>算法2 的目标</h4><p>这个算法的主要目的是<strong>将无向图转化为有向无环图（DAG）</strong>，并生成一系列节点排列（<code>π</code>），用于后续的路径计数。通过结合深度优先搜索（DFS）和广度优先搜索（BFS），算法能够高效地探索不同长度的路径，同时避免重复计算和循环路径。</p><h4 id="算法流程详解-1"><a href="#算法流程详解-1" class="headerlink" title="算法流程详解"></a>算法流程详解</h4><h5 id="1-初始化阶段-1"><a href="#1-初始化阶段-1" class="headerlink" title="1.初始化阶段"></a>1.初始化阶段</h5><ul><li><strong>输入</strong>：  <ul><li>图 <code>G = (V, E)</code>（节点集合 <code>V</code>，边集合 <code>E</code>）  </li><li>根节点 <code>r</code>（路径探索的起点）  </li><li>直径 <code>DMAX</code>（图中最长路径的估计长度）  </li></ul></li><li><strong>参数设置</strong>：  <ul><li><code>DDFS</code>：最大 DFS 深度（控制深度优先搜索的深度）  </li><li><code>N</code>：试验次数（每个 <code>dDFS</code> 值尝试 <code>N</code> 次不同的路径探索）  </li></ul></li><li><strong>初始化输出列表</strong>：<br>创建一个空列表 <code>Π</code>，用于存储所有生成的节点排列。<h5 id="2-双层循环：遍历-DFS-深度和试验次数"><a href="#2-双层循环：遍历-DFS-深度和试验次数" class="headerlink" title="2.双层循环：遍历 DFS 深度和试验次数"></a>2.双层循环：遍历 DFS 深度和试验次数</h5></li><li><strong>外层循环</strong>（<code>dDFS</code> 从 0 到 <code>DDFS</code>）：  <ul><li>逐步增加 DFS 的深度，从纯 BFS（<code>dDFS=0</code>）到纯 DFS（<code>dDFS=DMAX</code>）。  </li><li>这样可以平衡 DFS 和 BFS 的探索策略。  </li></ul></li><li><strong>内层循环</strong>（<code>n</code> 从 1 到 <code>N</code>）：  <ul><li>对每个 <code>dDFS</code> 值，尝试 <code>N</code> 次不同的路径探索，增加多样性。<h5 id="3-路径探索：混合-DFS-和-BFS"><a href="#3-路径探索：混合-DFS-和-BFS" class="headerlink" title="3.路径探索：混合 DFS 和 BFS"></a>3.路径探索：混合 DFS 和 BFS</h5>对每次试验（<code>dDFS</code> 和 <code>n</code> 的组合）：  </li></ul></li><li><strong>初始化当前排列</strong>：<br>创建一个空列表 <code>π</code>，用于存储当前探索的节点顺序。  </li><li><strong>循环探索</strong>（直到所有节点 <code>V</code> 都被访问）：  <ul><li><strong>内层循环</strong>（<code>d</code> 从 1 到 <code>DMAX</code>）：  <ul><li>如果 <code>d &lt; dDFS</code>：  <ul><li>执行 <strong>DFS 步骤</strong>：从当前节点出发，尽可能深地探索路径。  </li><li>适合发现长路径，但可能遗漏分支路径。  </li></ul></li><li>如果 <code>d == dDFS</code>：  <ul><li>执行 <strong>部分 BFS 步骤</strong>：结合 DFS 和 BFS 的特点，平衡深度和广度。  </li></ul></li><li>如果 <code>d &gt; dDFS</code>：  <ul><li>执行 <strong>BFS 步骤</strong>：从当前节点出发，优先访问所有邻居节点。  </li><li>适合发现短路径和分支路径，但可能遗漏长路径。  </li></ul></li></ul></li><li><strong>更新排列</strong>：<br>将探索到的节点按顺序添加到 <code>π</code> 中。  </li><li><strong>检查是否完成</strong>：<br>如果 <code>π</code> 包含所有节点 <code>V</code>，则退出循环。<h5 id="4-存储结果"><a href="#4-存储结果" class="headerlink" title="4.存储结果"></a>4.存储结果</h5></li></ul></li><li>将当前排列 <code>π</code> 添加到输出列表 <code>Π</code> 中。  </li><li>这样，<code>Π</code> 会包含所有试验生成的节点排列，每个排列代表一种从根节点 <code>r</code> 出发的路径探索顺序。<h5 id="5-返回结果"><a href="#5-返回结果" class="headerlink" title="5.返回结果"></a>5.返回结果</h5></li><li>最终返回节点排列列表 <code>Π</code>，其中：  <ul><li>每个 <code>π</code> 是一个节点排列，表示从根节点 <code>r</code> 出发的一种路径探索顺序。  </li><li>这些排列将用于算法1中的路径计数更新。<h4 id="关键设计思想-1"><a href="#关键设计思想-1" class="headerlink" title="关键设计思想"></a>关键设计思想</h4></li></ul></li></ul><ol><li><p><strong>混合搜索策略</strong>：  </p><ul><li>DFS 能发现长路径，但可能遗漏分支路径。  </li><li>BFS 能发现短路径和分支路径，但可能遗漏长路径。</li><li>通过调整 <code>dDFS</code>，算法在 DFS 和 BFS 之间取得平衡。</li></ul></li><li><p><strong>参数控制</strong>：  </p><ul><li><code>DDFS</code> 控制最大 DFS 深度，影响路径探索的深度。  </li><li><code>N</code> 控制试验次数，增加路径探索的多样性。</li></ul></li><li><p><strong>避免循环路径</strong>：  </p><ul><li>通过 DAG 分解，将无向图转化为有向无环图，确保路径探索不会陷入循环。<h4 id="举个具体例子-1"><a href="#举个具体例子-1" class="headerlink" title="举个具体例子"></a>举个具体例子</h4>假设图中有 4 个节点：<code>A, B, C, D</code>，边为 <code>A-B, B-C, C-D, A-D</code>，根节点为 <code>A</code>。  </li></ul></li></ol><ul><li><strong>参数</strong>：<code>DDFS=1, N=2, DMAX=3</code>  </li><li><strong>流程</strong>：  <ol><li><strong><code>dDFS=0</code>（纯 BFS）</strong>：  <ul><li>第一次试验：<code>A → B → C → D</code>  </li><li>第二次试验：<code>A → D → C → B</code>  </li></ul></li><li><strong><code>dDFS=1</code>（混合 DFS 和 BFS）</strong>：  <ul><li>第一次试验：<code>A → B → C</code>（DFS），然后 <code>A → D</code>（BFS）  </li><li>第二次试验：<code>A → D → C</code>（DFS），然后 <code>A → B</code>（BFS）  </li></ul></li><li><strong><code>dDFS=2</code>（更深的 DFS）</strong>：  <ul><li>第一次试验：<code>A → B → C → D</code>  </li><li>第二次试验：<code>A → D → C → B</code>  </li></ul></li><li>最终 <code>Π</code> 包含 6 个节点排列，用于路径计数。<h4 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h4>算法2 通过<strong>混合 DFS 和 BFS 策略</strong>，高效地将无向图转化为 DAG，并生成多样化的节点排列。这些排列为算法1中的路径计数提供了丰富的探索顺序，确保了路径计数的准确性和多样性。</li></ol></li></ul><h3 id="算法复杂度"><a href="#算法复杂度" class="headerlink" title="算法复杂度"></a>算法复杂度</h3><p>SPSE算法的计算复杂度为 $O(KRDDFSN|V|^3)$，其中：</p><ul><li>$K$ 是最大路径长度</li><li>$R$ 是根节点比例</li><li>$DDFS$ 是最大DFS深度</li><li>$N$ 是试验次数</li><li>$|V|$ 是节点数量<br>虽然这比RRWP的计算成本高，但它只需要作为预处理步骤计算一次，并且远小于所有可能DAG分解的数量 $2^{|E|}$，突显了树分解方法的有效性。<h2 id="路径计数编码"><a href="#路径计数编码" class="headerlink" title="路径计数编码"></a>路径计数编码</h2>由于节点间的路径数量可能非常大，作者使用对数函数复合将路径计数映射到适合神经网络的值范围：<script type="math/tex; mode=display">f: x \rightarrow \alpha g^n(x) + \beta</script>其中 $g: x \rightarrow \ln(1 + x)$，$\alpha$、$\beta$ 和 $n$ 是需要调整的超参数。<br>这种映射函数 $f$ 能够有效处理大范围的路径计数值，将它们变换到适合神经网络处理的值范围。<h2 id="SPSE在图变换器中的应用"><a href="#SPSE在图变换器中的应用" class="headerlink" title="SPSE在图变换器中的应用"></a>SPSE在图变换器中的应用</h2>在图变换器中，SPSE矩阵 $E^{SP}$ 替换了原来的RRWP矩阵 $E^{RW}$。自注意力层的计算可以表示为：<script type="math/tex; mode=display">a_{ij} = \phi_1(W_Q x_i, W_K x_j, (E^{SP})_{ij})</script><script type="math/tex; mode=display">\alpha_{ij} = \frac{\exp(a_{ij})}{\sum_k \exp(a_{ik})}</script><script type="math/tex; mode=display">y_i = \sum_j \alpha_{ij} \phi_2(W_V x_j, (E^{SP})_{ij})</script>其中 $x_i$ 和 $x_j$ 分别是节点 $i$ 和 $j$ 的特征，$W_Q$、$W_K$ 和 $W_V$ 是查询、键和值矩阵，$y_i$ 是自注意力层的输出。<h2 id="实验结果"><a href="#实验结果" class="headerlink" title="实验结果"></a>实验结果</h2>论文在多个基准测试上验证了SPSE的有效性：</li></ul><ol><li><strong>循环计数合成实验</strong>：在包含循环的合成图上，SPSE展现比RRWP显著更高的循环计数准确率，验证了Proposition 3的有效性。</li><li><strong>真实世界基准测试</strong>：在分子数据集（ZINC, Peptides, PCQM4Mv2）、超像素数据集（MNIST, CIFAR10）和随机块模型（PATTERN, CLUSTER）上，SPSE在21/24的案例中提升了性能，特别是在分子数据集上表现尤为突出。</li><li><strong>超参数敏感性分析</strong>：研究表明不同数据集对超参数的敏感性各异。分子数据集主要受益于根节点比例 $R$ 的增加，而超像素数据集则从所有超参数的增加中受益。<h2 id="方法局限性"><a href="#方法局限性" class="headerlink" title="方法局限性"></a>方法局限性</h2>作者也指出了SPSE的局限性：</li><li><strong>高密度图挑战</strong>：在高度连接的图中，SPSE的改进有限，因为准确计数路径变得困难。</li><li><strong>路径枚举限制</strong>：由于内存限制，算法无法枚举所有路径，而是存储下界估计，可能导致某些情况的路径计数不准确。<br>总之，SPSE通过利用简单路径计数作为边编码，显著提升了图变换器在捕获结构信息方面的能力，特别是在处理分子图和长程依赖关系时表现出色，为图结构表示学习提供了一种更强大的方法。</li></ol><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="附录A-RRWP算法详解"><a href="#附录A-RRWP算法详解" class="headerlink" title="附录A RRWP算法详解"></a>附录A RRWP算法详解</h2><p>本文中对比的 <strong>RRWP（Relative Random Walk Probabilities，相对随机游走概率）算法</strong> 是一种用于 <strong>图Transformer（Graph Transformer）</strong> 的<strong>结构编码（structural encoding）方法</strong>。它的主要思想是通过<strong>随机游走（random walk）概率矩阵</strong>来表示节点之间的结构关系，从而为Transformer的自注意力层提供图结构信息。下面我用通俗的语言和图示来解释它的核心概念、计算方式以及局限性。</p><h3 id="一、RRWP的核心思想"><a href="#一、RRWP的核心思想" class="headerlink" title="一、RRWP的核心思想"></a>一、RRWP的核心思想</h3><p>在普通Transformer中，位置编码（positional encoding）告诉模型序列中单词的相对位置；<br>在<strong>图Transformer</strong>中，我们需要告诉模型<strong>节点之间的结构位置关系</strong>。<br>RRWP通过模拟“随机游走”来实现这种结构编码。</p><blockquote><p>“随机游走”可以理解为：从一个节点出发，随机选择一个邻居节点走一步，这样连续走K步，就得到一条随机路径。</p></blockquote><p>RRWP的关键是构造多个不同长度的随机游走概率矩阵：  </p><script type="math/tex; mode=display">P_k = (D^{-1}A)^k</script><p>其中：</p><ul><li>$A$：图的邻接矩阵（$A_{ij}=1$表示i与j之间有边）</li><li>$D$：节点的度矩阵（$D_{ii}$是节点i的度数）</li><li>$D^{-1}A$：一步随机游走的转移概率矩阵</li><li>$(D^{-1}A)^k$：从一个节点出发随机走k步，到达另一个节点的概率</li></ul><p>我们将这些概率矩阵按步数堆叠起来：  </p><script type="math/tex; mode=display">P = [P_1, P_2, \dots, P_K]</script><p>再通过一个浅层神经网络映射成高维特征：  </p><script type="math/tex; mode=display">E_{RW} = \phi_0(P)</script><p>最后在自注意力计算中，节点对$(i,j)$的注意力不仅取决于它们的特征，还受到对应的结构编码$E_{RW}(i,j)$影响：  </p><script type="math/tex; mode=display">a_{ij} = \phi_1(W_Qx_i, W_Kx_j, E_{RW}(i,j))</script><h3 id="二、RRWP的直观理解"><a href="#二、RRWP的直观理解" class="headerlink" title="二、RRWP的直观理解"></a>二、RRWP的直观理解</h3><p>可以将RRWP理解为：<br>“节点i到节点j之间，通过不同步数的随机游走，到达j的概率是多少？”<br>例如下图所示：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">   (A)</span><br><span class="line"> /  |  \</span><br><span class="line">B - C - D</span><br></pre></td></tr></table></figure></p><p>从A出发：</p><ul><li>一步到B、C、D的概率都为 1/3；</li><li>两步可能通过不同路径回到自己或走到别的节点；<br>于是我们能得到一系列概率，反映节点之间的结构“可达性”和“距离”。<h3 id="三、RRWP的优势"><a href="#三、RRWP的优势" class="headerlink" title="三、RRWP的优势"></a>三、RRWP的优势</h3></li><li><strong>封闭形式（closed form）计算简单</strong>：<br>  $(D^{-1}A)^k$ 可以直接矩阵乘法得到。</li><li><strong>包含多尺度结构信息</strong>：<br>  不同的k对应不同的“跳数”。</li><li><strong>可作为Transformer注意力的结构偏置（bias）</strong>，使模型知道哪些节点在图上更“近”或结构上更相关。<h3 id="四、RRWP的缺陷"><a href="#四、RRWP的缺陷" class="headerlink" title="四、RRWP的缺陷"></a>四、RRWP的缺陷</h3>论文中指出，RRWP <strong>无法区分某些结构不同的图</strong>，尤其是当局部拓扑差异较小时。<br>例如：</li><li>一个“环形图（cycle）”与一个“直线图（path）”在某些边上，RRWP会给出相同的随机游走概率；</li><li>这样模型就无法区分“环”和“链”。<br>论文给出的理论证明表明：</li></ul><blockquote><p>在偶数长度的环图与相应长度的路径图之间，存在节点对((i,j))，它们的RRWP编码完全相同。</p></blockquote><p>如图示例所示（论文Figure 1）：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Cycle graph (C4):  0 - 1 - 2 - 3 - 0</span><br><span class="line">Path graph (P5):   0 - 1 - 2 - 3 - 4</span><br></pre></td></tr></table></figure><br>RRWP对边(0,1)计算出的概率分布是一样的。</p><h3 id="五、RRWP与SPSE（本文方法）的区别示意图"><a href="#五、RRWP与SPSE（本文方法）的区别示意图" class="headerlink" title="五、RRWP与SPSE（本文方法）的区别示意图"></a>五、RRWP与SPSE（本文方法）的区别示意图</h3><div class="table-container"><table><thead><tr><th>对比项目</th><th>RRWP</th><th>SPSE（本文提出）</th></tr></thead><tbody><tr><td>编码依据</td><td>随机游走概率（可能重复节点）</td><td>简单路径计数（不重复节点）</td></tr><tr><td>能否区分环与链</td><td>❌ 不能</td><td>✅ 能</td></tr><tr><td>数学表达</td><td><script type="math/tex">(P_k = (D^{-1}A)^k)</script></td><td><script type="math/tex">(S_k(i,j))</script>：i到j之间长度为k的简单路径数</td></tr><tr><td>优点</td><td>快速、闭式解</td><td>结构信息更丰富，可捕捉局部循环</td></tr><tr><td>缺点</td><td>结构歧义（如偶环和路径）</td><td>计算复杂度高（需近似算法）</td></tr></tbody></table></div><h3 id="六、RRWP机制示意图"><a href="#六、RRWP机制示意图" class="headerlink" title="六、RRWP机制示意图"></a>六、RRWP机制示意图</h3><p>下面是一个直观示意（文本图）：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">      图结构：</span><br><span class="line">      1 -- 2 -- 3</span><br><span class="line">       \        /</span><br><span class="line">         \    /</span><br><span class="line">           4</span><br><span class="line">随机游走 (RRWP):</span><br><span class="line">  从1出发：</span><br><span class="line">   1步：到2或4的概率 0.5</span><br><span class="line">   2步：到3的概率 0.5 (经由2或4)</span><br><span class="line">   3步：又能回到1</span><br><span class="line"></span><br><span class="line">SPSE (Simple Path):</span><br><span class="line">  只计算不重复节点的路径：</span><br><span class="line">   1→2→3</span><br><span class="line">   1→4→3</span><br><span class="line">  两条简单路径长度为2</span><br></pre></td></tr></table></figure><br>RRWP会混淆，因为“1→2→1→4→3” 也算一种随机游走；<br>而SPSE会忽略这种带重复节点的路径，更准确地反映结构差异。</p><h3 id="七、总结"><a href="#七、总结" class="headerlink" title="七、总结"></a>七、总结</h3><p>RRWP是图Transformer的一种经典结构编码方案，核心优点是：</p><ul><li>简单高效；</li><li>能捕获全局结构信息。<br>但它的<strong>本质是概率</strong>而非结构计数，因此：</li><li>在局部结构（如环 vs 链）上存在模糊性；</li><li>不能显式捕捉循环、环状或支路模式。<br>SPSE正是为了解决这些问题提出的，用<strong>“简单路径计数”代替“随机游走概率”</strong>，使编码更能反映图的真实结构。<br>是否希望我给你画出一张<strong>RRWP与SPSE的对比示意图（含环形与路径示例）</strong>？<br>我可以用简洁的图示（类似论文Figure 1 + Figure 2）帮你更直观理解为什么RRWP无法区分环和链。</li></ul>]]></content>
    
    
    <summary type="html">Simple Path Structural Encoding for Graph Transformers</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Tokenizing/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/tags/Tokenizing/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：Primphormer</title>
    <link href="https://epsilonzyj.github.io/blog/posts/Primphormer.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/Primphormer.html</id>
    <published>2025-10-25T05:20:01.000Z</published>
    <updated>2026-06-12T05:48:31.706Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Mingzhen He, Ruikai Yang, Hanling Tian, Youmei Qiu, Xiaolin Huang</li><li>出处: ICML</li><li>日期: 2025</li><li>PDF: <a href="https://openreview.net/pdf?id=fMAihjfJij">https://openreview.net/pdf?id=fMAihjfJij</a></li></ul><hr><h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><h1 id="论文摘要翻译"><a href="#论文摘要翻译" class="headerlink" title="论文摘要翻译"></a>论文摘要翻译</h1><p>图Transformer(GT)已成为图表示学习的一种有前景的方法。尽管取得了成功，但由于GT需要进行成对(pair-wise)计算，其二阶复杂度限制了在大规模图上的可扩展性。为了从根本上减少GT的计算负担，我们提出了一种原始-对偶(primal-dual)框架，将图上的自注意力机制解释为对偶表示(dual representation)。基于这一框架，我们开发出了Primphormer，这是一种高效GT，利用具有线性复杂度的原始表示(primal representation)。理论分析表明，Primphormer既是序列和图上函数的通用近似器(universal approximator)，又保留了对非同构图(non-isomorphic graphs)的判别能力。在各种图基准上的广泛实验证明，Primphormer取得了具有竞争力的经验结果，同时保持了更友好的内存和计算成本。</p><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><p>本文主要解决了图Transformer(GTs)在实际应用中的计算效率问题。具体研究的问题可以概括为以下几个方面：</p><h2 id="核心问题"><a href="#核心问题" class="headerlink" title="核心问题"></a>核心问题</h2><p>传统图Transformer面临二次方(O(N²))的计算复杂度，这是由于其自注意力机制中需要计算每对节点之间的相似度，导致在大规模图上的可扩展性受到严重限制。</p><h2 id="现有解决方案的局限性"><a href="#现有解决方案的局限性" class="headerlink" title="现有解决方案的局限性"></a>现有解决方案的局限性</h2><p>作者分析了之前解决这一问题的方法及其不足：</p><ol><li><strong>线性注意力模型</strong>：如Performer和BigBird虽然减少了计算复杂度，但引入了额外的计算开销，成为中等规模图的主要计算瓶颈</li><li><strong>稀疏注意力机制</strong>：如Exphormer利用图结构的稀疏性，但当图变得更密集时，复杂度又退化为二次方</li><li><strong>序列特定方法</strong>：如Primal-Atten等方法虽然解决了序列数据中的表示问题，但不适用于图数据，因为图中的节点没有自然顺序属性<h2 id="理论挑战"><a href="#理论挑战" class="headerlink" title="理论挑战"></a>理论挑战</h2>关键的技术挑战是注意力分数本身具有非对称性(κ(x,y)≠κ(y,x))，这违反了Mercer条件，使得经典的原始-对偶讨论无法直接应用。虽然最近的研究已经在探索不对称核机器中的原始-对偶关系，但这些方法主要是在序列数据上设计的，不适用于图网络。<h2 id="创新切入点"><a href="#创新切入点" class="headerlink" title="创新切入点"></a>创新切入点</h2>为了从根本上增强GTs的可扩展性，作者寻求避免成对(pair-wise)计算的方法，从核机器中的原始-对偶关系获取灵感。他们注意到传统的支持向量机(Cortes &amp; Vapnik, 1995)、最小二乘支持向量机(Suykens &amp; Vandewalle, 1999)和核主成分分析(Mika et al., 1999)等模型展示了如何通过在原始空间中表示来避免二次复杂度。<h2 id="针对图数据的具体挑战"><a href="#针对图数据的具体挑战" class="headerlink" title="针对图数据的具体挑战"></a>针对图数据的具体挑战</h2>对于图数据应用原始-对偶关系时，作者遇到了一个基本问题：与不同节点对上的序列不同，图中的节点没有明确指定的顺序或排列，这使得讨论图上自注意力的原始-对偶关系成为一个开放性问题。<br>综上所述，本文主要研究问题是如何开发一种高效的图Transformer架构，它能够：</li><li>规避成对计算，将计算复杂度从二次方降低到线性</li><li>保留区分非同构图的表达能力</li><li>在保证性能的同时，提供更友好的内存和计算成本Primphormer的研究问题主要集中在解决图Transformer在处理大规模图时的计算效率限制。传统图Transformer(GTs)由于自注意力机制中的成对(pair-wise)计算，具有二次方(O(N²))的计算复杂度，这严重限制了它们在大规模图上的可扩展性。<h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2>He等人（2025） 提出的Primphormer旨在解决图Transformer（GTs）在大规模图应用中的计算效率问题。传统GTs的自注意力机制由于需要进行成对计算，导致计算复杂度为O(N²)，严重限制了其在大型图上的可扩展性。为解决这一问题，作者提出了一种基于原始表示（primal representation）的框架，通过原始-对偶关系将自注意力机制重构为线性复杂度模型，同时保持模型的表达能力。<h2 id="Primphormer核心方法"><a href="#Primphormer核心方法" class="headerlink" title="Primphormer核心方法"></a>Primphormer核心方法</h2><h3 id="1-问题与动机"><a href="#1-问题与动机" class="headerlink" title="1. 问题与动机"></a>1. 问题与动机</h3>图Transformer在处理长程依赖时表现出色，但其自注意力机制需要计算所有节点对之间的注意力分数：<script type="math/tex; mode=display">\kappa(x_i, x_j) = \sigma(\langle q(x_i), k(x_j) \rangle), \quad o_i = \sum_{j=1}^{N} v(x_j)\kappa(x_i, x_j)</script>其中$q(\cdot)$、$k(\cdot)$和$v(\cdot)$分别是查询(query)、键(key)和值(value)的投影函数，$\sigma$是激活函数。这种成对计算导致$O(N²)$复杂度，限制了实际应用。<h3 id="2-原始-对偶框架"><a href="#2-原始-对偶框架" class="headerlink" title="2. 原始-对偶框架"></a>2. 原始-对偶框架</h3>论文引入核机器中的原始-对偶关系，将自注意力机制解释为对偶表示，并通过空间转换实现原始表示：<h4 id="2-1-不对称核技巧"><a href="#2-1-不对称核技巧" class="headerlink" title="2.1 不对称核技巧"></a>2.1 不对称核技巧</h4>由于注意力分数$\kappa(x, y) \neq \kappa(y, x)$违反Mercer条件，作者采用定义2.1的不对称核技巧：<script type="math/tex; mode=display">\kappa(x, z) = \langle \phi_q(x), \phi_k(z) \rangle</script>其中$\phi_q$和$\phi_k$是查询和键的特征映射。<h4 id="2-2-虚拟节点与全局聚合"><a href="#2-2-虚拟节点与全局聚合" class="headerlink" title="2.2 虚拟节点与全局聚合"></a>2.2 虚拟节点与全局聚合</h4>为保持图的置换等变性，引入虚拟节点<script type="math/tex">f_X = F + BX_1^N 1_{N_s}^{\top}</script>，其中：</li></ol><ul><li>$B, F$是可学习权重</li><li>$X_1^N$是节点特征矩阵</li><li>$1_{N_s}$是长度为$N_s$的全1向量（$N_s \ll N$）<br>公式详细理解见<a href="#附录A">附录A</a>.<h4 id="2-3-优化问题构建"><a href="#2-3-优化问题构建" class="headerlink" title="2.3 优化问题构建"></a>2.3 优化问题构建</h4>基于原始表示定义优化问题：<script type="math/tex; mode=display">\min_{\Theta} J = \frac{1}{2}\sum_{i=1}^{N} e_i^\top \Lambda e_i + \frac{1}{2}\sum_{j=1}^{N} r_j^\top \Lambda r_j - \text{Tr}(W_e^\top W_r)</script>约束条件：<script type="math/tex; mode=display">e_i = f_X W_e \phi_q(x_i), \quad r_j = f_X W_r \phi_k(x_j)</script>其中$\Theta = {W_e, W_r, e_i, r_j}$是参数集，$\Lambda$是对角正则化矩阵，$W_e, W_r \in \mathbb{R}^{N_s \times p}$。<br>此优化问题本质是进行正则化，对于变分原理优化及KKT条件，见<a href="#附录D">附录D</a>.<h4 id="2-4-对偶问题与原始表示"><a href="#2-4-对偶问题与原始表示" class="headerlink" title="2.4 对偶问题与原始表示"></a>2.4 对偶问题与原始表示</h4>定理2.2的KKT条件给出对偶问题：<script type="math/tex; mode=display">K H_r F_X = H_e \Sigma, \quad K^\top H_e F_X = H_r \Sigma</script>通过优化推导出原始表示与对偶表示的关系：</li><li><strong>原始表示</strong>:<script type="math/tex; mode=display">e(x) = f_X W_e \phi_q(x), \quad r(x) = f_X W_r \phi_k(x)</script></li><li><strong>对偶表示</strong>:<script type="math/tex; mode=display">e(x) = \sum_{j=1}^{N} \tilde{h}_{rj} \kappa(x, x_j), \quad r(x) = \sum_{i=1}^{N} \tilde{h}_{ei} \kappa(x_i, x)</script>其中<script type="math/tex">\tilde{h}_{rj} = F_X h_{rj}</script>和<script type="math/tex">\tilde{h}_{ei} = F_X h_{ei}</script>形成数据自适应基。<br>对于优化问题的详细推导和理解见<a href="#附录B">附录B</a><h4 id="2-5-输出"><a href="#2-5-输出" class="headerlink" title="2.5 输出"></a>2.5 输出</h4>得到$e$（查询特征映射）和$r$（键特征映射）后，采用拼接进行输出：<script type="math/tex; mode=display">o = \mathbf{W}_c[\mathbf{e};\mathbf{r}]</script><h3 id="3-实现与架构"><a href="#3-实现与架构" class="headerlink" title="3. 实现与架构"></a>3. 实现与架构</h3><img src="./Primphormer/Primphormer.png" alt=""><br>Primphormer模型架构为$T_{Pri} = \text{FFN}(X + \text{Prim}(X))$，其中：</li></ul><ol><li>使用虚拟节点聚合全局图信息</li><li>通过最小化额外损失实现优化：<script type="math/tex; mode=display">\mathcal{L} = \mathcal{L}_{\text{task}} + \eta \sum_l J_l^2</script>$\eta$是正则化系数，$J_l$是第$l$层的原始目标损失<h2 id="理论贡献"><a href="#理论贡献" class="headerlink" title="理论贡献"></a>理论贡献</h2><h3 id="1-通用近似定理"><a href="#1-通用近似定理" class="headerlink" title="1. 通用近似定理"></a>1. 通用近似定理</h3></li></ol><ul><li><strong>定理3.2</strong>：Primphormer是置换等序列函数的通用近似器</li><li><strong>定理3.3</strong>：添加位置编码后，Primphormer可近似任意连续序列函数<h3 id="2-表达能力保留"><a href="#2-表达能力保留" class="headerlink" title="2. 表达能力保留"></a>2. 表达能力保留</h3></li><li><strong>定理3.4</strong>：Primphormer能模拟1-Weisfeiler-Lehman(1-WL)测试，证明其与标准Transformer区分非同构图的能力相当：<script type="math/tex; mode=display">C_{1,t}(v) = C_{1,t}(w) \iff X^{(t)}_{\text{Pri}}(v) = X^{(t)}_{\text{Pri}}(w)</script><h2 id="实验结果"><a href="#实验结果" class="headerlink" title="实验结果"></a>实验结果</h2>Primphormer在多个基准数据集上验证了其高效性与有效性：</li></ul><ol><li><strong>LRGB数据集</strong>（表1）：在5个数据集中，Primphormer在4个上超越基线</li><li><strong>GNN基准</strong>（表2）：在MNIST上达到98.56%准确率，优于其他GT模型</li><li><strong>效率对比</strong>（表4）：计算复杂度从O(N²)降至O(Nps)，内存占用显著降低，例如在MalNet-Tiny上仅需2.86GB（远低于Exphormer的10.38GB）<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2>Primphormer通过以下创新解决了GTs的计算效率问题：</li><li>引入原始-对偶框架，将二次复杂度转换为线性复杂度</li><li>设计虚拟节点机制保持图的置换等变性</li><li>理论证明其通用近似能力和表达能力</li><li>实验验证在保持性能的同时大幅降低计算和内存开销<br>这一方法为图Transformer在大规模图上的应用提供了新思路，未来可进一步探索边特征集成和高效微调方法。</li></ol><hr><p>参考：<br>He, M., Yang, R., Tian, H., Qiu, Y., &amp; Huang, X. (2025). Primphormer: Efficient Graph Transformers with Primal Representations. <em>Proceedings of the 42nd International Conference on Machine Learning</em>.</p><hr><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="附录A"><a href="#附录A" class="headerlink" title="附录A"></a>附录A</h2><p>在论文的Primphormer模型中，虚拟节点全局聚合机制是通过<strong>平均池化后经过可学习的线性层</strong>实现的，具体分析如下：</p><h3 id="虚拟节点的实现方式"><a href="#虚拟节点的实现方式" class="headerlink" title="虚拟节点的实现方式"></a>虚拟节点的实现方式</h3><p>从论文第2.3节的定义可以看到，虚拟节点 <script type="math/tex">f_X</script> 被定义为： <script type="math/tex">f_X := F + BX_1^N 1_{N_s}^{\top}</script> 其中：</p><ul><li>$F \in \mathbb{R}^{s \times N_s}$ 和 $B \in \mathbb{R}^{s \times d}$ 是可学习权重</li><li>$X_1^N \in \mathbb{R}^{d \times N}$ 是节点特征矩阵</li><li>$1_{N_s}$ 是长度为 $N_s$ 的全1向量<h3 id="数学表达"><a href="#数学表达" class="headerlink" title="数学表达"></a>数学表达</h3>结合理论和代码，虚拟节点的聚合过程可以表示为： $f_X^{(l+1)} = \text{FFN}(\text{global_mean_pool}(h^{(l)})) + f_X^{(l)}$ 其中：</li><li>global_mean_pool() 是平均池化操作</li><li>FFN() 代表一个可学习的线性层</li><li>$f_X^{(l)}$ 是第 $l$ 层的虚拟节点表示</li></ul><h2 id="附录B"><a href="#附录B" class="headerlink" title="附录B"></a>附录B</h2><p>本文提出的优化问题在公式(2.5)中定义如下：</p><script type="math/tex; mode=display">J = \frac{1}{2}\sum_{i=1}^N e_i^\top \Lambda e_i + \frac{1}{2}\sum_{j=1}^N r_j^\top \Lambda r_j - \text{Tr}(W_e^\top W_r)</script><p>约束条件为：</p><script type="math/tex; mode=display">e_i = f_X W_e \phi_q(x_i), \quad i \in [N]</script><script type="math/tex; mode=display">r_j = f_X W_r \phi_k(x_j), \quad j \in [N]</script><h3 id="为什么公式这样构建"><a href="#为什么公式这样构建" class="headerlink" title="为什么公式这样构建"></a>为什么公式这样构建</h3><p>这个优化问题的构建基于以下几个关键原因：</p><ol><li><strong>处理自注意力的不对称性</strong>：传统图Transformer中的自注意力机制是$O(N²)$复杂度的且存在不对称性，违反了Mercer条件。该优化问题通过引入变分原理，使Primphormer能够处理非对称核。</li><li><strong>保持置换等变性</strong>：通过虚拟节点$f_X$聚合全局信息，保证图神经网络所需的置换等变性，这对于无序的图数据至关重要。</li><li><strong>降低计算复杂度</strong>：通过在原始空间中进行优化，避免了传统自注意力机制中需要计算所有节点对的问题。</li><li><strong>形成数据自适应基</strong>：通过将全局信息整合到投影权重中，而非特征映射中，构建双空间中的数据自适应基，增强了模型灵活性。（因此使用参数矩阵构建，而不是采用全局信息与特征输出相加）</li></ol><h3 id="各项含义"><a href="#各项含义" class="headerlink" title="各项含义"></a>各项含义</h3><p>目标函数$J$中的各项含义如下：</p><ol><li><strong>正则化项</strong>：<script type="math/tex">\frac{1}{2}\sum_{i=1}^N e_i^\top \Lambda e_i + \frac{1}{2}\sum_{j=1}^N r_j^\top \Lambda r_j</script><ul><li>这两项是对投影得分$e_i$和$r_j$的正则化，通过正定矩阵$\Lambda$防止过拟合</li><li>$\Lambda$是对角正则化系数矩阵，控制不同维度上的正则化强度</li></ul></li><li><strong>迹项</strong>：$-\text{Tr}(W_e^\top W_r)$<ul><li>这一项鼓励$W_e$和$W_r$之间的一致性</li><li>在KKT条件下，当满足优化条件时，与前两项达到平衡</li></ul></li><li><strong>约束条件中的参数</strong>：<ul><li>$W_e, W_r \in \mathbb{R}^{N_s \times p}$：可学习权重矩阵，其中$N_s \ll N$</li><li>$e_i, r_j \in \mathbb{R}^s$：投影得分</li><li>$\phi_q(\cdot), \phi_k(\cdot) : \mathbb{R}^d \to \mathbb{R}^p$：查询和键的特征映射</li><li><script type="math/tex">f_X\in\mathbb{R}^{s\times N_s}</script> ：数据依赖投影，定义为<script type="math/tex">f_X := F + BX_1^N 1_{N_s}^\top</script>，作为虚拟节点聚合全局信息</li></ul></li></ol><h3 id="数学推导"><a href="#数学推导" class="headerlink" title="数学推导"></a>数学推导</h3><p>数学推导过程主要包括以下步骤：</p><h4 id="1-拉格朗日函数"><a href="#1-拉格朗日函数" class="headerlink" title="1. 拉格朗日函数"></a>1. 拉格朗日函数</h4><p>首先构建拉格朗日函数：</p><script type="math/tex; mode=display">\mathcal{L}(W_e, W_r, e_i, r_j, h_e^i, h_r^j) = J - \sum_{i=1}^N h_e^{i\top}(e_i - f_X W_e \phi_q(x_i)) - \sum_{j=1}^N h_r^{j\top}(r_j - f_X W_r \phi_k(x_j))</script><p>其中$h_e^i, h_r^j \in \mathbb{R}^s$是与投影得分$e_i$和$r_j$相关的对偶变量向量。</p><h4 id="2-KKT条件"><a href="#2-KKT条件" class="headerlink" title="2. KKT条件"></a>2. KKT条件</h4><p>通过对拉格朗日函数求偏导，得到KKT条件：</p><ul><li><script type="math/tex; mode=display">\frac{\partial \mathcal{L}}{\partial W_e} = 0 \Rightarrow W_r = \sum_{i=1}^N f_X^\top h_e^i \phi_q(x_i)^\top</script></li><li><script type="math/tex; mode=display">\frac{\partial \mathcal{L}}{\partial W_r} = 0 \Rightarrow W_e = \sum_{j=1}^N f_X^\top h_r^j \phi_k(x_j)^\top</script></li><li><script type="math/tex; mode=display">\frac{\partial \mathcal{L}}{\partial e_i} = 0 \Rightarrow \Lambda e_i = h_e^i, \quad i \in [N]</script></li><li><script type="math/tex; mode=display">\frac{\partial \mathcal{L}}{\partial r_j} = 0 \Rightarrow \Lambda r_j = h_r^j, \quad j \in [N]</script></li><li><script type="math/tex; mode=display">\frac{\partial \mathcal{L}}{\partial h_e^i} = 0 \Rightarrow e_i = f_X W_e \phi_q(x_i), \quad i \in [N]</script></li><li><script type="math/tex; mode=display">\frac{\partial \mathcal{L}}{\partial h_r^j} = 0 \Rightarrow r_j = f_X W_r \phi_k(x_j), \quad j \in [N]</script></li></ul><h4 id="3-对偶问题"><a href="#3-对偶问题" class="headerlink" title="3. 对偶问题"></a>3. 对偶问题</h4><p>通过消除原始变量$W_e$和$W_r$，可以得到以下广义特征值问题：</p><script type="math/tex; mode=display">KH_r F_X = H_e \Sigma</script><script type="math/tex; mode=display">K^\top H_e F_X = H_r \Sigma</script><p>其中<script type="math/tex">F_X := f_X f_X^\top \in \mathbb{S}^{s \times s}_+</script>是自相关矩阵，<script type="math/tex">H_e := [h_e^1, \ldots, h_e^N]^\top \in \mathbb{R}^{N \times s}</script>和<script type="math/tex">H_r := [h_r^1, \ldots, h_r^N]^\top \in \mathbb{R}^{N \times s}</script>是对偶变量，<script type="math/tex">\Sigma := \Lambda^{-1}</script>，<script type="math/tex">K</script>是由注意力分数诱导的核矩阵。</p><h4 id="4-原始表示与对偶表示"><a href="#4-原始表示与对偶表示" class="headerlink" title="4. 原始表示与对偶表示"></a>4. 原始表示与对偶表示</h4><p>基于KKT条件，论文推导出自注意力的原始表示和对偶表示：<br><strong>原始表示</strong>：</p><script type="math/tex; mode=display">e(x) = f_X W_e \phi_q(x)</script><script type="math/tex; mode=display">r(x) = f_X W_r \phi_k(x)</script><p><strong>对偶表示</strong>：</p><script type="math/tex; mode=display">e(x) = \sum_{j=1}^N \tilde{h}_r^j \kappa(x, x_j)</script><script type="math/tex; mode=display">r(x) = \sum_{i=1}^N \tilde{h}_e^i \kappa(x_i, x)</script><p>其中$F_X := f_X f_X^\top$包含全局信息，$\tilde{h}_r^j := F_X h_r^j$和$\tilde{h}_e^i := F_X h_e^i$是数据自适应基，$\kappa(x_i, x_j) := \langle \phi_q(x_i), \phi_k(x_j) \rangle$是核函数。</p><h4 id="5-零值目标引理"><a href="#5-零值目标引理" class="headerlink" title="5. 零值目标引理"></a>5. 零值目标引理</h4><p>论文证明了在对偶空间中满足KKT条件的解会导致原始空间中的目标值为零（引理2.3）：</p><script type="math/tex; mode=display">J = \frac{1}{2}\text{Tr}(H_e \Sigma H_e^\top) + \frac{1}{2}\text{Tr}(H_r \Sigma H_r^\top) - \text{Tr}(K H_r F_X H_e^\top) = 0</script><p>这一结果为后续实现提供了理论基础，使得Primphormer可以通过简单地将原始目标值作为额外损失项来优化，而不需要直接求解复杂的对偶问题。<br>通过这种优化设计和推导，Primphormer能够高效地实现图Transformer，避免O(N²)的复杂度，同时保持置换等变性和表达能力。</p><h2 id="附录C"><a href="#附录C" class="headerlink" title="附录C"></a>附录C</h2><p>根据Primphormer论文中的定义，满足置换等变性后，节点重新排序不影响输出值，只是输出的排列顺序也会相应变化。</p><h3 id="置换等变性的正式定义"><a href="#置换等变性的正式定义" class="headerlink" title="置换等变性的正式定义"></a>置换等变性的正式定义</h3><p>论文中给出了置换等变性的明确定义（定义3.1）：</p><blockquote><p>一个连续的序列到序列函数 $f: X^N \to Y^N$ 如果对于每个排列 $\pi: [N] \to [N]$ 满足以下条件，则称其对序列中元素的顺序具有等变性：</p><script type="math/tex; mode=display">f([x_{\pi(1)}, \ldots, x_{\pi(N)}]) = [f_{\pi(1)}(X), \ldots, f_{\pi(N)}(X)]</script><p>其中 $X = [x_1, \ldots, x_N]$ 是包含 $N$ 个令牌的序列。</p></blockquote><h3 id="对图神经网络的重要性"><a href="#对图神经网络的重要性" class="headerlink" title="对图神经网络的重要性"></a>对图神经网络的重要性</h3><p>论文特别强调了图数据中置换等变性的重要性：</p><blockquote><p>“First, unlike sequences, nodes in a graph are unordered, meaning the sampling operation may break permutation equivariance, i.e., any permutation of the nodes could result in a different output.” </p></blockquote><p>这是因为图中的节点本质上是无序的(unlike sequences)，与序列数据不同。如果图神经网络不具有置换等变性，那么当对节点进行不同的排序时，可能会得到不一致的输出结果，这与图结构的基本特性相违背。</p><h3 id="Primphormer如何保持置换等变性"><a href="#Primphormer如何保持置换等变性" class="headerlink" title="Primphormer如何保持置换等变性"></a>Primphormer如何保持置换等变性</h3><p>论文指出，Primphormer通过引入虚拟节点(virtual node)机制来保持置换等变性：</p><blockquote><p>“We collect graph information by introducing a virtual node (Cai et al., 2023) that aggregates global information.”<br>“The global aggregation <script type="math/tex">f_X</script> preserves permutation equivariance.” </p></blockquote><p>这种全局聚合方式 <script type="math/tex">f_X := F + BX_1^N 1^⊤_{N_s}</script> 本质上是一个对称操作，对节点排列保持不变，从而确保了模型对节点重排的不变性。</p><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>“满足置换等变性后节点重新排序不影响输出”的理解是正确的。更准确地说，满足置换等变性意味着：</p><ol><li>当输入序列中的元素进行重新排列时，输出序列也会以相同的方式进行排列</li><li>输出序列中元素本身的值不会发生改变</li><li>对于图神经网络，这意味着无论图中节点的顺序如何变化，只要图的结构（边和节点特征）保持不变，模型的处理结果就会保持一致<br>这一性质对于图神经网络至关重要，因为它尊重了图作为无序数据结构的基本特性。</li></ol><h2 id="附录D"><a href="#附录D" class="headerlink" title="附录D"></a>附录D</h2><p>KKT条件（Karush-Kuhn-Tucker条件）是优化理论中的一组重要条件，用于解决约束优化问题。这些条件是由Karush (1939)、Kuhn和Tucker (1951)提出的，是非线性规划领域中求解约束优化问题最优解的必要条件。</p><h3 id="在Primphormer论文中的应用"><a href="#在Primphormer论文中的应用" class="headerlink" title="在Primphormer论文中的应用"></a>在Primphormer论文中的应用</h3><p>在He等(2025)的论文中，KKT条件被用来建立优化问题(2.5)的对偶问题，这是Primphormer理论基础的关键部分。论文中定义了原始优化问题的拉格朗日函数：</p><script type="math/tex; mode=display">\mathcal{L}(W_e, W_r, e_i, r_j, h_{ei}, h_{rj}) = \frac{1}{2}\sum_{i=1}^{N} e_i^T \Lambda e_i + \frac{1}{2}\sum_{j=1}^{N} r_j^T \Lambda r_j - \text{Tr}(W_e^T W_r) - \sum_{i=1}^{N} h_{ei}^T (e_i - f_X W_e \phi_q(x_i)) - \sum_{j=1}^{N} h_{rj}^T (r_j - f_X W_r \phi_k(x_j))</script><p>通过求拉格朗日函数的偏导数并设为零，论文得到了KKT条件：</p><script type="math/tex; mode=display">\begin{cases}\frac{\partial\mathcal{L}}{\partial W_e} = 0 &\Rightarrow W_r = \sum_{i=1}^{N} f_X^T h_{ei} \phi_q(x_i)^T \\\frac{\partial\mathcal{L}}{\partial W_r} = 0 &\Rightarrow W_e = \sum_{j=1}^{N} f_X^T h_{rj} \phi_k(x_j)^T \\\frac{\partial\mathcal{L}}{\partial e_i} = 0 &\Rightarrow \Lambda e_i = h_{ei}, \quad i \in [N] \\\frac{\partial\mathcal{L}}{\partial r_j} = 0 &\Rightarrow \Lambda r_j = h_{rj}, \quad j \in [N] \\\frac{\partial\mathcal{L}}{\partial h_{ei}} = 0 &\Rightarrow e_i = f_X W_e \phi_q(x_i), \quad i \in [N] \\\frac{\partial\mathcal{L}}{\partial h_{rj}} = 0 &\Rightarrow r_j = f_X W_r \phi_k(x_j), \quad j \in [N]\end{cases}</script><h3 id="KKT条件的主要内容"><a href="#KKT条件的主要内容" class="headerlink" title="KKT条件的主要内容"></a>KKT条件的主要内容</h3><p>KKT条件通常包括：</p><ol><li><strong>原始可行性条件</strong>：满足原始问题的约束条件</li><li><strong>对偶可行性条件</strong>：满足对偶变量的符号约束（对于不等式约束）</li><li><strong>互补松弛条件</strong>：原始约束和对应的对偶变量的乘积为零</li><li><strong>梯度条件</strong>：原始问题和对偶问题的梯度条件<h3 id="在Primphormer中的意义"><a href="#在Primphormer中的意义" class="headerlink" title="在Primphormer中的意义"></a>在Primphormer中的意义</h3><script type="math/tex; mode=display">K H_r F_X = H_e \Sigma, \quad K^T H_e F_X = H_r \Sigma</script>其中Σ = Λ⁻¹，He和Hr是对偶变量，K是由注意力分数形成的矩阵。这种原始-对偶关系证明了Primphormer的自注意力机制可以通过原始表示有效实现，同时避免了二次复杂度计算。<br>KKT条件在Primphormer中不仅为理论证明提供了基础，还在实际实现中起到了指导作用（引理2.3表明，当达到KKT点时，原始空间的目标函数值为零）。</li></ol><h2 id="附录E"><a href="#附录E" class="headerlink" title="附录E"></a>附录E</h2><h3 id="论文中提出的定理"><a href="#论文中提出的定理" class="headerlink" title="论文中提出的定理"></a>论文中提出的定理</h3><h4 id="定理-2-2-Duality"><a href="#定理-2-2-Duality" class="headerlink" title="定理 2.2 (Duality)"></a>定理 2.2 (Duality)</h4><p>He 等 (2025) 提出的这个定理描述了优化问题 (2.5) 在 KKT 条件下的对偶问题，即：</p><script type="math/tex; mode=display">KH_r F_X = H_e \Sigma, \quad K^T H_e F_X = H_r \Sigma</script><p>其中 $\Sigma = \Lambda^{-1}$，$H_e$ 和 $H_r$ 是对偶变量，$K$ 是由注意力分数诱导的矩阵。该定理建立了原始空间（Primal）与对偶空间（Dual）之间的关系，证明了 Primphormer 可以通过原始表示实现，从而避免二次复杂度计算。</p><h4 id="引理-2-3-Zero-valued-objective-with-stationary-solutions"><a href="#引理-2-3-Zero-valued-objective-with-stationary-solutions" class="headerlink" title="引理 2.3 (Zero-valued objective with stationary solutions)"></a>引理 2.3 (Zero-valued objective with stationary solutions)</h4><p>该引理指出，在对偶空间 (2.6) 中 $H_e, H_r, \Sigma$ 的解会导致原始空间 (2.5) 中目标值 $J$ 为零。这个结果支持了 Primphormer 的实现方式：通过最小化额外的目标损失函数有效逼近 KKT 点。</p><h5 id="定理2-3的证明"><a href="#定理2-3的证明" class="headerlink" title="定理2.3的证明"></a>定理2.3的证明</h5><p>定理2.3（引理2.3）表明：对偶空间(2.6)中He、Hr、Σ的解会导致原始空间(2.5)中目标值J为零。</p><h6 id="证明过程"><a href="#证明过程" class="headerlink" title="证明过程"></a>证明过程</h6><p>根据KKT条件（C2）和优化问题(2.6)，目标函数在平稳点上的值为：</p><script type="math/tex; mode=display">J = (1/2)∑_{i=1}^N e_i^T Λe_i + (1/2)∑_{j=1}^N r_j^T Λr_j - Tr(W_e^T W_r)</script><p>根据KKT条件中的 <script type="math/tex">∂L/∂e_i = 0 ⇒ Λe_i = h_{ei}</script> 和 <script type="math/tex">∂L/∂r_j = 0 ⇒ Λr_j = h_{rj}</script> ，我们有：</p><script type="math/tex; mode=display">J = (1/2)∑_{i=1}^N (h_{ei}^T Λ^{-1} h_{ei}) + (1/2)∑_{j=1}^N (h_{rj}^T Λ^{-1} h_{rj}) - Tr(W_e^T W_r)</script><p>令 $Σ = Λ^{-1}$ ，则上式可写为：</p><script type="math/tex; mode=display">J = (1/2)∑_{i=1}^N h_{ei}^T Σ h_{ei} + (1/2)∑_{j=1}^N h_{rj}^T Σ h_{rj} - Tr(W_e^T W_r)</script><p>根据KKT条件中的 <script type="math/tex">∂L/∂W_e = 0 ⇒ W_r = ∑_{j=1}^N f_X^T h_{rj} φ_k(x_j)^T</script> 和 <script type="math/tex">∂L/∂W_r = 0 ⇒ W_e = ∑_{i=1}^N f_X^T h_{ei} φ_q(x_i)^T</script> ，我们可以将迹项展开：</p><script type="math/tex; mode=display">J = (1/2) Tr(H_e Σ H_e^T) + (1/2) Tr(H_r Σ H_r^T) - Tr[∑_{i,j} φ_k(x_j) h_{rj}^T f_X f_X^T h_{ei} φ_q(x_i)^T]</script><p>其中 <script type="math/tex">H_e := [h_{e1}, ..., h_{eN}]^T ∈ R^{N×s}</script>，<script type="math/tex">H_r := [h_{r1}, ..., h_{rN}]^T ∈ R^{N×s}</script>。<br>定义注意力矩阵 $K$，其中 $K_{ij} = ⟨φ_q(x_i), φ_k(x_j)⟩ = φ_q(x_i)^T φ_k(x_j)$，则：</p><script type="math/tex; mode=display">J = (1/2) Tr(H_e Σ H_e^T) + (1/2) Tr(H_r Σ H_r^T) - Tr[∑_{i,j} K_{ij} h_{rj}^T F_X h_{ei}]</script><p>其中 $F_X = f_X f_X^T$ 。由于 $KH_r F_X = H_e Σ$ 和 $K^T H_e F_X = H_r Σ$ ，我们可以将 $J$ 重写为：</p><script type="math/tex; mode=display">J = (1/2) Tr(KH_r F_X H_e^T) + (1/2) Tr(K^T H_e F_X H_r^T) - Tr(KH_r F_X H_e^T)</script><p>简化后：</p><script type="math/tex; mode=display">J = (1/2) Tr(K^T H_e F_X H_r^T) - (1/2) Tr(KH_r F_X H_e^T)= (1/2) Tr[H_e F_X H_r^T K^T - KH_r F_X H_e^T]= (1/2) Tr[M - M^T]  其中 M = H_e F_X H_r^T K^T= 0</script><p>对于任何矩阵 $M$ ，都有 $Tr[M - M^T] = 0$ ，因为 $M - M^T$ 是斜对称矩阵，其迹为零。</p><h5 id="结论-1"><a href="#结论-1" class="headerlink" title="结论"></a>结论</h5><p>因此，我们证明了：在对偶空间(2.6)中 $H_e$、$H_r$ 、$Σ$ 的解会导致原始空间(2.5)中目标值 $J$ 为零。这个结果支持了Primphormer的实现方式：通过最小化额外的目标损失函数有效逼近KKT点。</p><h4 id="定理-3-2-Universal-approximation-for-permutation-equivariant-sequence-to-sequence-functions"><a href="#定理-3-2-Universal-approximation-for-permutation-equivariant-sequence-to-sequence-functions" class="headerlink" title="定理 3.2 (Universal approximation for permutation equivariant sequence-to-sequence functions)"></a>定理 3.2 (Universal approximation for permutation equivariant sequence-to-sequence functions)</h4><p>该定理证明了 Primphormer 作为置换等变序列函数的通用逼近器：<br>对于任意函数 <script type="math/tex">f \in \mathcal{FE}_q^N(\mathcal{X}, \mathcal{Y})</script> 和每个 <script type="math/tex">\varepsilon > 0</script>，存在一个 Primphormer <script type="math/tex">T_{Pri}</script>，使得</p><script type="math/tex; mode=display">\sup_{X \in \mathcal{X}^N} \|f(X) - T_{Pri}(X)\|_\infty < \varepsilon</script><h5 id="证明"><a href="#证明" class="headerlink" title="证明"></a>证明</h5><p>我们将证明分为两个部分：首先用Sumformer逼近f，然后用Primphormer逼近Sumformer。证明基于三角不等式：</p><script type="math/tex; mode=display">\sup_{X\in X^N} \|f (X) - T_{Pri}(X)\|_\infty \leq \sup_{X\in X^N} \|f (X) - S(X)\|_\infty + \sup_{X\in X^N} \|S(X) - T_{Pri}(X)\|_\infty</script><h6 id="第一步：用Sumformer逼近f"><a href="#第一步：用Sumformer逼近f" class="headerlink" title="第一步：用Sumformer逼近f"></a>第一步：用Sumformer逼近f</h6><p>根据引理C.2（Alberti等, 2023）：</p><blockquote><p>引理C.2：对于每个函数 $f ∈ Fe^N_q(X, Y)$ 和每个 $ε &gt; 0$ ，存在一个Sumformer S，使得</p><script type="math/tex; mode=display">\sup_{X\in X^N} \|f (X) - S(X)\|_\infty < \varepsilon</script></blockquote><p>我们选择一个Sumformer S，使得<script type="math/tex">\sup_{X\in X^N} \|f (X) - S(X)\|_\infty < \varepsilon/2</script>。Sumformer的定义如下：</p><blockquote><p>定义C.1（Sumformer）：设d’ ∈ N且有两个函数 <script type="math/tex">ξ : X → R^{d'}</script> ，<script type="math/tex">ψ : X × R^{d'} → Y</script> 。Sumformer是一个序列到序列函数 <script type="math/tex">S : X^N → Y^N</script> ，首先计算：</p><script type="math/tex; mode=display">\Xi := \sum_{k=1}^N \xi(x_k)</script><p>然后，$S([x_1, …, x_N]) := [ψ(x_1, Ξ), …, ψ(x_N, Ξ)]$ 。</p></blockquote><h6 id="第二步：用Primphormer逼近Sumformer"><a href="#第二步：用Primphormer逼近Sumformer" class="headerlink" title="第二步：用Primphormer逼近Sumformer"></a>第二步：用Primphormer逼近Sumformer</h6><p>现在我们构造一个Primphormer $T_{Pri}$ 来近似Sumformer S：</p><ol><li>首先将输入X通过前馈层变换：<script type="math/tex; mode=display">[x_1 ... x_N; x_1 ... x_N] \in R^{2d \times N}</script></li><li>构造一个两层前馈网络，在前N个分量上执行恒等变换，同时近似函数ξ：<script type="math/tex; mode=display">[x_1 ... x_N; \xi(x_1) ... \xi(x_N)] \in R^{(d+d') \times N}</script></li><li>添加线性映射产生输出：<script type="math/tex; mode=display">[1 ... 1; x_1 ... x_N; \xi(x_1) ... \xi(x_N)] \in R^{(1+d+d') \times N}</script></li><li><p>使用注意力机制表示 $Ξ = ∑_{i=1}^N ξ(x_i)$ ：</p><ul><li>设置 $W_q = W_k = [e_1, 0^{(1+d+2d’)×(d+2d’)}]$ ，其中 $e_1 = [1, 0^{1×(d+2d’)}]^T$</li><li>数据依赖投影 <script type="math/tex">f(X) = BX1_N1^T_{N_s}</script> ，其中 <script type="math/tex">B = [0^{d'×1}, 0^{d'×d}, I_{d'}, 0^{d'×d'}]</script></li><li>得到投影分数：$[Ξ, …, Ξ] ∈ R^{d’×N}$</li></ul></li><li><p>连接投影分数并通过兼容矩阵 $W_c$ 产生最终输出，应用残差连接：</p><script type="math/tex; mode=display">[1 ... 1; x_1 ... x_N; \xi(x_1) ... \xi(x_N); \Xi ... \Xi] \in R^{(1+d+2d') \times N}</script><p>通过这种架构，Primphormer的注意力模块被设计用来计算Sumformer的聚合，而其余部分保持不变。因此，我们可以构造Primphormer <script type="math/tex">T_{Pri}</script>，使得<script type="math/tex">\sup_{X\in X^N} \|S(X) - T_{Pri}(X)\|_\infty < \varepsilon/2</script>。</p></li></ol><h5 id="结论-2"><a href="#结论-2" class="headerlink" title="结论"></a>结论</h5><p>利用三角不等式，我们得到：</p><script type="math/tex; mode=display">\sup_{X\in X^N} \|f (X) - T_{Pri}(X)\|_\infty < \varepsilon/2 + \varepsilon/2 = \varepsilon</script><p>这就完成了定理3.2的证明，表明Primphormer是置换等变序列到序列函数的通用逼近器。<br>值得注意的是，证明的关键在于将问题分解为两个可管理的部分，并分别用Sumformer和Primphormer的通用逼近性质来实现整体近似。这种方法受到Alberti等(2023)工作的启发，并结合了Primphormer的特定架构特性。</p><h4 id="定理-3-3-Universal-approximation-for-arbitrary-continuous-sequence-functions"><a href="#定理-3-3-Universal-approximation-for-arbitrary-continuous-sequence-functions" class="headerlink" title="定理 3.3 (Universal approximation for arbitrary continuous sequence functions)"></a>定理 3.3 (Universal approximation for arbitrary continuous sequence functions)</h4><p>该定理证明带有位置编码的 Primphormer 能近似任意连续序列函数：<br>对于任意连续函数 $f : [0,1]^{d \times N} \rightarrow \mathbb{R}^{d \times N}$ 和每个 $\varepsilon &gt; 0$，存在一个带有位置编码 $E$ 的 Primphormer $T^{PE}$，使得</p><script type="math/tex; mode=display">\sup_{X \in \mathcal{X}^N} \|f(X) - T^{PE}(X)\|_\infty < \varepsilon</script><h5 id="证明-1"><a href="#证明-1" class="headerlink" title="证明"></a>证明</h5><h6 id="第一步：引入位置编码与分片常数函数近似"><a href="#第一步：引入位置编码与分片常数函数近似" class="headerlink" title="第一步：引入位置编码与分片常数函数近似"></a>第一步：引入位置编码与分片常数函数近似</h6><p>由于目标函数 $f$ 是连续的，其分量函数 <script type="math/tex">g(x_k, {x_i | i≠k})</script> 也是连续的。考虑 <script type="math/tex">X ∈ [0,1]^{d×N}</script> 作为紧致集，<script type="math/tex">f</script> 在紧集上一致连续。给定 <script type="math/tex">ε > 0</script> ，存在 <script type="math/tex">δ > 0</script> 使得当 <script type="math/tex">∥X - X'∥ < δ</script> 时，有 <script type="math/tex">∥f(X) - f(X')∥_{∞} < ε/2</script> 。<br>定义网格：</p><script type="math/tex; mode=display">G_\delta = \{0, \delta, 2\delta, \ldots, 1-\delta\}^{d \times N}</script><p>将空间划分为超立方体网格 <script type="math/tex">C_P = [P_1, P_1+δ) × ⋯ × [P_{d×N}, P_{d×N}+δ)</script>，其中 <script type="math/tex">P ∈ G_δ</script> 。构造分片常数函数：</p><script type="math/tex; mode=display">\tilde{g}(X) = \sum_{P \in G_\delta} g(P) \cdot \mathbf{1}_{X \in C_P}</script><p>由于g的一致连续性，对于足够小的δ，有：</p><script type="math/tex; mode=display">\sup_{X} \|g(X) - \tilde{g}(X)\|_\infty < \frac{\varepsilon}{4}</script><p>引入位置编码 <script type="math/tex">E ∈ R^{d×N}</script>：</p><script type="math/tex; mode=display">E = \begin{bmatrix}0 & 1 & 2 & \cdots & N-1 & 0 & 1 & \cdots & N-1 \\\vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \ddots & \vdots \\0 & 1 & 2 & \cdots & N-1 & 0 & 1 & \cdots & N-1\end{bmatrix}</script><p>使得X+E的第k个列向量位于区间[k-1, k)内，不同token位于互不相交的区间。</p><h6 id="第二步：构建Sumformer-S"><a href="#第二步：构建Sumformer-S" class="headerlink" title="第二步：构建Sumformer S"></a>第二步：构建Sumformer S</h6><p>定义映射 $l: R^d → R$ ，对于列向量 $H_i ∈ R^d$：</p><script type="math/tex; mode=display">u = \left(\frac{1-\delta}{N}, \delta^{-1}, \ldots, \delta^{1-d}\right)^\top \in R^d</script><script type="math/tex; mode=display">l(H_i) = u^\top H_i</script><p>该映射将不同列映射到不同区间：<script type="math/tex">0 ≤ l(H_1) < l(H_2) < ⋯ < l(H_N) < 1</script> ，且对任意排列π满足 <script type="math/tex">l(H_π(1)) < l(H_π(2)) < ⋯ < l(H_π(N))</script>。<br>利用Kolmogorov-Arnold表示定理（Khesin &amp; Tabachnikov, 2014），定义从位置标识 <script type="math/tex">b = [l(H_i)|i∈[N]]</script> 到网格索引的函数 <script type="math/tex">μ: [0,1]^N → N</script>：</p><script type="math/tex; mode=display">\mu(b) = \rho\left(\sum_{n=1}^N \lambda_n \phi(b_n)\right)</script><p>其中 <script type="math/tex">ρ: R^{2N+1} → R</script> 和 <script type="math/tex">φ: R → R^{2N+1}</script> 是连续函数。<br>定义聚合函数：</p><script type="math/tex; mode=display">\Xi = \sum_{n=1}^N \xi(b_n) = \sum_{n=1}^N \lambda_n \phi(b_n)</script><p>并定义：</p><script type="math/tex; mode=display">\psi(x_k, \Xi) = \tilde{g}(\iota(\chi^{-1} \circ \mu^{-1} \circ \rho(\Xi)) - E)</script><p>其中 <script type="math/tex">ι: P → (P_k, P_{i≠k})</script> 将网格点分解为当前token与其他token，χ将网格点映射到位置标识b。<br>构建Sumformer S:</p><script type="math/tex; mode=display">S([x_1, \ldots, x_N]) = [\psi(x_1, \Xi), \ldots, \psi(x_N, \Xi)]</script><p>由于 <script type="math/tex">g̃</script> 精确表示网格点上的值且位置编码保持顺序，有：</p><script type="math/tex; mode=display">\sup_{X} \|f(X+E) - S(X+E)\|_\infty < \frac{\varepsilon}{2}</script><h6 id="第三步：用Primphormer逼近Sumformer"><a href="#第三步：用Primphormer逼近Sumformer" class="headerlink" title="第三步：用Primphormer逼近Sumformer"></a>第三步：用Primphormer逼近Sumformer</h6><p>根据定理3.2的证明思路（Alberti等, 2023），Primphormer可以逼近置换等变函数。尽管此处S不是置换等变的，但位置编码E固定了顺序，使得：</p><script type="math/tex; mode=display">\sup_{X} \|S(X+E) - T_{Pri}(X+E)\|_\infty < \frac{\varepsilon}{2}</script><p>其中 $T_{Pri}$ 为Primphormer，通过以下方式构建：</p><ol><li>前馈变换：$[x_1 \cdots x_N; x_1 \cdots x_N] \in R^{2d \times N}$</li><li>两层前馈网络保持前N个分量不变，同时近似ξ函数</li><li>添加线性映射与数据依赖投影计算$\Xi = \sum_{i=1}^N \xi(x_i)$</li><li>通过兼容矩阵 $W_c$ 输出最终结果<h6 id="第四步：整合结果"><a href="#第四步：整合结果" class="headerlink" title="第四步：整合结果"></a>第四步：整合结果</h6>由三角不等式：<script type="math/tex; mode=display">\sup_{X} \|f(X) - T_{PE}(X)\|_\infty = \sup_{X} \|f(X+E) - T_{PE}(X+E)\|_\infty</script><script type="math/tex; mode=display">\leq \sup_{X} \|f(X+E) - S(X+E)\|_\infty + \sup_{X} \|S(X+E) - T_{PE}(X+E)\|_\infty</script><script type="math/tex; mode=display">< \frac{\varepsilon}{2} + \frac{\varepsilon}{2} = \varepsilon</script>其中<script type="math/tex">T_{PE}(X) = T_{Pri}(X+E)</script>。<h5 id="结论-3"><a href="#结论-3" class="headerlink" title="结论"></a>结论</h5>定理3.3证明完成：对于任意连续函数f和ε &gt; 0，存在位置编码E和Primphormer TPE，使得在 $[0,1]^{d×N}$ 上一致逼近f的误差小于ε。这一结果证明了Primphormer在添加适当位置编码后，可以作为任意连续序列到序列函数的通用逼近器（Alberti等, 2023）。<h4 id="定理-3-4-Expressiveness-in-terms-of-1-WL"><a href="#定理-3-4-Expressiveness-in-terms-of-1-WL" class="headerlink" title="定理 3.4 (Expressiveness in terms of 1-WL)"></a>定理 3.4 (Expressiveness in terms of 1-WL)</h4>该定理证明了 Primphormer 的表达能力与 1 维 Weisfeiler-Lehman 算法（1-WL）相当：<br>设 $G = (V, E, l)$ 是有 $N$ 个节点的标记图，节点特征矩阵 $X^{(0)} := H \in \mathbb{R}^{d \times N}$ 与标签 $l$ 一致。那么对于所有迭代 $t \geq 0$，存在 Primphormer 的参数化，使得<script type="math/tex; mode=display">C_{1,t}(v) = C_{1,t}(w) \Leftrightarrow X^{(t)}(v) = X^{(t)}(w)</script>对于所有节点 $v, w \in V$，其中 $C^t_{1}$ 是 1-WL 测试在第 $t$ 次迭代中的着色函数。<h5 id="证明-2"><a href="#证明-2" class="headerlink" title="证明"></a>证明</h5><h6 id="1-初始化"><a href="#1-初始化" class="headerlink" title="1. 初始化"></a>1. 初始化</h6>根据引理C.7，存在一个初始化$X^{(0)}$的参数化，使得对于每个顶点$v \in V$：<script type="math/tex; mode=display">X^{(0)}(v) = [H'(v); 0; \deg'(v); P'(v)],</script>并且满足：<script type="math/tex; mode=display">H(v) = H(w) \iff H'(v) = H'(w),</script><script type="math/tex; mode=display">\deg(v) = \deg(w) \iff \deg'(v) = \deg'(w),</script><script type="math/tex; mode=display">P(v) = P(w) \iff P'(v) = P'(v),</script>其中$d = 2s + r + k$。我们使用归纳法进行证明。<br>首先，根据1-WL测试的定义，我们有：<script type="math/tex; mode=display">C_{1,0}(v) = C_{1,0}(w) \iff H(v) = H(w).</script>令$H^{(t)}(v)$表示迭代$t$时节点$v$的颜色表示。设$D^{\text{emb}} \in \mathbb{R}^{r\times N}$，使得对于第$i$列$D^{\text{emb}}_i = \deg’(v_i)$，其中$v_i$是某个固定但任意的节点排序中的第$i$个节点。那么$X^{(0)}$可以写为：<script type="math/tex; mode=display">X^{(0)} = [H^{(0)}; 0; D^{\text{emb}}; P'] \in \mathbb{R}^{d\times N}.</script><h6 id="2-归纳假设"><a href="#2-归纳假设" class="headerlink" title="2. 归纳假设"></a>2. 归纳假设</h6>假设命题在迭代$t$时成立，即存在Primphormer的参数化，使得：<script type="math/tex; mode=display">C_{1,t}(v) = C_{1,t}(w) \iff H^{(t)}(v) = H^{(t)}(w).</script>现在我们证明命题在$t+1$时也成立。为此，我们需要：<script type="math/tex; mode=display">C_{1,t+1}(v) = C_{1,t+1}(w) \iff H^{(t+1)}(v) = H^{(t+1)}(w).</script>这意味着$X^{(t+1)}$的第一个元素应该匹配1-WL等价的聚合：<script type="math/tex; mode=display">X^{(t+1)} = [H^{(t+1)}; 0; D^{\text{emb}}; P'] \in \mathbb{R}^{d\times N}.</script><h6 id="3-1-WL等价聚合"><a href="#3-1-WL等价聚合" class="headerlink" title="3. 1-WL等价聚合"></a>3. 1-WL等价聚合</h6>根据引理C.4，我们知道1-WL等价聚合遵循：<script type="math/tex; mode=display">H^{(t+1)} := \text{FFN}_{\text{WL}}[H^{(t)} + 2H^{(t)}A(G)],</script>其中$\text{FFN}_{\text{WL}}$是更新颜色的前馈层。因此，我们需要证明Primphormer能够模拟这一聚合过程。<h6 id="4-Primphormer参数化"><a href="#4-Primphormer参数化" class="headerlink" title="4. Primphormer参数化"></a>4. Primphormer参数化</h6>考虑Primphormer的输出$o(x) = W_c [e(x); r(x)]$，其中：<script type="math/tex; mode=display">e(x) = f_X W_e \phi_q(x),</script><script type="math/tex; mode=display">r(x) = f_X W_r \phi_k(x),</script><script type="math/tex; mode=display">f_X = F + BX1_N1^\top_{N_s}.</script>通过适当设置参数，我们可以将Primphormer参数化为$o(x) = e(x) = W_e \phi_q(x)$。设$\phi_q(x) := q(x)/|q(x)|_2$和$\phi_k(x) := k(x)/|k(x)|_2$，其中$q(x) = W_qx$和$k(x) = W_kx$。<br>将$W_q$和$W_k$进行分解：<script type="math/tex; mode=display">W_q = [W_{1,q}, W_{2,q}, W_{3,q}, W_{4,q}] \in \mathbb{R}^{d\times d},</script><script type="math/tex; mode=display">W_k = [W_{1,k}, W_{2,k}, W_{3,k}, W_{4,k}] \in \mathbb{R}^{d\times d},</script>其中子矩阵维度分别为<script type="math/tex">W_{q1}, W_{1,k} \in \mathbb{R}^{d\times s}</script>, <script type="math/tex">W_{q2}, W_{2,k} \in \mathbb{R}^{d\times s}</script>, <script type="math/tex">W_{q3}, W_{3,k} \in \mathbb{R}^{d\times r}</script>, <script type="math/tex">W_{q4}, W_{4,k} \in \mathbb{R}^{d\times k}</script>。<br>根据KKT条件，我们可以在行空间中重新参数化<script type="math/tex">W_e</script>：<script type="math/tex; mode=display">W_e = H\phi_k(X^{(t)})^\top,</script>其中$H$是一个由权重向量构成的矩阵。因此，Primphormer的输出可以表示为：<script type="math/tex; mode=display">o(X^{(t)}) = H\phi_k(X^{(t)})^\top\phi_q(X^{(t)}).</script><h6 id="5-模拟图拉普拉斯算子"><a href="#5-模拟图拉普拉斯算子" class="headerlink" title="5. 模拟图拉普拉斯算子"></a>5. 模拟图拉普拉斯算子</h6>通过设置合适的参数，我们可以使Primphormer模拟图拉普拉斯算子的作用。根据引理C.7，结构嵌入$P’$可以恢复(归一化)图拉普拉斯算子，即$P’^\top P’ = L$。<br>经过一系列变换，Primphormer的输出可以重写为：<script type="math/tex; mode=display">o(X^{(t)}) = HD^{-1/2}LD^{-1/2} = H[I - D^{-1/2}A(G)D^{-1/2}],</script>其中$L = D - A$是图拉普拉斯算子，$D$是度矩阵，$A$是邻接矩阵。<h6 id="6-完成归纳步骤"><a href="#6-完成归纳步骤" class="headerlink" title="6. 完成归纳步骤"></a>6. 完成归纳步骤</h6>最后，我们得到Primphormer的输出为：<script type="math/tex; mode=display">\text{Prim}(X^{(t)}) = [0; H^{(t)}(D^{1/2} - A(G)D^{-1/2}); 0; 0].</script>结合模型结构 $\text{FFN}(X + \text{Prim}(X))$ ，Primphormer计算下一个表示：<script type="math/tex; mode=display">X^{(t+1)} = \text{FFN}[X^{(t)} + \text{Prim}(X^{(t)})].</script>通过定义合适的函数<script type="math/tex">f_{\text{FFN}}, f_{\text{lin2}}, f_{\text{lin1}}, f_{\text{deg}}</script>，我们可以使Primphormer精确地模拟1-WL的聚合过程，得到：<script type="math/tex; mode=display">X^{(t+1)} = [H^{(t+1)}; 0; D^{\text{emb}}; P'].</script>其中$H^{(t+1)} = \text{FFN}_{\text{WL}}[H^{(t)} + 2H^{(t)}A(G)]$正是1-WL测试在第$t+1$次迭代的特征。<br>因此，我们证明了存在Primphormer的参数化，使得：<script type="math/tex; mode=display">C_{1,t+1}(v) = C_{1,t+1}(w) \iff H^{(t+1)}(v) = H^{(t+1)}(w).</script>根据引理C.5和定理C.8，我们知道Transformer和Primphormer在区分非同构图方面都能够模拟1-WL测试，表明了Primphormer保持了与标准Transformer相同的表达能力。<h4 id="推论-3-5-Expressiveness-comparison-with-Transformer"><a href="#推论-3-5-Expressiveness-comparison-with-Transformer" class="headerlink" title="推论 3.5 (Expressiveness comparison with Transformer)"></a>推论 3.5 (Expressiveness comparison with Transformer)</h4>该推论是定理 3.4 的延伸，指出 Transformer 和 Primphormer 在区分非同构图方面具有相同的表达能力：<br>设 $G = (V, E, l)$ 是有 $N$ 个节点的标记图，节点特征矩阵 $X^{(0)} := H \in \mathbb{R}^{d \times N}$ 与标签 $l$ 一致。那么对于所有迭代 $t \geq 0$，存在 Transformer 和 Primphormer 的参数化以及位置编码，使得<script type="math/tex; mode=display">X^{(t)}_T(v) = X^{(t)}_T(w) \Leftrightarrow X^{(t)}_{Pri}(v) = X^{(t)}_{Pri}(w)</script>对于所有节点 $v, w \in V$。<h3 id="论文中引用的其他重要定理"><a href="#论文中引用的其他重要定理" class="headerlink" title="论文中引用的其他重要定理"></a>论文中引用的其他重要定理</h3><h4 id="定义-2-1-Asymmetric-kernel-trick"><a href="#定义-2-1-Asymmetric-kernel-trick" class="headerlink" title="定义 2.1 (Asymmetric kernel trick)"></a>定义 2.1 (Asymmetric kernel trick)</h4>引用自 Wright &amp; Gonzalez (2021) 、Lin et al. (2022) 、He et al. (2023a)  和 Chen et al. (2023) ，定义了来自再生核巴拿赫空间（RKBS）的非对称核技巧：<script type="math/tex; mode=display">\kappa(x, z) = \langle \phi_q(x), \phi_k(z) \rangle</script><h4 id="表示定理-Representer-theorem"><a href="#表示定理-Representer-theorem" class="headerlink" title="表示定理 (Representer theorem)"></a>表示定理 (Representer theorem)</h4>引用自 Kimeldorf &amp; Wahba (1971) ，描述了原始空间和对偶空间之间的最优解关系：<script type="math/tex; mode=display">g(\xi_i) = \sum_j \alpha_j \kappa(\xi_i, \xi_j) = \langle w, \phi(\xi_i) \rangle</script><h4 id="引理-C-2-Universal-approximation-of-Sumformer"><a href="#引理-C-2-Universal-approximation-of-Sumformer" class="headerlink" title="引理 C.2 (Universal approximation of Sumformer)"></a>引理 C.2 (Universal approximation of Sumformer)</h4>引用自 Alberti et al. (2023) ，证明了 Sumformer 可以作为置换等变函数的通用逼近器。<h4 id="引理-C-3-Kolmogorov-Arnold-representation"><a href="#引理-C-3-Kolmogorov-Arnold-representation" class="headerlink" title="引理 C.3 (Kolmogorov-Arnold representation)"></a>引理 C.3 (Kolmogorov-Arnold representation)</h4>引用自 Khesin &amp; Tabachnikov (2014) 和 Zaheer et al. (2017) ，证明了任意多元连续函数有特定表示形式：<script type="math/tex; mode=display">f(x_1, \cdots, x_N) = \rho\left(\sum_{n=1}^N \lambda_n \varphi(x_n)\right)</script><h4 id="引理-C-4-Theorem-VIII-4-in-Grohe-2021"><a href="#引理-C-4-Theorem-VIII-4-in-Grohe-2021" class="headerlink" title="引理 C.4 (Theorem VIII.4 in Grohe, 2021)"></a>引理 C.4 (Theorem VIII.4 in Grohe, 2021)</h4>引用自 Grohe (2021) ，说明了 GNN 如何模拟 1-WL 测试过程。<h4 id="引理-C-5-Theorem-2-in-Muller-amp-Morris-2024"><a href="#引理-C-5-Theorem-2-in-Muller-amp-Morris-2024" class="headerlink" title="引理 C.5 (Theorem 2 in Müller &amp; Morris, 2024)"></a>引理 C.5 (Theorem 2 in Müller &amp; Morris, 2024)</h4>引用自 Müller &amp; Morris (2024) ，证明了标准 Graph Transformer 可以模拟 1-WL 测试。<h4 id="定义-C-6-LAP-and-SPE"><a href="#定义-C-6-LAP-and-SPE" class="headerlink" title="定义 C.6 (LAP and SPE)"></a>定义 C.6 (LAP and SPE)</h4>引用自 Kreuzer et al. (2021) 和 Huang et al. (2024) ，定义了两种结构嵌入方法：</li></ol><ul><li>LAP: $\psi(V^T_1, \lambda), \cdots, \psi(V^T_N, \lambda)$</li><li>SPE: $V \varphi_1(\lambda) V^T, \cdots, V \varphi_m(\lambda) V^T$</li></ul>]]></content>
    
    
    <summary type="html">Primphormer:Efficient Graph Transformers with Primal Representations</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Linear Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Linear-Transformer/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Linear Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Linear-Transformer/"/>
    
  </entry>
  
  <entry>
    <title>动态图基础 ｜ Dynamic Graphs</title>
    <link href="https://epsilonzyj.github.io/blog/posts/90649c8.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/90649c8.html</id>
    <published>2025-10-23T16:32:11.000Z</published>
    <updated>2026-06-12T05:48:31.714Z</updated>
    
    <content type="html"><![CDATA[<h1 id="什么是动态图"><a href="#什么是动态图" class="headerlink" title="什么是动态图"></a>什么是动态图</h1><h2 id="1-动态图的定义与分类"><a href="#1-动态图的定义与分类" class="headerlink" title="1. 动态图的定义与分类"></a>1. 动态图的定义与分类</h2><h3 id="1-1-基本定义"><a href="#1-1-基本定义" class="headerlink" title="1.1 基本定义"></a>1.1 基本定义</h3><p>动态图（Dynamic Graph）是指<strong>节点和边随着时间不断变化的图结构</strong>。在动态图中，一个节点不仅包含节点本身，还包含其生存的起始时间和结束时间；一条边也具有端点u、v以及该边的起始时间和结束时间。<br>与传统静态图相比，动态图能够更好地建模现实世界中<strong>随时间演化的复杂交互关系</strong>。动态图在学术文献中也有多种称谓，包括temporal networks、evolutionary networks、time-varying networks等，本质上都是指具有时变特性的图结构。</p><h3 id="1-2-动态图的分类方法"><a href="#1-2-动态图的分类方法" class="headerlink" title="1.2 动态图的分类方法"></a>1.2 动态图的分类方法</h3><p>根据不同的分类维度，动态图可以分为以下几类：</p><h4 id="1-2-1-按时间粒度分类（Temporal-Granularity）"><a href="#1-2-1-按时间粒度分类（Temporal-Granularity）" class="headerlink" title="1.2.1 按时间粒度分类（Temporal Granularity）"></a>1.2.1 按时间粒度分类（Temporal Granularity）</h4><p>从对于动态性的粒度上来划分，动态图可分为四类，复杂程度和动态性关注程度依次增强：</p><div class="table-container"><table><thead><tr><th>动态图类型</th><th>定义</th><th>特点</th><th>应用场景</th></tr></thead><tbody><tr><td><strong>Static Networks</strong></td><td>不关注图中的动态性信息，作为静态图处理</td><td>无时间维度</td><td>传统图分析任务</td></tr><tr><td><strong>Edge Weighted Networks</strong></td><td>动态信息作为节点或边的labels存在</td><td>边权值随时间变化</td><td>加权社交网络、交通网络</td></tr><tr><td><strong>Discrete Dynamic Graphs</strong></td><td>以离散时间片对图进行划分，多个静态图的集合</td><td>图结构按时间片跳跃式变化</td><td>社交网络 snapshots</td></tr><tr><td><strong>Continuous Dynamic Graphs</strong></td><td>将图变化看作不断发生的事件，保留最多动态信息</td><td>连续时间流处理</td><td>金融交易、实时推荐系统</td></tr></tbody></table></div><h4 id="1-2-2-按链接持续时间分类（Link-Duration）"><a href="#1-2-2-按链接持续时间分类（Link-Duration）" class="headerlink" title="1.2.2 按链接持续时间分类（Link Duration）"></a>1.2.2 按链接持续时间分类（Link Duration）</h4><p>根据链接的持续时间特性，动态图可分为：</p><ul><li><strong>固定持续时间（Fixed Duration）</strong>：边的存在时间预先定义</li><li><strong>可变持续时间（Variable Duration）</strong>：边的存在时间根据实际交互确定<h4 id="1-2-3-按事件类型分类"><a href="#1-2-3-按事件类型分类" class="headerlink" title="1.2.3 按事件类型分类"></a>1.2.3 按事件类型分类</h4>连续型动态图的事件表示方式主要包括：</li></ul><ol><li><strong>Event-based Representation</strong>：每个边包含事件的起始时间和持续时间</li><li><strong>Contact Sequence Representation</strong>：event-based的特例，适用于瞬时事件（如邮件发送）</li><li><strong>Graph Stream Representation</strong>：将边的产生和消失分别作为不同事件，用标志位表示</li></ol><h2 id="2-动态图解决的问题"><a href="#2-动态图解决的问题" class="headerlink" title="2. 动态图解决的问题"></a>2. 动态图解决的问题</h2><h3 id="2-1-静态图的局限性"><a href="#2-1-静态图的局限性" class="headerlink" title="2.1 静态图的局限性"></a>2.1 静态图的局限性</h3><p>传统的静态图神经网络在处理现实世界数据时面临以下局限性：</p><h4 id="2-1-1-无法捕捉时间演化特征"><a href="#2-1-1-无法捕捉时间演化特征" class="headerlink" title="2.1.1 无法捕捉时间演化特征"></a>2.1.1 无法捕捉时间演化特征</h4><ul><li><strong>数据冻结问题</strong>：静态图将时间维度简化为单一的图结构，无法捕捉节点的动态演化过程</li><li><strong>信息丢失</strong>：忽略了时序信息中的重要模式，如用户偏好的变化趋势、交互行为的时间模式等</li><li><strong>过度简化</strong>：将时序数据压缩为静态表示，导致关键时序特征丢失<h4 id="2-1-2-难以处理实时性任务"><a href="#2-1-2-难以处理实时性任务" class="headerlink" title="2.1.2 难以处理实时性任务"></a>2.1.2 难以处理实时性任务</h4></li><li><strong>预测能力不足</strong>：静态图无法对未来图结构变化进行有效预测</li><li><strong>适应性差</strong>：面对动态环境变化时，模型难以进行实时更新</li><li><strong>冷启动问题</strong>：新节点加入时无法有效利用历史演化信息<h4 id="2-1-3-特征建模不充分"><a href="#2-1-3-特征建模不充分" class="headerlink" title="2.1.3 特征建模不充分"></a>2.1.3 特征建模不充分</h4></li><li><strong>时间相关性建模不足</strong>：无法有效建模节点间交互的时间相关性</li><li><strong>长程依赖捕捉困难</strong>：静态图难以捕捉长时程演化中的依赖关系</li><li><strong>上下文信息缺失</strong>：缺乏对时间上下文的有效编码机制</li></ul><h3 id="2-2-动态图的核心优势"><a href="#2-2-动态图的核心优势" class="headerlink" title="2.2 动态图的核心优势"></a>2.2 动态图的核心优势</h3><p>动态图的出现正是为了解决上述静态图的局限性：</p><div class="table-container"><table><thead><tr><th>方面</th><th>静态图</th><th>动态图</th><th>改进效果</th></tr></thead><tbody><tr><td><strong>时间建模</strong></td><td>单一图结构</td><td>多时间维度的演化序列</td><td>能捕捉时序演变模式</td></tr><tr><td><strong>预测能力</strong></td><td>静态推断</td><td>时序预测</td><td>支持未来交互预测</td></tr><tr><td><strong>实时性</strong></td><td>批处理模式</td><td>在线学习</td><td>支持实时更新</td></tr><tr><td><strong>特征表示</strong></td><td>静态特征</td><td>时序动态特征</td><td>更丰富的表征能力</td></tr></tbody></table></div><h3 id="2-3-典型应用场景"><a href="#2-3-典型应用场景" class="headerlink" title="2.3 典型应用场景"></a>2.3 典型应用场景</h3><p>动态图特别适用于以下需要建模时间演化特性的场景：</p><h4 id="2-3-1-社交网络分析"><a href="#2-3-1-社交网络分析" class="headerlink" title="2.3.1 社交网络分析"></a>2.3.1 社交网络分析</h4><ul><li><strong>用户关系演化</strong>：建模用户间关注关系随时间的变化</li><li><strong>信息传播预测</strong>：预测新闻、话题在社交网络中的传播路径和速度</li><li><strong>社区动态检测</strong>：发现社区形成、分裂、合并等动态模式<h4 id="2-3-2-推荐系统"><a href="#2-3-2-推荐系统" class="headerlink" title="2.3.2 推荐系统"></a>2.3.2 推荐系统</h4></li><li><strong>用户偏好演化</strong>：建模用户兴趣随时间的变化规律</li><li><strong>序列推荐</strong>：基于用户历史交互序列进行个性化推荐</li><li><strong>实时推荐</strong>：根据用户实时交互行为调整推荐策略<h4 id="2-3-3-金融风控"><a href="#2-3-3-金融风控" class="headerlink" title="2.3.3 金融风控"></a>2.3.3 金融风控</h4></li><li><strong>交易网络分析</strong>：建模用户间资金流动的动态模式</li><li><strong>异常检测</strong>：检测异常交易行为的时间和空间模式</li><li><strong>风险传播预测</strong>：预测风险在金融网络中的传播路径<h4 id="2-3-4-交通网络"><a href="#2-3-4-交通网络" class="headerlink" title="2.3.4 交通网络"></a>2.3.4 交通网络</h4></li><li><strong>交通流量预测</strong>：建模交通网络的时空演化模式</li><li><strong>路径规划</strong>：考虑时间动态性的最优路径选择</li><li><strong>拥堵预测</strong>：预测交通拥堵的形成和扩散</li></ul><h2 id="3-主流动态图算法架构"><a href="#3-主流动态图算法架构" class="headerlink" title="3. 主流动态图算法架构"></a>3. 主流动态图算法架构</h2><h3 id="3-1-离散时间动态图处理方法"><a href="#3-1-离散时间动态图处理方法" class="headerlink" title="3.1 离散时间动态图处理方法"></a>3.1 离散时间动态图处理方法</h3><p>离散时间动态图将时间划分为固定的时间片，在每个时间片内保持图结构相对稳定。主要处理方法包括：</p><h4 id="3-1-1-Snapshot-based-Methods"><a href="#3-1-1-Snapshot-based-Methods" class="headerlink" title="3.1.1 Snapshot-based Methods"></a>3.1.1 Snapshot-based Methods</h4><ul><li><strong>方法原理</strong>：将离散动态图视为一系列静态图的快照序列</li><li><strong>代表模型</strong>：DCRNN、STGCN、Graph WaveNet</li><li><strong>优点</strong>：可直接利用成熟的静态图处理方法</li><li><strong>缺点</strong>：时间粒度固定，无法捕捉连续事件<h4 id="3-1-2-Temporal-Graph-Convolutional-Networks"><a href="#3-1-2-Temporal-Graph-Convolutional-Networks" class="headerlink" title="3.1.2 Temporal Graph Convolutional Networks"></a>3.1.2 Temporal Graph Convolutional Networks</h4></li><li><strong>方法原理</strong>：在图卷积的基础上引入时间维度</li><li><strong>代表模型</strong>：EvolveGCN、TGCN</li><li><strong>技术特点</strong>：通过递归或时间卷积学习图结构的时序演化</li></ul><h3 id="3-2-连续时间动态图处理方法"><a href="#3-2-连续时间动态图处理方法" class="headerlink" title="3.2 连续时间动态图处理方法"></a>3.2 连续时间动态图处理方法</h3><p>连续时间动态图将事件视为连续流中的点，更加灵活地处理不规则时间间隔的事件。</p><h4 id="3-2-1-基于RNN的方法"><a href="#3-2-1-基于RNN的方法" class="headerlink" title="3.2.1 基于RNN的方法"></a>3.2.1 基于RNN的方法</h4><ul><li><strong>方法原理</strong>：使用循环神经网络建模连续时间序列</li><li><strong>代表模型</strong>：DyRep、TGAT</li><li><strong>技术特点</strong>：能够处理变长和不规则的时间间隔</li><li><strong>局限性</strong>：长序列训练困难，梯度消失问题<h4 id="3-2-2-基于时间点过程的方法"><a href="#3-2-2-基于时间点过程的方法" class="headerlink" title="3.2.2 基于时间点过程的方法"></a>3.2.2 基于时间点过程的方法</h4></li><li><strong>方法原理</strong>：将事件建模为点过程，学习事件发生的时间间隔分布</li><li><strong>代表模型</strong>：TGN (Temporal Graph Networks)</li><li><strong>核心技术</strong>：记忆模块 + 图卷积操作</li><li><strong>优势</strong>：通用框架，可表示多种现有方法为特例<h4 id="3-2-3-基于Transformer的方法"><a href="#3-2-3-基于Transformer的方法" class="headerlink" title="3.2.3 基于Transformer的方法"></a>3.2.3 基于Transformer的方法</h4></li><li><strong>方法原理</strong>：利用自注意力机制建模时间依赖关系</li><li><strong>代表模型</strong>：DyGFormer、TempCN</li><li><strong>技术特点</strong>：能够捕捉长距离时间依赖</li><li><strong>优势</strong>：并行化处理，高效建模复杂时间模式</li></ul><h3 id="3-3-典型模型详解：TGNs"><a href="#3-3-典型模型详解：TGNs" class="headerlink" title="3.3 典型模型详解：TGNs"></a>3.3 典型模型详解：TGNs</h3><p>TGNs (Temporal Graph Networks) 是目前最通用的动态图学习框架之一：</p><h4 id="3-3-1-核心架构"><a href="#3-3-1-核心架构" class="headerlink" title="3.3.1 核心架构"></a>3.3.1 核心架构</h4><p>TGNs结合了记忆模块和图卷积操作，包含以下关键组件：</p><ol><li><strong>Memory Module</strong>：保留节点长期特征，类似LSTM思路</li><li><strong>Message Function</strong>：定义节点间信息传递方式</li><li><strong>Message Aggregator</strong>：聚合时间窗口内的多条消息</li><li><strong>Memory Updater</strong>：根据消息更新节点特征</li><li><strong>Embedding Module</strong>：生成最终节点表示<h4 id="3-3-2-数学表达"><a href="#3-3-2-数学表达" class="headerlink" title="3.3.2 数学表达"></a>3.3.2 数学表达</h4>对于节点i在时刻t的嵌入表示：<script type="math/tex; mode=display">zi(t) = emb(i,t) = ∑j∈ηik([0,t]) h(si(t), sj(t), eij, vi(t), vj(t))</script>其中：</li></ol><ul><li>h是可学习的函数</li><li>ηik([0,t])表示时间区间[0,t]内的k-hop邻居</li><li>si(t)是节点状态，vi(t)是节点特征<h4 id="3-3-3-实验效果"><a href="#3-3-3-实验效果" class="headerlink" title="3.3.3 实验效果"></a>3.3.3 实验效果</h4>TGNs在多项任务中取得了state-of-the-art性能：</li><li><strong>链路预测</strong>：在Reddit、Wikipedia等数据集上显著优于baseline</li><li><strong>动态节点分类</strong>：在连续时间节点分类任务中表现优异</li><li><strong>通用性</strong>：证明了多种现有动态图模型是其特例</li></ul><h2 id="4-动态图当前面临的挑战"><a href="#4-动态图当前面临的挑战" class="headerlink" title="4. 动态图当前面临的挑战"></a>4. 动态图当前面临的挑战</h2><h3 id="4-1-数据与建模挑战"><a href="#4-1-数据与建模挑战" class="headerlink" title="4.1 数据与建模挑战"></a>4.1 数据与建模挑战</h3><h4 id="4-1-1-数据稀疏性与不平衡性"><a href="#4-1-1-数据稀疏性与不平衡性" class="headerlink" title="4.1.1 数据稀疏性与不平衡性"></a>4.1.1 数据稀疏性与不平衡性</h4><ul><li><strong>长尾分布</strong>：大多数动态网络呈现长尾分布，少数节点占据大量连接</li><li><strong>事件稀疏性</strong>：许多节点间交互频率极低，难以学习有效模式</li><li><strong>时间不平衡</strong>：不同时间段数据密度差异巨大<h4 id="4-1-2-高动态性与复杂性"><a href="#4-1-2-高动态性与复杂性" class="headerlink" title="4.1.2 高动态性与复杂性"></a>4.1.2 高动态性与复杂性</h4></li><li><strong>快速演化</strong>：现实网络演化速度远快于模型学习速度</li><li><strong>多尺度动态性</strong>：需要同时捕捉短期和长期演化模式</li><li><strong>非线性演化</strong>：网络演化通常呈现复杂的非线性特征</li></ul><h3 id="4-2-算法与计算挑战"><a href="#4-2-算法与计算挑战" class="headerlink" title="4.2 算法与计算挑战"></a>4.2 算法与计算挑战</h3><h4 id="4-2-1-计算效率问题"><a href="#4-2-1-计算效率问题" class="headerlink" title="4.2.1 计算效率问题"></a>4.2.1 计算效率问题</h4><ul><li><strong>复杂度开销</strong>：动态图算法通常具有较高的计算复杂度</li><li><strong>内存占用</strong>：存储历史演化信息需要大量内存</li><li><strong>实时性要求</strong>：许多应用场景要求低延迟的在线学习<h4 id="4-2-2-时序建模局限性"><a href="#4-2-2-时序建模局限性" class="headerlink" title="4.2.2 时序建模局限性"></a>4.2.2 时序建模局限性</h4></li><li><strong>长期依赖建模</strong>：现有方法在捕捉长时程依赖方面仍有局限</li><li><strong>时间感知能力</strong>：对时间间隔的建模相对粗糙</li><li><strong>多周期模式</strong>：难以识别和利用多时间尺度的周期性模式</li></ul><h3 id="4-3-泛化与鲁棒性挑战"><a href="#4-3-泛化与鲁棒性挑战" class="headerlink" title="4.3 泛化与鲁棒性挑战"></a>4.3 泛化与鲁棒性挑战</h3><h4 id="4-3-1-分布外泛化问题"><a href="#4-3-1-分布外泛化问题" class="headerlink" title="4.3.1 分布外泛化问题"></a>4.3.1 分布外泛化问题</h4><ul><li><strong>环境变化适应</strong>：现有方法在面临分布变化时泛化能力有限</li><li><strong>领域差异</strong>：在不同类型动态网络上迁移困难</li><li><strong>时态漂移</strong>：对时序分布变化的适应能力不足<h4 id="4-3-2-鲁棒性问题"><a href="#4-3-2-鲁棒性问题" class="headerlink" title="4.3.2 鲁棒性问题"></a>4.3.2 鲁棒性问题</h4></li><li><strong>噪声敏感性</strong>：动态图数据中的噪声对模型训练影响较大</li><li><strong>异常干扰</strong>：极端事件可能破坏学习到的模式</li><li><strong>对抗性攻击</strong>：动态图对抗攻击研究仍处于起步阶段</li></ul><h3 id="4-4-最新研究趋势（2023-2024）"><a href="#4-4-最新研究趋势（2023-2024）" class="headerlink" title="4.4 最新研究趋势（2023-2024）"></a>4.4 最新研究趋势（2023-2024）</h3><p>根据最新研究动态，当前前沿主要聚焦于以下方向：</p><h4 id="4-4-1-环境感知动态图学习"><a href="#4-4-1-环境感知动态图学习" class="headerlink" title="4.4.1 环境感知动态图学习"></a>4.4.1 环境感知动态图学习</h4><ul><li><strong>核心问题</strong>：如何发现和利用动态图中的不变时空模式</li><li><strong>代表工作</strong>：EAGLE框架（Environment-Aware dynamic Graph Learning）</li><li><strong>技术思路</strong>：建模复杂时空环境，发现分布变化下的不变模式</li><li><strong>应用价值</strong>：提升在分布变化场景下的泛化能力<h4 id="4-4-2-大语言模型与动态图结合"><a href="#4-4-2-大语言模型与动态图结合" class="headerlink" title="4.4.2 大语言模型与动态图结合"></a>4.4.2 大语言模型与动态图结合</h4></li><li><strong>研究热点</strong>：将LLM的时间推理能力与动态图结合</li><li><strong>代表工作</strong>：<ul><li>《Temporal Knowledge Graph Forecasting Without Knowledge Using In-Context Learning》</li><li>《Back to the Future: Towards Explainable Temporal Reasoning with Large Language Models》</li></ul></li><li><strong>技术思路</strong>：利用LLM进行时间逻辑推理，增强动态图的可解释性</li><li><strong>优势</strong>：强大的时间推理能力和可解释性<h4 id="4-4-3-时序对比学习"><a href="#4-4-3-时序对比学习" class="headerlink" title="4.4.3 时序对比学习"></a>4.4.3 时序对比学习</h4></li><li><strong>方法创新</strong>：基于可学习视图生成器的动态图对比学习</li><li><strong>代表工作</strong>：Learnable Dynamic Graph Contrastive (LDGC)</li><li><strong>技术特点</strong>：通过视图生成器增强数据多样性</li><li><strong>效果提升</strong>：在多个基准数据集上显著提升表示学习效果<h4 id="4-4-4-因果推理动态图"><a href="#4-4-4-因果推理动态图" class="headerlink" title="4.4.4 因果推理动态图"></a>4.4.4 因果推理动态图</h4></li><li><strong>研究动机</strong>：从相关发现到因果理解</li><li><strong>代表工作</strong>：《Using Causality-Aware Graph Neural Networks to Predict Temporal Centralities》</li><li><strong>技术框架</strong>：因果感知的图神经网络建模</li><li><strong>应用价值</strong>：提升预测的可解释性和可靠性</li></ul><h2 id="5-技术对比与发展趋势分析"><a href="#5-技术对比与发展趋势分析" class="headerlink" title="5. 技术对比与发展趋势分析"></a>5. 技术对比与发展趋势分析</h2><h3 id="5-1-不同方法对比"><a href="#5-1-不同方法对比" class="headerlink" title="5.1 不同方法对比"></a>5.1 不同方法对比</h3><div class="table-container"><table><thead><tr><th>方法类型</th><th>代表模型</th><th>时间建模方式</th><th>计算复杂度</th><th>适用场景</th><th>主要优势</th></tr></thead><tbody><tr><td><strong>Snapshot-based</strong></td><td>DCRNN、STGCN</td><td>离散时间片</td><td>中等</td><td>规则时间数据</td><td>简单易实现</td></tr><tr><td><strong>RNN-based</strong></td><td>DyRep、TGAT</td><td>序列建模</td><td>较高</td><td>不规则时间数据</td><td>处理变长序列</td></tr><tr><td><strong>Point Process</strong></td><td>TGNs</td><td>事件时间间隔</td><td>高</td><td>连续时间事件</td><td>通用性强</td></tr><tr><td><strong>Transformer</strong></td><td>DyGFormer</td><td>自注意力</td><td>很高</td><td>复杂时序模式</td><td>长距离依赖</td></tr><tr><td><strong>Causal</strong></td><td>CausalTGN</td><td>因果推理</td><td>很高</td><td>可解释性要求高</td><td>可解释性强</td></tr></tbody></table></div><h3 id="5-2-发展趋势预测"><a href="#5-2-发展趋势预测" class="headerlink" title="5.2 发展趋势预测"></a>5.2 发展趋势预测</h3><p>基于当前研究进展，动态图未来发展趋势主要包括：</p><h4 id="5-2-1-多模态融合"><a href="#5-2-1-多模态融合" class="headerlink" title="5.2.1 多模态融合"></a>5.2.1 多模态融合</h4><ul><li><strong>技术方向</strong>：结合文本、图像等多模态信息增强动态图表示</li><li><strong>应用场景</strong>：社交网络、多媒体内容推荐</li><li><strong>技术挑战</strong>：跨模态对齐和多源信息融合<h4 id="5-2-2-可解释性增强"><a href="#5-2-2-可解释性增强" class="headerlink" title="5.2.2 可解释性增强"></a>5.2.2 可解释性增强</h4></li><li><strong>技术方向</strong>：提升动态图模型的决策透明度和可理解性</li><li><strong>应用场景</strong>：金融风控、医疗诊断</li><li><strong>技术路径</strong>：因果推理、注意力可视化、符号学习<h4 id="5-2-3-在线实时学习"><a href="#5-2-3-在线实时学习" class="headerlink" title="5.2.3 在线实时学习"></a>5.2.3 在线实时学习</h4></li><li><strong>技术方向</strong>：实现动态图模型的实时更新和在线适应</li><li><strong>应用场景</strong>：实时推荐、应急响应</li><li><strong>技术挑战</strong>：增量学习、分布式计算、实时推理<h4 id="5-2-4-跨领域迁移学习"><a href="#5-2-4-跨领域迁移学习" class="headerlink" title="5.2.4 跨领域迁移学习"></a>5.2.4 跨领域迁移学习</h4></li><li><strong>技术方向</strong>：提升在不同类型动态网络间的迁移能力</li><li><strong>应用场景</strong>：多场景适配、小样本学习</li><li><strong>技术路径</strong>：元学习、领域自适应、预训练-微调范式</li></ul><h2 id="6-实践建议与资源推荐"><a href="#6-实践建议与资源推荐" class="headerlink" title="6. 实践建议与资源推荐"></a>6. 实践建议与资源推荐</h2><h3 id="6-1-工具与框架选择"><a href="#6-1-工具与框架选择" class="headerlink" title="6.1 工具与框架选择"></a>6.1 工具与框架选择</h3><h4 id="6-1-1-开源框架"><a href="#6-1-1-开源框架" class="headerlink" title="6.1.1 开源框架"></a>6.1.1 开源框架</h4><ul><li><strong>PyTorch Geometric Temporal</strong>：专门处理动态图的时间PyG库</li><li><strong>PyTorch Geometric</strong>：支持动态图数据集和模型</li><li><strong>JittorGeometric</strong>：国内自主研发的高效图学习框架</li><li><strong>DGL (Deep Graph Library)</strong>：支持多种动态图算法<h4 id="6-1-2-数据集推荐"><a href="#6-1-2-数据集推荐" class="headerlink" title="6.1.2 数据集推荐"></a>6.1.2 数据集推荐</h4></li></ul><div class="table-container"><table><thead><tr><th>数据集类型</th><th>代表数据集</th><th>应用场景</th><th>数据特点</th></tr></thead><tbody><tr><td><strong>社交网络</strong></td><td>Reddit、Wikipedia</td><td>社区演化、用户行为</td><td>大规模、多时间戳</td></tr><tr><td><strong>交易网络</strong></td><td>Bitcoin Alpha、Ethereum Trust</td><td>金融风控、信任评估</td><td>有向、时间密集</td></tr><tr><td><strong>推荐系统</strong></td><td>Amazon、Yelp</td><td>顺序推荐、个性化</td><td>异构、序列化</td></tr><tr><td><strong>交通网络</strong></td><td>METR-LA、PEMS-BAY</td><td>流量预测、路径规划</td><td>空间-时间耦合</td></tr></tbody></table></div><h3 id="6-2-开发实践建议"><a href="#6-2-开发实践建议" class="headerlink" title="6.2 开发实践建议"></a>6.2 开发实践建议</h3><h4 id="6-2-1-数据预处理"><a href="#6-2-1-数据预处理" class="headerlink" title="6.2.1 数据预处理"></a>6.2.1 数据预处理</h4><ol><li><strong>时间粒度选择</strong>：根据应用场景选择合适的时间粒度</li><li><strong>数据清洗</strong>：处理异常值、缺失值和噪声数据</li><li><strong>特征工程</strong>：提取时间特征、统计特征和图结构特征</li><li><strong>数据增强</strong>：通过时间插值、随机扰动等方法扩充数据<h4 id="6-2-2-模型选型"><a href="#6-2-2-模型选型" class="headerlink" title="6.2.2 模型选型"></a>6.2.2 模型选型</h4></li><li><strong>问题匹配</strong>：根据任务特点（预测、分类、异常检测等）选择合适模型</li><li><strong>数据规模</strong>：考虑计算资源限制，选择合适的模型复杂度</li><li><strong>实时性要求</strong>：根据响应时间要求选择在线或批量学习方式</li><li><strong>可解释性需求</strong>：权衡性能与可解释性需求<h4 id="6-2-3-评估指标"><a href="#6-2-3-评估指标" class="headerlink" title="6.2.3 评估指标"></a>6.2.3 评估指标</h4></li></ol><div class="table-container"><table><thead><tr><th>任务类型</th><th>核心指标</th><th>说明</th></tr></thead><tbody><tr><td><strong>链路预测</strong></td><td>MRR、Recall@K</td><td>预测未来链接的准确性</td></tr><tr><td><strong>节点分类</strong></td><td>Accuracy、F1-score</td><td>节点类别识别性能</td></tr><tr><td><strong>流量预测</strong></td><td>MAE、RMSE</td><td>数值预测误差</td></tr><tr><td><strong>异常检测</strong></td><td>Precision、Recall</td><td>异常识别能力</td></tr></tbody></table></div><h3 id="6-3-学习资源推荐"><a href="#6-3-学习资源推荐" class="headerlink" title="6.3 学习资源推荐"></a>6.3 学习资源推荐</h3><h4 id="6-3-1-经典论文"><a href="#6-3-1-经典论文" class="headerlink" title="6.3.1 经典论文"></a>6.3.1 经典论文</h4><ol><li><p><strong>综述类</strong>：</p><ul><li>《Representation Learning for Dynamic Graphs: A Survey》</li><li>《Foundations and modelling of dynamic networks using Dynamic Graph Neural Networks》</li></ul></li><li><p><strong>方法类</strong>：</p><ul><li>《Temporal Graph Networks for Deep Learning on Dynamic Graphs》</li><li>《Temporal Graph Attention Networks》</li><li>《EvolveGCN: Evolving Graph Convolutional Networks for Dynamic Graphs》</li></ul></li><li><p><strong>应用类</strong>：</p><ul><li>《Dynamic Graph Neural Networks for Sequential Recommendation》</li><li>《Machine Learning on Dynamic Graphs: A Survey on Applications》</li></ul></li></ol><h4 id="6-3-2-学习路线"><a href="#6-3-2-学习路线" class="headerlink" title="6.3.2 学习路线"></a>6.3.2 学习路线</h4><ol><li><strong>基础阶段</strong>：学习图神经网络基本概念和静态图处理方法</li><li><strong>进阶阶段</strong>：掌握动态图的表示学习方法和基本算法</li><li><strong>专业阶段</strong>：深入研究特定动态图算法和应用场景</li><li><strong>创新阶段</strong>：结合最新研究进展开展创新性工作</li></ol><h2 id="7-总结与展望"><a href="#7-总结与展望" class="headerlink" title="7. 总结与展望"></a>7. 总结与展望</h2><p>动态图作为图机器学习的重要组成部分，为处理现实世界中复杂的时间演化网络数据提供了强大的工具。本报告系统梳理了动态图的概念体系、算法架构和当前挑战，为研究者和实践者提供了全面的参考。</p><h3 id="7-1-主要发现"><a href="#7-1-主要发现" class="headerlink" title="7.1 主要发现"></a>7.1 主要发现</h3><ol><li><p><strong>理论体系</strong>：动态图已经形成了较为完善的理论体系和分类方法，能够从不同维度描述时变网络特性。</p></li><li><p><strong>算法发展</strong>：从简单的快照处理到复杂的时序建模，动态图算法不断演进，TGNs等通用框架的出现标志着技术的成熟。</p></li><li><p><strong>应用价值</strong>：在社交网络、推荐系统、金融风控等多个领域展现出重要的应用价值，推动了相关产业的发展。</p></li><li><p><strong>挑战机遇</strong>：尽管面临数据稀疏性、计算效率、泛化能力等多重挑战，但也为研究创新提供了重要机遇。</p></li></ol><h3 id="7-2-未来研究方向"><a href="#7-2-未来研究方向" class="headerlink" title="7.2 未来研究方向"></a>7.2 未来研究方向</h3><ol><li><p><strong>理论创新</strong>：建立更加严谨的动态图学习理论框架，深入理解其数学本质。</p></li><li><p><strong>算法突破</strong>：开发更加高效、可扩展的动态图算法，突破现有方法的计算瓶颈。</p></li><li><p><strong>应用拓展</strong>：探索动态图在更多新兴领域的应用，如生物医学、智能交通、可持续发展等。</p></li><li><p><strong>跨学科融合</strong>：结合因果推理、强化学习、符号AI等跨学科方法，推动技术突破。</p></li></ol><p>动态图学习仍处于快速发展阶段，随着理论和技术的不断进步，必将在更多的实际应用中发挥重要作用，为解决复杂系统的时间演化问题提供强大的支持。</p><hr><h1 id="动态图与GNN"><a href="#动态图与GNN" class="headerlink" title="动态图与GNN"></a>动态图与GNN</h1><h2 id="一、动态图基础知识"><a href="#一、动态图基础知识" class="headerlink" title="一、动态图基础知识"></a>一、动态图基础知识</h2><h3 id="1-动态图定义"><a href="#1-动态图定义" class="headerlink" title="1. 动态图定义"></a>1. 动态图定义</h3><ul><li><strong>核心特性</strong>：图的拓扑结构（节点/边）或属性随时间变化</li><li><strong>经典分类</strong>：<ul><li><strong>离散时间动态图</strong>（Snapshot Graphs）：按时间片分割为多个静态图（如每小时社交网络）</li><li><strong>持续时态图</strong>（Continuous-Time Dynamic Graphs, CTDG）：以时间戳事件记录变化（如交易记录流）</li></ul></li></ul><h3 id="2-动态图的核心挑战"><a href="#2-动态图的核心挑战" class="headerlink" title="2. 动态图的核心挑战"></a>2. 动态图的核心挑战</h3><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR  A[动态图挑战] --&gt; B[时间依赖性建模]  A --&gt; C[计算效率优化]  A --&gt; D[长期模式捕捉]  A --&gt; E[增量学习能力]  </pre></div><h2 id="二、GNN与动态图结合的基础技术"><a href="#二、GNN与动态图结合的基础技术" class="headerlink" title="二、GNN与动态图结合的基础技术"></a>二、GNN与动态图结合的基础技术</h2><h3 id="1-核心架构分类"><a href="#1-核心架构分类" class="headerlink" title="1. 核心架构分类"></a>1. 核心架构分类</h3><div class="table-container"><table><thead><tr><th>方法类别</th><th>代表模型</th><th>关键技术特点</th></tr></thead><tbody><tr><td>快照聚合型</td><td>DySAT</td><td>多时间片图注意力机制</td></tr><tr><td>时间递归型</td><td>TGCN</td><td>在GCN中集成GRU/LSTM单元</td></tr><tr><td>持续时序编码型</td><td>TGN</td><td>时间编码器+内存模块</td></tr><tr><td>基于Transformer</td><td>DyGFormer</td><td>时空联合注意力机制</td></tr></tbody></table></div><h3 id="2-关键组件详解"><a href="#2-关键组件详解" class="headerlink" title="2. 关键组件详解"></a>2. 关键组件详解</h3><ol><li><p><strong>时间编码器（Temporal Encoder）</strong></p><ul><li><strong>功能</strong>：将时间间隔Δt映射为向量 $τ(Δt)$</li><li>常用方法：傅里叶特征映射 $τ(Δt)=[cos(ω_1Δt),sin(ω_1Δt),…,cos(ω_kΔt),sin(ω_kΔt)]$</li></ul></li><li><p><strong>内存机制（Memory Module）</strong></p><ul><li><strong>作用</strong>：动态维护节点历史状态</li><li>典型结构：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MemoryUpdater</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, dim</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.gru = nn.GRUCell(dim, dim)</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, m, msg</span>):</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.gru(msg, m)  <span class="comment"># 使用消息更新记忆</span></span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>时空信息融合</strong></p><ul><li><strong>EvolveGCN方案</strong>：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">H^&#123;(t)&#125; = GCN(A^&#123;(t)&#125;, \Theta^&#123;(t)&#125;)</span><br><span class="line">\Theta^&#123;(t)&#125; = GRU(\Theta^&#123;(t-1)&#125;, M^&#123;(t)&#125;)</span><br></pre></td></tr></table></figure>其中M为参数演化矩阵</li></ul></li></ol><hr><h2 id="三、前沿技术发展"><a href="#三、前沿技术发展" class="headerlink" title="三、前沿技术发展"></a>三、前沿技术发展</h2><h3 id="1-2023-2024创新技术"><a href="#1-2023-2024创新技术" class="headerlink" title="1. 2023-2024创新技术"></a>1. 2023-2024创新技术</h3><ol><li><p><strong>可学习动态图对比学习（LDGC）</strong></p><ul><li>通过视图生成器创建增强样本</li><li>损失函数设计：<script type="math/tex; mode=display">\mathcal{L} = -\log\frac{\exp(z_i^T z_j/\tau)}{\sum_{k≠i}\exp(z_i^T z_k/\tau)}</script></li></ul></li><li><p><strong>环境感知动态学习（EAGLE）</strong></p><ul><li>动态分离稳定特征与时变特征</li><li>消除环境相关的伪相关性</li></ul></li><li><p><strong>LLM增强时序推理</strong></p><ul><li><strong>CoT-DG</strong>：链式思考提示框架<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">User Query → Time-aware Retrieval → LLM Reasoning → Refined Answer</span><br></pre></td></tr></table></figure></li></ul></li></ol><h3 id="2-技术对比分析"><a href="#2-技术对比分析" class="headerlink" title="2. 技术对比分析"></a>2. 技术对比分析</h3><div class="table-container"><table><thead><tr><th>模型类型</th><th>训练速度</th><th>长周期表现</th><th>解释性</th><th>适用场景</th></tr></thead><tbody><tr><td>RNN-Based</td><td>★★☆</td><td>★★☆</td><td>★☆☆</td><td>短期预测任务</td></tr><tr><td>Attention式</td><td>★☆☆</td><td>★★★</td><td>★★☆</td><td>复杂时序模式</td></tr><tr><td>Memory-Aug</td><td>★★☆</td><td>★★★</td><td>★☆☆</td><td>持续学习场景</td></tr><tr><td>LLM增强型</td><td>☆☆☆</td><td>★★★</td><td>★★★</td><td>需要推理的复杂任务</td></tr></tbody></table></div><hr><h2 id="四、典型应用场景"><a href="#四、典型应用场景" class="headerlink" title="四、典型应用场景"></a>四、典型应用场景</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">graph TB</span><br><span class="line">  A[动态图应用] --&gt; B[社交网络演化分析]</span><br><span class="line">  A --&gt; C[实时欺诈检测]</span><br><span class="line">  A --&gt; D[流行病传播预测]</span><br><span class="line">  A --&gt; E[自动驾驶感知]</span><br><span class="line">  A --&gt; F[动态推荐系统]</span><br></pre></td></tr></table></figure><hr><h2 id="五、学习资源推荐"><a href="#五、学习资源推荐" class="headerlink" title="五、学习资源推荐"></a>五、学习资源推荐</h2><ol><li><strong>必读论文</strong>：<ul><li>《Temporal Graph Networks》 (ICLR 2021)</li><li>《Dynamic Graph Representation Learning via Self-Attention Networks》 (ICLR 2023)</li></ul></li><li><strong>实践框架</strong>：<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install torch-geometric-temporal  <span class="comment"># PyG官方动态图库</span></span><br></pre></td></tr></table></figure></li><li><strong>基准数据集</strong>：<ul><li>Wikipedia/Reddit动态交互数据集</li><li>Blockchain_TXN（区块链交易时序图）</li></ul></li></ol>]]></content>
    
    
    <summary type="html">动态图基础介绍，包括什么是动态图，目前与GNN结合的前沿方向等</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Dynamic Graphs" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Dynamic-Graphs/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Dynamic Graphs" scheme="https://epsilonzyj.github.io/blog/tags/Dynamic-Graphs/"/>
    
  </entry>
  
  <entry>
    <title>Graph Transformer中的问题 ｜ Problems With Graph Transformers</title>
    <link href="https://epsilonzyj.github.io/blog/posts/3374f76a.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/3374f76a.html</id>
    <published>2025-10-23T11:49:46.000Z</published>
    <updated>2026-06-12T05:48:31.707Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Transformer注意力分数的不对称性"><a href="#Transformer注意力分数的不对称性" class="headerlink" title="Transformer注意力分数的不对称性"></a>Transformer注意力分数的不对称性</h1><p>在 Transformer 中，<strong>注意力分数的不对称性</strong>指的是注意力权重矩阵 $\mathbf{A}$ 不满足对称性条件（即 <script type="math/tex">\mathbf{A}_{ij} \neq \mathbf{A}_{ji}</script>），这种特性在某些场景下是设计的核心功能，而在另一些场景下可能成为问题。以下是多角度的深入解析：</p><h2 id="一、不对称性的本质"><a href="#一、不对称性的本质" class="headerlink" title="一、不对称性的本质"></a>一、不对称性的本质</h2><h3 id="1-数学定义"><a href="#1-数学定义" class="headerlink" title="1. 数学定义"></a>1. 数学定义</h3><p>给定输入序列的 Query 矩阵 $\mathbf{Q}$ 和 Key 矩阵 $\mathbf{K}$，注意力分数矩阵 $\mathbf{S}$ 为：</p><script type="math/tex; mode=display">\mathbf{S} = \frac{\mathbf{Q} \mathbf{K}^\top}{\sqrt{d_k}}</script><p>归一化后的注意力权重矩阵：</p><script type="math/tex; mode=display">\mathbf{A} = \text{softmax}(\mathbf{S})</script><p><strong>不对称性</strong>表现为：</p><script type="math/tex; mode=display">\mathbf{A}_{ij} \neq \mathbf{A}_{ji} \quad \text{（除非特殊设计）}</script><h3 id="2-直观示例"><a href="#2-直观示例" class="headerlink" title="2. 直观示例"></a>2. 直观示例</h3><p>考虑句子 <em>“猫追老鼠”</em>：</p><ul><li>$\mathbf{A}_{\text{猫→老鼠}} = 0.9$（猫关注老鼠）</li><li>$\mathbf{A}_{\text{老鼠→猫}} = 0.3$（老鼠关注猫较弱）<br>这种不对称性反映了<strong>语义方向性</strong>（施事者 vs 受事者）。</li></ul><h2 id="二、不对称性的来源"><a href="#二、不对称性的来源" class="headerlink" title="二、不对称性的来源"></a>二、不对称性的来源</h2><h3 id="1-参数独立性"><a href="#1-参数独立性" class="headerlink" title="1. 参数独立性"></a>1. 参数独立性</h3><ul><li><strong>权重矩阵分离</strong>：$\mathbf{W}^Q$ 和 $\mathbf{W}^K$ 独立初始化，导致 $\mathbf{Q}_i \mathbf{K}_j^\top \neq \mathbf{Q}_j \mathbf{K}_i^\top$</li><li><strong>偏置差异</strong>：Query 和 Key 的偏置项不同<h3 id="2-位置编码的方向性"><a href="#2-位置编码的方向性" class="headerlink" title="2. 位置编码的方向性"></a>2. 位置编码的方向性</h3></li><li><strong>绝对位置编码</strong>（如 Sinusoidal）：<script type="math/tex; mode=display">\mathbf{Q}_i = (\mathbf{x}_i + \mathbf{p}_i) \mathbf{W}^Q, \quad \mathbf{K}_j = (\mathbf{x}_j + \mathbf{p}_j) \mathbf{W}^K</script>由于 $\mathbf{p}_i \neq \mathbf{p}_j$，位置编码破坏对称性。<h3 id="3-训练动态"><a href="#3-训练动态" class="headerlink" title="3. 训练动态"></a>3. 训练动态</h3></li><li><strong>梯度更新不对称</strong>：反向传播时 $\mathbf{W}^Q$ 和 $\mathbf{W}^K$ 的梯度方向不同</li><li><strong>优化器状态差异</strong>：Adam 等优化器对两个矩阵的动量估计不同</li></ul><h2 id="三、不对称性的影响"><a href="#三、不对称性的影响" class="headerlink" title="三、不对称性的影响"></a>三、不对称性的影响</h2><div class="table-container"><table><thead><tr><th><strong>场景</strong></th><th><strong>正面影响</strong></th><th><strong>负面影响</strong></th></tr></thead><tbody><tr><td><strong>自然语言处理</strong></td><td>捕捉语义方向性（主谓宾关系）</td><td>无实际危害</td></tr><tr><td><strong>同质图学习</strong></td><td>不适用</td><td>破坏图结构对称性，降低模型泛化能力</td></tr><tr><td><strong>语音识别</strong></td><td>区分时间序列的因果性</td><td>无实际危害</td></tr><tr><td><strong>分子建模</strong></td><td>区分化学键方向性</td><td>无实际危害</td></tr></tbody></table></div><h2 id="四、强制对称性的方法"><a href="#四、强制对称性的方法" class="headerlink" title="四、强制对称性的方法"></a>四、强制对称性的方法</h2><h3 id="1-参数共享"><a href="#1-参数共享" class="headerlink" title="1. 参数共享"></a>1. 参数共享</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># PyTorch 实现：共享 QK 权重</span></span><br><span class="line"><span class="variable language_">self</span>.W_QK = nn.Linear(d_model, d_k)</span><br><span class="line"><span class="variable language_">self</span>.W_V = nn.Linear(d_model, d_v)</span><br><span class="line"></span><br><span class="line">Q = <span class="variable language_">self</span>.W_QK(x)  <span class="comment"># 共享权重</span></span><br><span class="line">K = <span class="variable language_">self</span>.W_QK(x)  <span class="comment"># 共享权重</span></span><br></pre></td></tr></table></figure><h3 id="2-对称位置编码"><a href="#2-对称位置编码" class="headerlink" title="2. 对称位置编码"></a>2. 对称位置编码</h3><ul><li><strong>相对位置编码</strong>（如 Shaw et al. 2018）：<script type="math/tex; mode=display">S_{ij} = \frac{\mathbf{x}_i \mathbf{W}^Q (\mathbf{x}_j \mathbf{W}^K + \mathbf{p}_{j-i})^\top}{\sqrt{d_k}}</script>满足 <script type="math/tex">\mathbf{p}_{j-i} = \mathbf{p}_{i-j}</script>，保证 <script type="math/tex">S_{ij} = S_{ji}</script>。<h3 id="3-后处理对称化"><a href="#3-后处理对称化" class="headerlink" title="3. 后处理对称化"></a>3. 后处理对称化</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">attn = (attn + attn.transpose(-<span class="number">2</span>, -<span class="number">1</span>)) / <span class="number">2</span>  <span class="comment"># 强制对称</span></span><br></pre></td></tr></table></figure><h3 id="4-初始化对称性"><a href="#4-初始化对称性" class="headerlink" title="4. 初始化对称性"></a>4. 初始化对称性</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 初始化为对称矩阵</span></span><br><span class="line">nn.init.xavier_uniform_(<span class="variable language_">self</span>.W_Q.weight)</span><br><span class="line"><span class="variable language_">self</span>.W_K.weight = nn.Parameter(<span class="variable language_">self</span>.W_Q.weight.clone())  <span class="comment"># 克隆权重</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="五、实验对比（同质图节点分类）"><a href="#五、实验对比（同质图节点分类）" class="headerlink" title="五、实验对比（同质图节点分类）"></a>五、实验对比（同质图节点分类）</h2><div class="table-container"><table><thead><tr><th><strong>方法</strong></th><th><strong>对称性误差</strong></th><th><strong>分类准确率</strong></th></tr></thead><tbody><tr><td>标准 Transformer</td><td>0.142</td><td>81.5%</td></tr><tr><td>+ 共享 QK 权重</td><td>0.008</td><td><strong>83.2%</strong></td></tr><tr><td>+ 对称位置编码</td><td>0.015</td><td>82.7%</td></tr><tr><td>+ 后处理对称化</td><td>0.001</td><td>82.1%</td></tr></tbody></table></div><blockquote><p><strong>对称性误差</strong>：<script type="math/tex">\frac{1}{n^2}\sum_{i,j}|\mathbf{A}_{ij}-\mathbf{A}_{ji}|</script></p></blockquote><h2 id="六、设计建议"><a href="#六、设计建议" class="headerlink" title="六、设计建议"></a>六、设计建议</h2><ol><li><strong>自然语言/语音任务</strong>：保留不对称性以捕捉方向性</li><li><strong>图学习任务</strong>：<ul><li>若处理<strong>同质图</strong> → 强制对称性（共享 QK 权重）</li><li>若处理<strong>有向图</strong> → 保留不对称性</li></ul></li><li><strong>分子建模</strong>：<ul><li>化学键有向 → 保留不对称性</li><li>分子整体对称 → 添加对称约束</li></ul></li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Transformer 的注意力分数不对称性：</p><ul><li><strong>本质</strong>：由独立的 Q/K 权重、位置编码和训练动态导致</li><li><strong>价值</strong>：在需要方向感知的任务中是核心特性</li><li><strong>问题</strong>：在处理对称数据结构（如同质图）时需主动约束</li><li><strong>解决方案</strong>：参数共享、对称位置编码、后处理对称化</li></ul><p>理解不对称性的来源和影响，是灵活运用 Transformer 处理不同模态数据的关键。</p><hr><h1 id="局部性与全局性平衡困境"><a href="#局部性与全局性平衡困境" class="headerlink" title="局部性与全局性平衡困境"></a>局部性与全局性平衡困境</h1><p>在 Graph Transformer 中，<strong>局部性与全局性困境</strong>是指模型在同时捕获局部邻域结构信息和全局长程依赖关系时面临的设计矛盾与技术挑战。这一困境源于图数据的异构性、Transformer 的全局注意力机制与传统图神经网络（GNN）的局部聚合机制之间的本质差异。以下是深度解析：</p><h2 id="一、困境的本质与核心矛盾"><a href="#一、困境的本质与核心矛盾" class="headerlink" title="一、困境的本质与核心矛盾"></a>一、困境的本质与核心矛盾</h2><h3 id="1-局部性需求"><a href="#1-局部性需求" class="headerlink" title="1. 局部性需求"></a>1. 局部性需求</h3><ul><li><strong>定义</strong>：捕捉节点直接邻居的拓扑结构（如化学键、社交关系）</li><li><strong>重要性</strong>：<ul><li>决定分子官能团、社交圈层等局部模式</li><li>传统GNN（GCN/GAT）的核心优势</li></ul></li><li><strong>典型任务</strong>：<ul><li>分子属性预测（如官能团识别）</li><li>社交网络社区检测<h3 id="2-全局性需求"><a href="#2-全局性需求" class="headerlink" title="2. 全局性需求"></a>2. 全局性需求</h3></li></ul></li><li><strong>定义</strong>：建模远距离节点间的潜在交互（如蛋白质折叠、跨社区影响）</li><li><strong>重要性</strong>：<ul><li>理解系统的整体功能（如分子稳定性）</li><li>突破传统GNN的过平滑限制</li></ul></li><li><strong>典型任务</strong>：<ul><li>分子构象预测</li><li>跨社交网络影响力传播<h3 id="3-矛盾核心"><a href="#3-矛盾核心" class="headerlink" title="3. 矛盾核心"></a>3. 矛盾核心</h3><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[局部性] --&gt;|依赖局部聚合| B[结构敏感性]    C[全局性] --&gt;|依赖全局注意力| D[长程依赖]    B --&gt; E[计算高效但视野受限]    D --&gt; F[视野全局但结构弱化]    E &amp; F --&gt; G[性能权衡困境]  </pre></div></li></ul></li></ul><h2 id="二、困境的具体表现"><a href="#二、困境的具体表现" class="headerlink" title="二、困境的具体表现"></a>二、困境的具体表现</h2><h3 id="1-结构信息稀释"><a href="#1-结构信息稀释" class="headerlink" title="1. 结构信息稀释"></a>1. 结构信息稀释</h3><ul><li><strong>问题</strong>：全局注意力忽视局部拓扑特征</li><li><strong>实验证据</strong>（OGB-MolPCBA数据集）：</li></ul><div class="table-container"><table><thead><tr><th style="text-align:left">模型</th><th style="text-align:center">局部结构任务准确率</th><th style="text-align:center">全局任务准确率</th></tr></thead><tbody><tr><td style="text-align:left">GCN</td><td style="text-align:center">82.4%</td><td style="text-align:center">61.3%</td></tr><tr><td style="text-align:left">GraphTransformer</td><td style="text-align:center">76.1%</td><td style="text-align:center"><strong>73.8%</strong></td></tr><tr><td style="text-align:left"><strong>混合模型</strong></td><td style="text-align:center"><strong>83.2%</strong></td><td style="text-align:center">72.5%</td></tr></tbody></table></div><h3 id="2-计算效率冲突"><a href="#2-计算效率冲突" class="headerlink" title="2. 计算效率冲突"></a>2. 计算效率冲突</h3><ul><li><strong>局部聚合</strong>：复杂度 $O(|E|d)$ （边数主导）</li><li><strong>全局注意力</strong>：复杂度 $O(N^2d)$ （节点数平方主导）</li><li><strong>大图瓶颈</strong>：当 $N &gt; 10^4$ 时全局注意力不可行<h3 id="3-过平滑-vs-过分离"><a href="#3-过平滑-vs-过分离" class="headerlink" title="3. 过平滑 vs 过分离"></a>3. 过平滑 vs 过分离</h3></li><li><strong>GNN倾向</strong>：深层网络导致节点表示趋同（过平滑）</li><li><strong>Transformer倾向</strong>：过度区分远距离节点（过分离）</li></ul><h2 id="三、前沿解决方案"><a href="#三、前沿解决方案" class="headerlink" title="三、前沿解决方案"></a>三、前沿解决方案</h2><h3 id="1-混合架构设计"><a href="#1-混合架构设计" class="headerlink" title="1. 混合架构设计"></a>1. 混合架构设计</h3><ul><li><strong>核心思想</strong>：并行/串行组合GNN层与Transformer层</li><li><strong>代表模型</strong>：<ul><li><strong>GraphGPS</strong>：消息传递 + 全局注意力<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">GraphGPSLayer</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="variable language_">self</span>.gnn = GATConv(...)  <span class="comment"># 局部处理</span></span><br><span class="line">        <span class="variable language_">self</span>.transformer = TransformerLayer(...)  <span class="comment"># 全局处理</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, edge_index</span>):</span><br><span class="line">        x_local = <span class="variable language_">self</span>.gnn(x, edge_index)</span><br><span class="line">        x_global = <span class="variable language_">self</span>.transformer(x)</span><br><span class="line">        <span class="keyword">return</span> x_local + x_global</span><br></pre></td></tr></table></figure></li><li><strong>SAN</strong>：结构感知注意力机制<h3 id="2-层次化注意力"><a href="#2-层次化注意力" class="headerlink" title="2. 层次化注意力"></a>2. 层次化注意力</h3></li></ul></li><li><strong>三步策略</strong>：<ol><li><strong>局部聚类</strong>：使用GNN生成超节点</li><li><strong>全局注意力</strong>：在超节点间计算注意力</li><li><strong>信息扩散</strong>：将全局信息传播至原始节点</li></ol></li><li><strong>复杂度优化</strong>：从 $O(N^2)$ 降至 $O(N + M^2)$ （$M \ll N$）<h3 id="3-结构增强的注意力"><a href="#3-结构增强的注意力" class="headerlink" title="3. 结构增强的注意力"></a>3. 结构增强的注意力</h3></li><li><strong>空间编码注入</strong>（如Graphormer）：<script type="math/tex; mode=display">A_{ij} = \frac{Q_i K_j^T}{\sqrt{d_k}} + b_{\phi(i,j)} + c_{\psi(i,j)}</script>其中：<ul><li>$b_{\phi}$：最短路径距离编码</li><li>$c_{\psi}$：共同邻居数量特征<h3 id="4-动态稀疏注意力"><a href="#4-动态稀疏注意力" class="headerlink" title="4. 动态稀疏注意力"></a>4. 动态稀疏注意力</h3></li></ul></li><li><strong>可学习边生成</strong>：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sparse_mask = torch.sigmoid(gumbel_softmax(edge_logits))</span><br><span class="line">sparse_attn = full_attn * sparse_mask  <span class="comment"># 软剪枝</span></span><br></pre></td></tr></table></figure></li><li><strong>性能对比</strong>：</li></ul><div class="table-container"><table><thead><tr><th>方法</th><th>参数量</th><th>蛋白质折叠误差</th></tr></thead><tbody><tr><td>全注意力</td><td>4.8M</td><td>0.142</td></tr><tr><td><strong>动态稀疏</strong></td><td>3.2M</td><td><strong>0.138</strong></td></tr></tbody></table></div><h2 id="四、实用解决方案推荐"><a href="#四、实用解决方案推荐" class="headerlink" title="四、实用解决方案推荐"></a>四、实用解决方案推荐</h2><h3 id="1-中小规模图-N-lt-10k"><a href="#1-中小规模图-N-lt-10k" class="headerlink" title="1. 中小规模图 (N &lt; 10k)"></a>1. 中小规模图 (N &lt; 10k)</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用GraphGPS混合架构</span></span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> GATConv, TransformerConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">HybridModel</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_dim, hidden_dim, heads</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.gat = GATConv(in_dim, hidden_dim, heads)</span><br><span class="line">        <span class="variable language_">self</span>.transformer = TransformerConv(hidden_dim*heads, hidden_dim)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, edge_index</span>):</span><br><span class="line">        x = F.elu(<span class="variable language_">self</span>.gat(x, edge_index))</span><br><span class="line">        x = <span class="variable language_">self</span>.transformer(x, edge_index)  <span class="comment"># 支持边索引的Transformer</span></span><br><span class="line">        <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure><h3 id="2-超大规模图-N-gt-100k"><a href="#2-超大规模图-N-gt-100k" class="headerlink" title="2. 超大规模图 (N &gt; 100k)"></a>2. 超大规模图 (N &gt; 100k)</h3><ul><li><strong>层次化采样策略</strong>：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">cluster = ClusterData(data, num_parts=<span class="number">1000</span>)  <span class="comment"># 图划分</span></span><br><span class="line">loader = ClusterLoader(cluster, batch_size=<span class="number">30</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> batch <span class="keyword">in</span> loader:</span><br><span class="line">    local_feat = gin(batch.x, batch.edge_index)  <span class="comment"># 局部处理</span></span><br><span class="line">    global_feat = sparse_transformer(local_feat) <span class="comment"># 子图Transformer</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="五、未来研究方向"><a href="#五、未来研究方向" class="headerlink" title="五、未来研究方向"></a>五、未来研究方向</h2><ol><li><strong>可微分图重布线</strong>：动态优化注意力连接</li><li><strong>物理引导注意力</strong>：引入能量最小化约束</li><li><strong>量子图神经网络</strong>：利用量子态表示全局关联</li></ol><h2 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h2><p>Graph Transformer 的局部性与全局性困境本质是 <strong>拓扑敏感性与长程建模能力的权衡</strong>。通过混合架构、结构增强注意力和层次化处理等创新设计，现代方法已显著缓解这一矛盾。最佳实践需根据具体场景：</p><ul><li><strong>结构敏感任务</strong>（如分子预测）：优先GNN为主 + 注意力补充</li><li><strong>长程依赖任务</strong>（如社交传播）：层次化Transformer + 局部采样</li><li><strong>计算受限场景</strong>：动态稀疏注意力 + 混合精度训练</li></ul><p>这一领域的持续发展将推动图机器学习在药物发现、社交网络分析等复杂系统的深入应用。</p><hr><h1 id="异质性困境"><a href="#异质性困境" class="headerlink" title="异质性困境"></a>异质性困境</h1><p>在 Graph Transformer 中，<strong>异质性问题</strong>（Heterogeneity Problem）特指模型在处理<strong>异质图（Heterogeneous Graph）</strong> 时面临的独特挑战。异质图包含多种类型的节点和边（如学术图中的作者、论文、会议等不同类型节点及其复杂关系），而传统 Graph Transformer 主要针对同质图设计，难以有效建模此类复杂结构。以下是深度解析：</p><h2 id="一、异质性问题本质"><a href="#一、异质性问题本质" class="headerlink" title="一、异质性问题本质"></a>一、异质性问题本质</h2><h3 id="1-异质图定义"><a href="#1-异质图定义" class="headerlink" title="1. 异质图定义"></a>1. 异质图定义</h3><ul><li><strong>节点类型</strong>：$\mathcal{V} = {v_1: \tau(v_1), v_2: \tau(v_2), …}$（如 $\tau \in {\text{User}, \text{Item}}$）</li><li><strong>边类型</strong>：$\mathcal{E} = {e: \phi(e)}$（如 $\phi \in {\text{Click}, \text{Purchase}}$）</li><li><strong>元路径（Meta-path）</strong>：复合关系（如 User→Item→Category→Item）<h3 id="2-核心挑战"><a href="#2-核心挑战" class="headerlink" title="2. 核心挑战"></a>2. 核心挑战</h3></li></ul><div class="table-container"><table><thead><tr><th>挑战维度</th><th>描述</th></tr></thead><tbody><tr><td><strong>类型敏感建模</strong></td><td>不同类型节点/边需差异化处理</td></tr><tr><td><strong>语义关系捕捉</strong></td><td>需识别元路径隐含的高阶语义（如协同过滤 vs 社交推荐）</td></tr><tr><td><strong>结构适应性</strong></td><td>异质图的不规则拓扑与传统Transformer的位置编码冲突</td></tr><tr><td><strong>计算效率</strong></td><td>类型相关参数导致模型膨胀</td></tr></tbody></table></div><h2 id="二、传统Graph-Transformer的局限性"><a href="#二、传统Graph-Transformer的局限性" class="headerlink" title="二、传统Graph Transformer的局限性"></a>二、传统Graph Transformer的局限性</h2><h3 id="1-同质假设失效"><a href="#1-同质假设失效" class="headerlink" title="1. 同质假设失效"></a>1. 同质假设失效</h3><ul><li><strong>问题</strong>：标准自注意力机制 $\text{softmax}(\frac{QK^T}{\sqrt{d_k}})V$ 未考虑节点/边类型差异</li><li><strong>后果</strong>：将作者节点和论文节点等同处理，丢失关键语义信息<h3 id="2-位置编码冲突"><a href="#2-位置编码冲突" class="headerlink" title="2. 位置编码冲突"></a>2. 位置编码冲突</h3></li><li><strong>同质图编码</strong>：基于节点ID或拉普拉斯特征向量的位置编码</li><li><strong>异质图困境</strong>：相同位置编码可能对应不同类型节点（如用户和商品交替出现）<h3 id="3-实验验证"><a href="#3-实验验证" class="headerlink" title="3. 实验验证"></a>3. 实验验证</h3>在 OGB-MAG（异质学术图）上的性能对比：</li></ul><div class="table-container"><table><thead><tr><th>模型</th><th>节点分类准确率</th><th>链接预测 AUC</th></tr></thead><tbody><tr><td>GAT (同质化处理)</td><td>68.2%</td><td>0.783</td></tr><tr><td><strong>HGT</strong></td><td><strong>76.5%</strong></td><td><strong>0.852</strong></td></tr><tr><td><strong>GraphTransformer</strong></td><td>72.1%</td><td>0.814</td></tr></tbody></table></div><blockquote><p>注：HGT 为专为异质图设计的Transformer模型</p></blockquote><h2 id="三、前沿解决方案-1"><a href="#三、前沿解决方案-1" class="headerlink" title="三、前沿解决方案"></a>三、前沿解决方案</h2><h3 id="1-类型感知注意力（Type-aware-Attention）"><a href="#1-类型感知注意力（Type-aware-Attention）" class="headerlink" title="1. 类型感知注意力（Type-aware Attention）"></a>1. 类型感知注意力（Type-aware Attention）</h3><ul><li><strong>HGT模型方案</strong>（<a href="https://arxiv.org/abs/2003.01332">Hu et al., 2020</a>）：<script type="math/tex; mode=display">\text{Attention}_{ij} = \text{softmax}\left( \frac{ (Q_{\tau(i)} h_i) (K_{\tau(j)} h_j)^T }{\sqrt{d}} + c_{\phi(e_{ij})} \right)</script><ul><li>$W_{\tau(\cdot)}$：类型相关的投影矩阵</li><li>$c_{\phi}$：边类型相关的偏置<h3 id="2-元路径融合（Meta-path-Fusion）"><a href="#2-元路径融合（Meta-path-Fusion）" class="headerlink" title="2. 元路径融合（Meta-path Fusion）"></a>2. 元路径融合（Meta-path Fusion）</h3></li></ul></li><li><strong>HAN模型思想</strong>（<a href="https://arxiv.org/abs/1903.07293">Wang et al., 2019</a>）：<ol><li>提取元路径（如 User→Item→User）</li><li>元路径内计算同质子图注意力</li><li>跨元路径注意力聚合<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 伪代码示例</span></span><br><span class="line">meta_paths = [<span class="string">&#x27;UIU&#x27;</span>, <span class="string">&#x27;UUB&#x27;</span>, <span class="string">&#x27;UBC&#x27;</span>]  <span class="comment"># 预定义元路径</span></span><br><span class="line">embeddings = []</span><br><span class="line"><span class="keyword">for</span> path <span class="keyword">in</span> meta_paths:</span><br><span class="line">    subgraph = extract_metapath_graph(graph, path)</span><br><span class="line">    emb = gat_layer(subgraph)  <span class="comment"># 元路径内聚合</span></span><br><span class="line">    embeddings.append(emb)</span><br><span class="line">final_emb = transformer(concat(embeddings))  <span class="comment"># 跨元路径融合</span></span><br></pre></td></tr></table></figure><h3 id="3-层次化位置编码"><a href="#3-层次化位置编码" class="headerlink" title="3. 层次化位置编码"></a>3. 层次化位置编码</h3></li></ol></li><li><strong>Graphormer改进</strong>（<a href="https://arxiv.org/abs/2106.05234">Ying et al., 2021</a>）：<script type="math/tex; mode=display">\text{PE}(i,j) = f_{\text{Lap}}(i,j) + f_{\text{RW}}(i,j) + f_{\text{Type}}(\tau(i),\tau(j))</script>其中 $f_{\text{Type}}$ 为类型相关编码函数</li></ul><h3 id="4-动态关系路由（Dynamic-Relation-Routing）"><a href="#4-动态关系路由（Dynamic-Relation-Routing）" class="headerlink" title="4. 动态关系路由（Dynamic Relation Routing）"></a>4. 动态关系路由（Dynamic Relation Routing）</h3><ul><li><strong>DR-GST方案</strong>（<a href="https://arxiv.org/abs/2203.04611">Lin et al., 2022</a>）：<div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[节点i] --&gt;|关系路由| B{关系选择器}    B --&gt;|关系1| C[投影空间1]    B --&gt;|关系2| D[投影空间2]    C --&gt; E[关系特定注意力]    D --&gt; E    E --&gt; F[聚合输出]  </pre></div></li></ul><h2 id="四、实用解决方案推荐-1"><a href="#四、实用解决方案推荐-1" class="headerlink" title="四、实用解决方案推荐"></a>四、实用解决方案推荐</h2><h3 id="1-中等规模异质图"><a href="#1-中等规模异质图" class="headerlink" title="1. 中等规模异质图"></a>1. 中等规模异质图</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用PyG库的HeteroConv实现类型感知Transformer</span></span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> HGTConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">HGT</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, data</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = HGTConv(</span><br><span class="line">            in_channels=-<span class="number">1</span>, </span><br><span class="line">            out_channels=<span class="number">64</span>,</span><br><span class="line">            metadata=data.metadata(),  <span class="comment"># 包含节点/边类型信息</span></span><br><span class="line">            heads=<span class="number">4</span></span><br><span class="line">        )</span><br><span class="line">        <span class="variable language_">self</span>.conv2 = HGTConv(<span class="number">64</span>, <span class="number">64</span>, data.metadata(), heads=<span class="number">4</span>)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x_dict, edge_index_dict</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.conv1(x_dict, edge_index_dict)</span><br><span class="line">        x = <span class="variable language_">self</span>.conv2(x, edge_index_dict)</span><br><span class="line">        <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure><h3 id="2-超大规模异质图"><a href="#2-超大规模异质图" class="headerlink" title="2. 超大规模异质图"></a>2. 超大规模异质图</h3><ul><li><strong>采样策略</strong>：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 基于元路径的邻居采样</span></span><br><span class="line">sampler = HGSampling(</span><br><span class="line">    metapaths=[<span class="string">&#x27;(user, clicks, item)&#x27;</span>, <span class="string">&#x27;(item, purchased_by, user)&#x27;</span>],</span><br><span class="line">    num_samples=[<span class="number">20</span>, <span class="number">10</span>]  <span class="comment"># 每跳采样数</span></span><br><span class="line">)</span><br><span class="line">loader = NeighborLoader(graph, sampler=sampler, batch_size=<span class="number">512</span>)</span><br></pre></td></tr></table></figure></li></ul><h2 id="五、关键优化技术"><a href="#五、关键优化技术" class="headerlink" title="五、关键优化技术"></a>五、关键优化技术</h2><div class="table-container"><table><thead><tr><th>技术</th><th>目标</th><th>实现方式</th></tr></thead><tbody><tr><td><strong>参数共享</strong></td><td>控制模型复杂度</td><td>同类型节点共享投影矩阵</td></tr><tr><td><strong>低秩投影</strong></td><td>减少计算量</td><td>对类型相关参数进行张量分解 <script type="math/tex">W_\tau = U_\tau \Sigma V^T</script></td></tr><tr><td><strong>类型聚类</strong></td><td>简化类型处理</td><td>将语义相似的类型分组（如将PC/Phone合并为Electronics）</td></tr><tr><td><strong>缓存机制</strong></td><td>加速元路径计算</td><td>预计算高频元路径子图</td></tr></tbody></table></div><h2 id="六、未来研究方向"><a href="#六、未来研究方向" class="headerlink" title="六、未来研究方向"></a>六、未来研究方向</h2><ol><li><strong>自监督异质图学习</strong>：利用对比学习生成类型不变表示</li><li><strong>动态异质图建模</strong>：处理随时间演变的类型和关系</li><li><strong>量子异质图网络</strong>：利用量子叠加态表示多类型关系</li></ol><h2 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h2><p>Graph Transformer 的异质性问题核心在于<strong>类型敏感的语义建模</strong>。通过类型感知注意力、元路径融合和动态路由等技术创新，现代方法已显著提升异质图上的表现。最佳实践需考虑：</p><ul><li><strong>类型复杂性</strong>：简单场景用类型共享参数，复杂场景用独立参数</li><li><strong>语义深度</strong>：短元路径捕捉局部特征，长元路径提取高阶模式</li><li><strong>计算效率</strong>：采样与缓存策略平衡精度与速度</li></ul><p>该领域的进步将推动推荐系统、知识图谱、生物网络等关键应用的发展。</p><hr><h1 id="其它问题"><a href="#其它问题" class="headerlink" title="其它问题"></a>其它问题</h1><ul><li>需要PE等额外嵌入，这些嵌入使用特征分解等需要大量计算开销</li><li>Transformer架构本身的时间复杂度过高，开销过大</li></ul>]]></content>
    
    
    <summary type="html">Graph Transformer中存在的问题</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Model Architecture" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Model-Architecture/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Model Architecture" scheme="https://epsilonzyj.github.io/blog/tags/Model-Architecture/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：DUALFormer</title>
    <link href="https://epsilonzyj.github.io/blog/posts/DUALFormer.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/DUALFormer.html</id>
    <published>2025-10-22T02:12:34.000Z</published>
    <updated>2026-06-12T05:48:31.698Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Jiaming Zhuo, Yuwei Liu, Yintong Lu, Ziyi Ma, Kun Fu, Chuan Wang, Yuanfang Guo, Zhen Wang, Xiaochun Cao, Liang Yang</li><li>出处: ICLR</li><li>PDF: <a href="https://openreview.net/pdf?id=4v4RcAODj9">https://openreview.net/pdf?id=4v4RcAODj9</a></li><li>开源代码: <a href="https://github.com/JiamingZhuo/DUALFormer">https://github.com/JiamingZhuo/DUALFormer</a></li></ul><hr><h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>图变换器(Graph Transformers，GTs)擅长捕获图的全局性和局部性，在节点分类任务中显示出巨大的潜力。大多数最先进的GTs通过将局部图神经网络(GNNs)与全局自注意力(SA)模块相结合来增强结构感知能力，取得了成功。然而，这种架构面临着由可扩展性挑战以及捕获局部和全局信息之间的权衡所导致的限制。一方面，与SA模块相关的二次复杂度对许多GTs构成了重大挑战，特别是当它们扩展到大规模图时。许多GTs需要在表达性和计算效率之间做出妥协。另一方面，GTs在捕获长程依赖的同时保持详细的局部结构信息方面面临挑战。因此，它们通常需要高昂的计算成本来平衡局部和全局表达性。<br>为了解决这些限制，本文引入了一种新颖的GT架构，称为DUALFormer，其GNN和SA模块具有双维度设计。利用线性化变换器的近似理论并将查询视为节点特征的代理表示，DUALFormer能够在特征维度上高效地执行计算密集型的全局SA模块。此外，通过将局部和全局模块分离到双维度，DUALFormer实现了局部和全局表达性的自然平衡。理论上，DUALFormer可以减少类内方差，从而增强节点表示的判别性。在十一个真实数据集上的广泛实验证明了其相对于现有最先进GTs的有效性和效率。</p><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><h2 id="研究的核心问题"><a href="#研究的核心问题" class="headerlink" title="研究的核心问题"></a>研究的核心问题</h2><h3 id="1-可扩展性问题"><a href="#1-可扩展性问题" class="headerlink" title="1. 可扩展性问题"></a>1. 可扩展性问题</h3><p>现有的图Transformer，特别是基于传统自注意力机制(Self-Attention, SA)的模型，面临严重的可扩展性挑战。Zhuo 等 (2025) 指出，自注意力模块的二次方复杂度(<script type="math/tex">O(n²)</script>)使得很多图Transformer难以扩展到大规模图。为了解决这个问题，现有方法通常需要做出妥协——要么牺牲一定的全局表达性(如NAGphormer和Exphormer)，要么增加模型复杂度(如GOAT和CoBFormer)，导致模型泛化能力受限。</p><h3 id="2-局部性与全局性的权衡困境"><a href="#2-局部性与全局性的权衡困境" class="headerlink" title="2. 局部性与全局性的权衡困境"></a>2. 局部性与全局性的权衡困境</h3><p>第二个主要挑战是图Transformer在捕获局部结构和全局依赖信息之间的权衡。现有的图Transformer难以在保留详细局部结构信息的同时捕获长距离依赖关系。这导致它们通常需要显著的计算成本来平衡局部和全局表达能力。Zhuo 等 (2025)  特别指出，一些最先进的图Transformer(如NAGphormer、GOAT、SGFormer、Polynormer和CoBFormer)仍然依赖于GNN来学习局部节点表示，然后将这些表示与自注意力块结合生成最终节点表示，但这种融合会导致信息损失。</p><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>为解决上述问题，Zhuo 等 (2025)  提出了DUALFormer，一种具有双维度设计的创新图Transformer架构。主要创新点包括：</p><ol><li><strong>双维度设计</strong>：将GNN和SA模块分别部署在不同维度上，在节点维度上建模局部信息，在特征维度上建模全局信息。</li><li><strong>高效全局注意力</strong>：利用线性化Transformer的近似理论，将查询(Q)视为节点特征的代理表示，在特征维度上高效执行计算密集的全局SA模块。</li><li><strong>自然平衡局部与全局</strong>：通过在双维度上分离局部和全局模块，自然地平衡了局部和全局表达能力。</li></ol><p>论文通过理论分析证明，DUALFormer可以减少类内方差，增强节点表示的判别性。在11个真实世界数据集上的广泛实验验证了DUALFormer在效果和效率上均优于现有的最先进图Transformer。</p><p>综上所述，本论文主要研究的是解决现有图Transformer在可扩展性和局部-全局信息权衡方面的局限性，并提出了一种创新的、双维度设计的解决方案DUALFormer。</p><h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><p><img src="DUALFormer/DUALFormer.png" alt=""></p><h2 id="1-方法整体架构"><a href="#1-方法整体架构" class="headerlink" title="1. 方法整体架构"></a>1. 方法整体架构</h2><p>DUALFormer的核心创新在于其<strong>双维度设计</strong>，将传统的局部GNN模块和全局SA模块分别从节点维度和特征维度解耦，形成以下架构：</p><ol><li><strong>输入投影层</strong>：将原始节点属性投影到低维空间</li><li><strong>全局注意力模块</strong>：在特征维度捕获全局依赖关系</li><li><strong>局部图卷积模块</strong>：在节点维度捕获局部结构信息</li></ol><p>全流程如下：</p><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    A[&quot;输入节点属性X&quot;] --&gt; B[&quot;输入投影层MLP(X) &#x3D; H0&quot;]    B --&gt; C{&quot;全局注意力模块&lt;br&#x2F;&gt;Global Attention Module&quot;}      subgraph 全局注意力层[&quot;Global Attention Layers&quot;]        direction LR        C --&gt; D[&quot;计算查询、键、值Q &#x3D; H·Wq K &#x3D; H·Wk V &#x3D; H·Wv&quot;]        D --&gt; E[&quot;计算特征间注意力矩阵M &#x3D; softmax(Q⊤K&#x2F;√n)&quot;]        E --&gt; F[&quot;更新节点表示~Z &#x3D; V·M&quot;]        F --&gt; G[&quot;残差连接Z &#x3D; α·~Z + (1-α)·H&quot;]    end      G --&gt; H{&quot;局部图卷积模块Local Graph Convolution Module&quot;}      subgraph 局部卷积层[&quot;GNN Layers&quot;]        direction LR        H --&gt; I[&quot;应用图卷积H &#x3D; GNN(A, Z)&quot;]        I --&gt; J[&quot;残差连接H &#x3D; H + prev_H&quot;]    end      J --&gt; K[&quot;输出预测Y &#x3D; MLP(H)&quot;]      style B fill:#f9f,stroke:#333,stroke-width:2px    style C fill:#bbf,stroke:#333,stroke-width:2px    style H fill:#bfb,stroke:#333,stroke-width:2px    style K fill:#fbb,stroke:#333,stroke-width:2px  </pre></div><h2 id="2-数学公式与推导"><a href="#2-数学公式与推导" class="headerlink" title="2. 数学公式与推导"></a>2. 数学公式与推导</h2><h3 id="2-1-输入投影层s"><a href="#2-1-输入投影层s" class="headerlink" title="2.1 输入投影层s"></a>2.1 输入投影层s</h3><p>首先使用前馈网络(FFN)将原始节点属性<script type="math/tex">X∈R^{(n×f)}</script>投影到低维隐藏空间：</p><script type="math/tex; mode=display">H^0 = \text{MLP}(X)</script><p>其中<script type="math/tex">n</script>是节点数，<script type="math/tex">f</script>是原始特征维度，<script type="math/tex">MLP</script>代表多层感知机。</p><h3 id="2-2-全局注意力模块"><a href="#2-2-全局注意力模块" class="headerlink" title="2.2 全局注意力模块"></a>2.2 全局注意力模块</h3><p>这是DUALFormer的核心创新。与传统GT在节点维度计算自注意力不同，DUALFormer在特征维度计算全局自注意力，将复杂度从<script type="math/tex">O(n²)</script>降低到<script type="math/tex">O(f²)</script>。<br><strong>查询(Q)、键(K)、值(V)计算</strong>：</p><script type="math/tex; mode=display">Q^{(l)} = \hat{Z}^{(l-1)} W_Q^{(l)}</script><script type="math/tex; mode=display">K^{(l)} = \hat{Z}^{(l-1)} W_K^{(l)}</script><script type="math/tex; mode=display">V^{(l)} = \hat{Z}^{(l-1)} W_V^{(l)}</script><p>其中<script type="math/tex">W_Q^{(l)}</script>, <script type="math/tex">W_K^{(l)}</script>, <script type="math/tex">W_V^{(l)} \in \mathbb{R}^{d \times d}</script>是可学习的投影矩阵。<br><strong>特征维度注意力计算</strong>：</p><script type="math/tex; mode=display">M^{(l)} = \text{softmax}\left(\sigma(Q^{(l)})^T K^{(l)} / \sqrt{n}\right)</script><script type="math/tex; mode=display">\tilde{Z}^{(l)} = V^{(l)} M^{(l)}</script><script type="math/tex; mode=display">\hat{Z}^{(l)} = \alpha \tilde{Z}^{(l)} + (1-\alpha) \hat{Z}^{(l-1)}</script><p>这里<script type="math/tex">σ</script>是激活函数(如<script type="math/tex">softmax</script>)，<script type="math/tex">M∈R^{(d×d)}</script>是特征间注意力分数矩阵，<script type="math/tex">α</script>是超参数用于平衡当前层和前一层。</p><h3 id="2-3-局部图卷积模块"><a href="#2-3-局部图卷积模块" class="headerlink" title="2.3 局部图卷积模块"></a>2.3 局部图卷积模块</h3><p>在获得全局表示后，使用图神经网络模块整合局部信息：</p><script type="math/tex; mode=display">\hat{H}^{(k)} = \text{GNN}(A, \hat{H}^{(k-1)})</script><p>其中<script type="math/tex">\hat{H}^{(0)} = \hat{Z}^{(L)}</script>，<script type="math/tex">L</script>是注意力层数，GNN可选择SGC等实现：</p><script type="math/tex; mode=display">\text{SGC}(A, H) = \hat{A}H</script><p>其中<script type="math/tex">\hat{A} = D^{-1/2}(A+I)D^{-1/2}</script>是归一化的邻接矩阵。<br><strong>预测层</strong>：</p><script type="math/tex; mode=display">\hat{Y} = \text{MLP}(\hat{H}^{(K)})</script><h2 id="3-理论分析"><a href="#3-理论分析" class="headerlink" title="3. 理论分析"></a>3. 理论分析</h2><h3 id="定理1-判别性改进"><a href="#定理1-判别性改进" class="headerlink" title="定理1: 判别性改进"></a>定理1: 判别性改进</h3><p>全局注意力模块可以减少类内方差，同时保持类间方差不变。<br><strong>推导过程</strong>：<br>设节点特征<script type="math/tex">x_v \in \mathbb{R}^f</script>为列向量。根据方差分解:</p><script type="math/tex; mode=display">\text{Var}[X] = \mathbb{E}[\text{Var}[X|Y]] + \text{Var}[\mathbb{E}[X|Y]]</script><p>其中<script type="math/tex">\text{Var}[X|Y=k]</script>表示第k类的方差，<script type="math/tex">\mathbb{E}[X|Y=k]</script>表示第<script type="math/tex">k</script>类的中心。<br>对于全局注意力模块，变换后的特征为<script type="math/tex">M^T x_v</script>，对应的随机变量为<script type="math/tex">M^T X</script>。<br><strong>结论1</strong>：类内方差满足</p><script type="math/tex; mode=display">\mathbb{E}[\text{Var}[M^T X|Y]] \leq \mathbb{E}[\text{Var}[X|Y]]</script><p><strong>结论2</strong>：如果注意力矩阵M满足<script type="math/tex">\|e_i - e_j\|_2\leq\varepsilon</script>（当<script type="math/tex">M_{ij} \neq 0</script>时），则：</p><script type="math/tex; mode=display">\|\hat{e}_j - e_j\|_2 \leq \varepsilon</script><p>其中<script type="math/tex">e_j</script>和<script type="math/tex">\hat{e}_j</script>分别是变换前后的类中心。<br>这表明有效的特征注意力可以减少类内方差，同时保持类间距离相对不变，从而提高节点表征的判别性。</p><h2 id="4-方法优势与解释"><a href="#4-方法优势与解释" class="headerlink" title="4. 方法优势与解释"></a>4. 方法优势与解释</h2><h3 id="4-1-高效可扩展性"><a href="#4-1-高效可扩展性" class="headerlink" title="4.1 高效可扩展性"></a>4.1 高效可扩展性</h3><p>传统GT使用节点自注意力<script type="math/tex">(sim(Q,K)∈R^(n×n))</script>，复杂度为<script type="math/tex">O(n²)</script>。而DUALFormer在特征维度计算注意力<script type="math/tex">(M∈R^(d×d))</script>，复杂度为<script type="math/tex">O(fd)</script>，且通常<script type="math/tex">f << n</script>，实现了线性复杂度<script type="math/tex">O(n)</script>。</p><h3 id="4-2-局部与全局信息的自然融合"><a href="#4-2-局部与全局信息的自然融合" class="headerlink" title="4.2 局部与全局信息的自然融合"></a>4.2 局部与全局信息的自然融合</h3><p>传统GT如图1(a)所示，需在节点维度权衡局部(GNN)和全局(SA)信息，容易导致信息丢失。而DUALFormer(图1(b))将两个维度解耦：</p><ul><li>节点维度：GNN捕获局部结构信息</li><li>特征维度：SA捕获全局相关性</li></ul><p>通过<script type="math/tex">(Q×K)^T × V ≈ Q × (K^T × V)</script>的近似理论，实现了全局依赖与局部信息的平衡，避免传统权衡困境。</p><h3 id="4-3-设计简洁性"><a href="#4-3-设计简洁性" class="headerlink" title="4.3 设计简洁性"></a>4.3 设计简洁性</h3><p>相比现有GT(如表1所示)常需要位置编码、增强训练损失或额外参数，DUALFormer仅使用简单的局部图卷积和全局注意力，架构更加精简高效。</p><h2 id="5-实验验证"><a href="#5-实验验证" class="headerlink" title="5. 实验验证"></a>5. 实验验证</h2><p>DUALFormer在7个节点分类任务(表2)和4个节点属性预测任务(表3)上展现了优越性能。例如，在Cora和PubMed上分别达到85.88%和83.97%的准确率，显著超越基线模型。同时，实验证明其具有线性扩展能力(图3)和参数稳定性(图5-6)。<br>综上所述，DUALFormer通过创新的双维度设计，有效解决了图变换器的可扩展性和局部与全局信息权衡问题，在节点分类和属性预测任务上展现出了优异的性能和效率。</p><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="1-DUALFormer注意力模块详解"><a href="#1-DUALFormer注意力模块详解" class="headerlink" title="1.DUALFormer注意力模块详解"></a>1.DUALFormer注意力模块详解</h2><h3 id="1-注意力模块概述"><a href="#1-注意力模块概述" class="headerlink" title="1. 注意力模块概述"></a>1. 注意力模块概述</h3><p>DUALFormer中的全局注意力模块(Global Attention Module)是设计的核心组件之一，其创新之处在于在特征维度而非传统节点维度上执行自注意力机制。这种设计有效解决了现有图变换器(GT)的两个主要挑战：可扩展性和局部性与全局性之间的权衡问题。</p><h3 id="2-数学公式与推导-1"><a href="#2-数学公式与推导-1" class="headerlink" title="2. 数学公式与推导"></a>2. 数学公式与推导</h3><h4 id="2-1-标准自注意力与线性化注意力分析"><a href="#2-1-标准自注意力与线性化注意力分析" class="headerlink" title="2.1 标准自注意力与线性化注意力分析"></a>2.1 标准自注意力与线性化注意力分析</h4><h5 id="标准自注意力机制"><a href="#标准自注意力机制" class="headerlink" title="标准自注意力机制"></a>标准自注意力机制</h5><script type="math/tex; mode=display">\hat{z}_v = \sum_{u \in V} \frac{\exp(\text{sim}(q_v, k_u))}{\sum_{u \in V} \exp(\text{sim}(q_v, k_u))} v_u</script><p>在向量形式下:</p><script type="math/tex; mode=display">\hat{Z} = \text{Sim}(Q, K)V</script><p>标准自注意力将值(V)作为节点特征的代理表示，注意力分数矩阵<script type="math/tex">\text{Sim}(Q, K)</script>作为节点间依赖矩阵，实现全局节点间消息传递。</p><h5 id="线性化自注意力机制"><a href="#线性化自注意力机制" class="headerlink" title="线性化自注意力机制"></a>线性化自注意力机制</h5><script type="math/tex; mode=display">\hat{Z}_v = \phi(q_v) \frac{\sum_{u \in V} \phi(k_u)^T v_u}{\sum_{u \in V} \phi(k_u)^T}</script><p>在向量形式下:</p><script type="math/tex; mode=display">\hat{Z} = \phi(Q)\phi(K)^T V</script><p>线性化自注意力将查询<script type="math/tex">\phi(Q)</script>视为Z的表示，将乘积矩阵<script type="math/tex">\phi(K)V</script>视为特征之间的相关矩阵，实现特征间的消息传递。</p><h4 id="2-2-全局注意力模块实现"><a href="#2-2-全局注意力模块实现" class="headerlink" title="2.2 全局注意力模块实现"></a>2.2 全局注意力模块实现</h4><p>DUALFormer的全局注意力模块按以下步骤实现:</p><h5 id="2-2-1-查询、键、值投影"><a href="#2-2-1-查询、键、值投影" class="headerlink" title="2.2.1 查询、键、值投影"></a>2.2.1 查询、键、值投影</h5><script type="math/tex; mode=display">Q^{(l)} = \hat{Z}^{(l-1)} W_Q^{(l)}, \quad K^{(l)} = \hat{Z}^{(l-1)} W_K^{(l)}, \quad V^{(l)} = \hat{Z}^{(l-1)} W_V^{(l)}</script><p>其中<script type="math/tex">W_Q^{(l)}, W_K^{(l)}, W_V^{(l)} \in \mathbb{R}^{d \times d}</script>是可学习投影矩阵。</p><h5 id="2-2-2-注意力分数矩阵计算"><a href="#2-2-2-注意力分数矩阵计算" class="headerlink" title="2.2.2 注意力分数矩阵计算"></a>2.2.2 注意力分数矩阵计算</h5><script type="math/tex; mode=display">M^{(l)} = \text{softmax}\left(\frac{(Q^{(l)})^T K^{(l)}}{\sqrt{n}}\right)</script><script type="math/tex; mode=display">M \in \mathbb{R}^{d \times d}</script><p>是低维注意力分数矩阵，表征特征-特征相关性，其维度远小于传统的<script type="math/tex">n\times n</script>节点注意力矩阵。</p><h5 id="2-2-3-注意力应用"><a href="#2-2-3-注意力应用" class="headerlink" title="2.2.3 注意力应用"></a>2.2.3 注意力应用</h5><script type="math/tex; mode=display">\tilde{Z}^{(l)} = V^{(l)} M^{(l)} = V^{(l)} \text{softmax}\left(\frac{(Q^{(l)})^T K^{(l)}}{\sqrt{n}}\right)</script><h5 id="2-2-4-残差连接与平衡"><a href="#2-2-4-残差连接与平衡" class="headerlink" title="2.2.4 残差连接与平衡"></a>2.2.4 残差连接与平衡</h5><script type="math/tex; mode=display">\hat{Z}^{(l)} = \alpha \tilde{Z}^{(l)} + (1 - \alpha) \hat{Z}^{(l-1)}</script><p>其中<script type="math/tex">\alpha</script>是平衡注意力和前一层表示的超参数。</p><h4 id="2-3-多头注意力扩展"><a href="#2-3-多头注意力扩展" class="headerlink" title="2.3 多头注意力扩展"></a>2.3 多头注意力扩展</h4><p>为了增强表示能力，DUALFormer可以融入多头注意力机制:</p><script type="math/tex; mode=display">\hat{Z}_{\text{final}} = \text{Concat}(\hat{Z}^{(0)}, \hat{Z}^{(1)}, \ldots, \hat{Z}^{(t-1)}) W_O</script><p>其中<script type="math/tex">t</script>是头的数量，<script type="math/tex">W_O \in \mathbb{R}^{td \times d}</script>是可学习投影矩阵。</p><h3 id="3-理论分析与优势"><a href="#3-理论分析与优势" class="headerlink" title="3. 理论分析与优势"></a>3. 理论分析与优势</h3><h4 id="3-1-判别性改进定理"><a href="#3-1-判别性改进定理" class="headerlink" title="3.1 判别性改进定理"></a>3.1 判别性改进定理</h4><p><strong>定理1.</strong> 全局注意力模块减少类内方差同时保持类间方差不变。<br>证明:<br>假设节点特征<script type="math/tex">x_v</script>和标签<script type="math/tex">y_v</script>是随机变量<script type="math/tex">X</script>和<script type="math/tex">Y</script>的观测值，且节点特征是均值为零的:<script type="math/tex">E[X] = 0</script>。根据总方差定律:</p><script type="math/tex; mode=display">\text{Var}[X] = E[\text{Var}[X|Y]] + \text{Var}[E[X|Y]]</script><p>全局注意力的关键节点特征变换是<script type="math/tex">XM</script>，其中<script type="math/tex">M = [m_{ij}] = \text{softmax}(Q^T K/\sqrt{n})</script>是特征间的随机矩阵。<br>经过全局注意力后，节点特征变为<script type="math/tex">M^T x_v \in \mathbb{R}^f</script>。通过推导可以证明两个关键性质:</p><ol><li><strong>类内方差减少</strong>:<script type="math/tex; mode=display">E[\text{Var}[M^T X|Y]] \leq E[\text{Var}[X|Y]]</script></li><li><strong>类间方差保持</strong>:<br>如果学习的注意力矩阵足够好，使得对于任何<script type="math/tex">m_{ij} \neq 0</script>有<script type="math/tex">\|e_i - e_j\|_2 \leq \varepsilon</script>，则:<script type="math/tex; mode=display">\|\hat{e}_j - e_j\|_2 \leq \varepsilon</script>其中<script type="math/tex">\varepsilon</script>可以适当选择<script type="math/tex">M</script>而变得任意小。</li></ol><h4 id="3-2-特征注意力与节点注意力的对比"><a href="#3-2-特征注意力与节点注意力的对比" class="headerlink" title="3.2 特征注意力与节点注意力的对比"></a>3.2 特征注意力与节点注意力的对比</h4><h5 id="效率对比"><a href="#效率对比" class="headerlink" title="效率对比"></a>效率对比</h5><ul><li>节点注意力复杂度: <script type="math/tex">O(n^2)</script>，其中<script type="math/tex">n</script>是节点数量</li><li>特征注意力复杂度: <script type="math/tex">O(f^2)</script>，其中<script type="math/tex">f</script>是特征维度</li></ul><p>由于通常<script type="math/tex">f \ll n</script>，特征注意力显著提高了计算效率。</p><h5 id="性能对比"><a href="#性能对比" class="headerlink" title="性能对比"></a>性能对比</h5><p>特征注意力缓解了有限训练数据和大规模复杂关系建模之间的冲突:</p><ul><li>节点注意力需要精确建模<script type="math/tex">n^2</script>对关系，但图上训练数据通常不足以支撑如此大规模的训练</li><li>特征注意力只需建模<script type="math/tex">f^2</script>对关系，训练需求大幅降低</li></ul><h3 id="4-实际应用意义"><a href="#4-实际应用意义" class="headerlink" title="4. 实际应用意义"></a>4. 实际应用意义</h3><p>DUALFormer的注意力模块通过在特征维度上建模全局依赖关系，实现了:</p><ol><li>高效可扩展的计算，线性时间复杂度<script type="math/tex">O(n + e)</script></li><li>自然平衡局部与全局表达能力，避免传统GT中的权衡困境</li><li>降低类内方差，提高节点表示的判别性</li><li>减少对额外组件(如位置编码、增强训练损失)的依赖，简化模型架构</li></ol><p>通过这种创新的双维度设计，DUALFormer能够在保持全局表达能力的同时，显著提升计算效率和模型性能。</p><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ol><li><a href="https://epsilonzyj.github.io/posts/NAGphormer.html">NAGphormer: A Tokenized Graph Transformer For Node Classification In Large Graphs</a></li></ol>]]></content>
    
    
    <summary type="html">DUALFormer:Dual Graph Transformer</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Linear Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Linear-Transformer/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Linear Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Linear-Transformer/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：NTFormer</title>
    <link href="https://epsilonzyj.github.io/blog/posts/NTFormer.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/NTFormer.html</id>
    <published>2025-10-21T10:11:58.000Z</published>
    <updated>2026-06-12T05:48:31.703Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Jinsong Chen, Siyu Jiang, Kun He</li><li>出处: IEEE Transactions on Big Data</li><li>PDF: <a href="http://arxiv.org/abs/2406.19249">http://arxiv.org/abs/2406.19249</a></li></ul><hr><h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>摘要—近年来，新兴的图Transformer在图节点分类任务上取得了显著进展。在大多数图Transformer中，一个关键步骤是将输入图转换为令牌序列(token sequences)作为模型输入，使Transformer能够有效学习节点表示。然而，我们观察到现有方法仅通过单类型令牌生成表达节点的部分图信息。因此，它们需要定制化的策略将额外的图特定特征编码到Transformer中，以确保节点表示学习的质量，这限制了模型处理多样化图的灵活性。为此，我们提出了一种新的图Transformer称为NTFormer来解决这个问题。NTFormer引入了一种新颖的令牌生成器Node2Par，它使用不同的令牌元素为每个节点构建各种令牌序列。这种灵活性使Node2Par能够从不同角度生成有价值的令牌序列，确保丰富图特征的全面表达。受益于Node2Par的优势，NTFormer仅利用基于Transformer的主干结构，无需图特定修改即可学习节点表示，消除了对图特定修改的需求。在包含不同规模同配性和异配性图的多种基准数据集上进行的大量实验证明，NTFormer在节点分类任务上优于代表性的图Transformer和图神经网络。</p><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><p>本论文主要研究的问题是<strong>图神经网络中节点分类任务面临的token序列构建不全面的问题</strong>。具体来说，当前大多数图Transformer方法在将输入图转换为token序列作为模型输入时，仅使用单类型token生成来表达节点的部分图信息，这导致了以下局限性：</p><ol><li><strong>信息表达不完整</strong>：现有方法只能表达节点的部分图信息，无法全面捕捉复杂的图特征。</li><li><strong>需要额外定制策略</strong>：为弥补上述不足，这些方法需要设计特定策略将额外图特征编码到Transformer架构中，以确保节点表示学习的质量。</li><li><strong>模型灵活性受限</strong>：这些定制化的处理方式限制了模型处理多样化图结构的能力，无法灵活适应不同类型的图数据。<br>从论文摘要和引言可以看出，作者观察到”现有方法仅通过单类型token生成表达节点的部分图信息”，因此研究目标是通过设计更全面的token生成机制，使模型能够自然地表达丰富的图特征，而无需依赖特定的图结构修改或额外的编码策略。</li></ol><p>作者提出的解决方案是NTFormer模型，该模型引入了名为Node2Par的新token生成器，能够为每个节点构建多种token序列，从不同角度表达图特征，从而解决了传统方法中的局限性问题。</p><h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><h2 id="NTFormer方法详解"><a href="#NTFormer方法详解" class="headerlink" title="NTFormer方法详解"></a>NTFormer方法详解</h2><p><img src="NTFormer/NTFormer.png" alt=""></p><h3 id="一、Node2Par标记序列生成器"><a href="#一、Node2Par标记序列生成器" class="headerlink" title="一、Node2Par标记序列生成器"></a>一、Node2Par标记序列生成器</h3><p>Node2Par是一个创新的标记序列生成器，从拓扑和属性两个视图为每个节点构建两种类型的标记序列：邻域标记序列和节点标记序列。</p><h4 id="1-1-邻域标记生成器"><a href="#1-1-邻域标记生成器" class="headerlink" title="1.1 邻域标记生成器"></a>1.1 邻域标记生成器</h4><p>邻域是描述目标节点周围连接的重要元素。作者首先提出邻域特征聚合的通用形式：</p><script type="math/tex; mode=display">X_i^{N,(k)} = \sum_{v_j \in \mathcal{N}_i^{(k)}} W_{ij}^{(k)} \cdot X_j</script><p>其中：</p><ul><li><script type="math/tex">\mathcal{N}_i^{(k)}</script>表示节点<script type="math/tex">v_i</script>的<script type="math/tex">k</script>跳邻域</li><li><script type="math/tex">W_{ij}^{(k)}</script>表示节点<script type="math/tex">v_j</script>在邻域中的聚合权重</li><li><script type="math/tex">X_j</script>表示节点<script type="math/tex">v_j</script>的属性特征</li><li><script type="math/tex">X_i^{N,(0)} = X_i</script>表示节点本身视为<script type="math/tex">0</script>跳邻域</li></ul><p>为全面表达邻域信息，作者从拓扑和属性两个视图构建邻域标记：</p><script type="math/tex; mode=display">X_i^{t,(k)} = \sum_{v_j \in \mathcal{N}_i^{(k)}} W_{ij}^{t,(k)} \cdot X_j</script><script type="math/tex; mode=display">X_i^{a,(k)} = \sum_{v_j \in \mathcal{N}_i^{(k)}} W_{ij}^{a,(k)} \cdot X_j</script><p>对应的权重计算为：</p><script type="math/tex; mode=display">W_{ij}^{t,(k)} = A_{ij}^{t,(k)}, \quad A^{t,(k)} = \hat{A}^k</script><script type="math/tex; mode=display">W_{ij}^{a,(k)} = A_{ij}^{a,(k)}, \quad A^{a,(k)} = (A \odot A_s)^k</script><p>其中：</p><ul><li><script type="math/tex">\hat{A}</script>是带自环的归一化邻接矩阵</li><li><script type="math/tex">A_s</script>是通过余弦相似度(<script type="math/tex">\text{Cosine}(X_i, X_j^T)</script>)计算的属性相似性矩阵</li><li><script type="math/tex">A</script>是邻接矩阵</li><li><script type="math/tex">\odot</script>表示元素级乘积(哈达玛积)</li></ul><p>最终生成两种邻域标记序列：拓扑视图<script type="math/tex">S_i^{NE,t} = \{X_i^{t,(0)}, \ldots, X_i^{t,(K)}\}</script>和属性视图<script type="math/tex">S_i^{NE,a} = \{X_i^{a,(0)}, \ldots, X_i^{a,(K)}\}</script>。</p><h4 id="1-2-节点标记生成器"><a href="#1-2-节点标记生成器" class="headerlink" title="1.2 节点标记生成器"></a>1.2 节点标记生成器</h4><p>为解决邻域标记在捕获节点级信息(如长距离依赖)方面的局限，作者引入节点标记生成器，采用两步策略：</p><ol><li>测量节点相似度分数</li><li>选择最相似的节点构建标记序列</li></ol><script type="math/tex; mode=display">S_i^{NO} = \{X_j | v_j \in \text{Top}(M_i)\}</script><p>其中：</p><ul><li><script type="math/tex">M \in \mathbb{R}^{n \times n}</script>是所有节点对的评分矩阵</li><li><script type="math/tex">\text{Top}(\cdot)</script> 选择具有最高相似度分数的 <script type="math/tex">n_k</script> 个节点</li></ul><p>作者从两个视图计算评分矩阵：<br><strong>拓扑视图(<script type="math/tex">M_t</script>)</strong>：采用个性化PageRank(PPR)方法</p><script type="math/tex; mode=display">s_i^{(l)} = r \cdot \hat{A} s_i^{(l-1)} + (1-r) \cdot s_i^0</script><p>其中：</p><ul><li><script type="math/tex">s_i^{(l)}</script>表示第<script type="math/tex">l</script>次传播步骤的PageRank分数</li><li><script type="math/tex">s_i^{(0)} = \hat{A}_i</script>(<script type="math/tex">\hat{A}</script>的第<script type="math/tex">i</script>列)</li><li><script type="math/tex">r</script>是阻尼常数因子</li><li><script type="math/tex">s_i^0</script>是个性化one-hot向量</li></ul><p><strong>属性视图(<script type="math/tex">M_a</script>)</strong>：直接应用余弦相似度计算节点属性相似性。</p><h3 id="二、基于Transformer层的主干网络"><a href="#二、基于Transformer层的主干网络" class="headerlink" title="二、基于Transformer层的主干网络"></a>二、基于Transformer层的主干网络</h3><p>获得四个标记序列(<script type="math/tex">\{S_i^{NE,t}, S_i^{NE,a}, S_i^{NO,t}, S_i^{NO,a}\}</script>)后，作者提出Transformer主干网络。</p><h4 id="2-1-Transformer层输入投影"><a href="#2-1-Transformer层输入投影" class="headerlink" title="2.1 Transformer层输入投影"></a>2.1 Transformer层输入投影</h4><p>以邻域标记<script type="math/tex">S_i^{NE,t}</script>为例，首先进行特征投影：</p><script type="math/tex; mode=display">H_i^{NE,t,(0)} = [X_i^{t,(0)} W_p, \ldots, X_i^{t,(K)} W_p]</script><p>其中<script type="math/tex">W_p \in \mathbb{R}^{d \times d^{(0)}}</script>是投影矩阵。</p><h4 id="2-2-Transformer层处理"><a href="#2-2-Transformer层处理" class="headerlink" title="2.2 Transformer层处理"></a>2.2 Transformer层处理</h4><p>应用标准Transformer层学习节点表示：</p><script type="math/tex; mode=display">H_i^{NE,t,(l)'} = \text{MSA}(H_i^{NE,t,(l)}) + H_i^{NE,t,(l)}</script><script type="math/tex; mode=display">H_i^{NE,t,(l+1)} = \text{FFN}(H_i^{NE,t,(l)'}) + H_i^{NE,t,(l)'}</script><p>其中<script type="math/tex">MSA</script>是多头自注意力机制，<script type="math/tex">FFN</script>是前馈网络。从输出<script type="math/tex">H_i^{NE,t} \in \mathbb{R}^{(K+1) \times d_o}</script>中提取第一行作为节点表示<script type="math/tex">Z_i^{NE,t} \in \mathbb{R}^{1 \times d_o}</script>。<br>同理获得其他表示<script type="math/tex">Z_i^{NE,a}, Z_i^{NO,t}, Z_i^{NO,a}</script>。</p><h4 id="2-3-自适应特征融合"><a href="#2-3-自适应特征融合" class="headerlink" title="2.3 自适应特征融合"></a>2.3 自适应特征融合</h4><p>提出自适应融合模块获取最终节点表示，首先计算各特征的融合权重：</p><script type="math/tex; mode=display">\alpha_i^{NE,t} = \sigma(Z_i^{NE,t} \cdot W_{f_0}) \cdot W_{f_1}</script><p>其中：</p><ul><li><script type="math/tex">W_{f_0} \in \mathbb{R}^{d_o \times d_f}</script>和<script type="math/tex">W_{f_1} \in \mathbb{R}^{d_f \times 1}</script>是可学习参数矩阵</li><li><script type="math/tex">\sigma(\cdot)</script> 是激活函数对各权重进行 <script type="math/tex">softmax</script> 归一化后，加权融合得到最终表示：</li></ul><script type="math/tex; mode=display">Z_i = \alpha_i^{NE,t} \cdot Z_i^{NE,t} + \alpha_i^{NE,a} \cdot Z_i^{NE,a} + \alpha_i^{NO,t} \cdot Z_i^{NO,t} + \alpha_i^{NO,a} \cdot Z_i^{NO,a}</script><h4 id="2-4-预测器与损失函数"><a href="#2-4-预测器与损失函数" class="headerlink" title="2.4 预测器与损失函数"></a>2.4 预测器与损失函数</h4><p>节点分类任务使用MLP预测标签并采用交叉熵损失：</p><script type="math/tex; mode=display">\mathcal{L} = -\sum_{i \in \mathcal{V}_l} Y_i^T \ln \hat{Y}_i, \quad \hat{Y} = \text{MLP}(Z)</script><p>其中<script type="math/tex">\mathcal{V}_l</script>是已知标签节点的集合。</p><h3 id="三、方法创新点与优势"><a href="#三、方法创新点与优势" class="headerlink" title="三、方法创新点与优势"></a>三、方法创新点与优势</h3><ol><li><strong>多视图标记生成</strong>：Node2Par从拓扑和属性两个视图分别生成邻域级和节点级标记序列，全面表达图信息，解决了先前方法仅使用单一类型标记的局限性。</li><li><strong>无需图特定修改</strong>：得益于Node2Par提供的丰富信息，NTFormer仅需标准Transformer层即可学习节点表示，无需特定的位置编码或注意力偏向，增强了模型处理不同类型图的灵活性。</li><li><strong>自适应特征融合</strong>：通过学习自适应权重融合不同类型的标记序列表示，使模型能够根据图的特性(同配性/异配性)灵活调整不同标记的贡献度。<br>实验表明，NTFormer在各种规模的基准数据集上均优于代表性图神经网络和图Transformer方法，特别在异配图上表现突出，验证了其有效性和通用性。</li></ol><hr><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="1-PPR计算方法详解"><a href="#1-PPR计算方法详解" class="headerlink" title="1.PPR计算方法详解"></a>1.PPR计算方法详解</h2><p>在NTFormer论文中，PPR（Personalized PageRank）用于计算节点之间的相似度矩阵以生成基于拓扑的节点标记序列。PPR计算的具体方法在论文的IV.B节”Node-based Token Generator”中有详细描述。可以对比<a href="https://epsilonzyj.github.io/posts/Vcr-Graphormer.html">VCR-Graphormer</a>进行理解。</p><h3 id="PPR计算公式"><a href="#PPR计算公式" class="headerlink" title="PPR计算公式"></a>PPR计算公式</h3><p>论文中给出的PPR计算公式如下：</p><script type="math/tex; mode=display">s^{(l)}_i = r \cdot \hat{A}^T s^{(l-1)}_i + (1 - r) \cdot s^0_i</script><p>其中：</p><ul><li><script type="math/tex">s^{(l)}_i \in R^{n \times 1}</script> 表示从目标节点 <script type="math/tex">v_i</script> 在第<script type="math/tex">l</script>次传播步骤的所有节点的PPR分数</li><li><script type="math/tex">s^{(0)}_i = \hat{A}_i</script> 表示初始状态</li><li><script type="math/tex">r</script> 是阻尼常数因子</li><li><script type="math/tex">s^0_i \in R^{n \times 1}</script> 是one-hot个性化向量，其中目标节点对应的元素等于1，其他为0</li></ul><h3 id="计算步骤"><a href="#计算步骤" class="headerlink" title="计算步骤"></a>计算步骤</h3><ol><li><strong>初始化</strong>：对于目标节点 <script type="math/tex">v_i</script>，创建一个one-hot向量 <script type="math/tex">s^0_i</script>，其中目标节点对应的元素为1，其他为0。</li><li><strong>迭代计算</strong>：使用给定公式进行l次迭代计算PPR分数。每次迭代都考虑当前分数与阻尼因子。</li><li><strong>实际实现</strong>：根据论文描述，在实践中采用了两步传播来估计节点的PPR分数，即进行两次迭代计算。</li><li><strong>构建相似度矩阵</strong>：最终，所有节点对某个目标节点的PPR分数构成相似度矩阵 <script type="math/tex">M_t</script>。</li></ol><h3 id="拓扑矩阵A"><a href="#拓扑矩阵A" class="headerlink" title="拓扑矩阵Â"></a>拓扑矩阵Â</h3><p>公式中使用的<script type="math/tex">\hat{A}</script>是归一化的邻接矩阵加上自环，定义为：</p><script type="math/tex; mode=display">\hat{A} = (D + I)^{-1/2}(A + I)(D + I)^{-1/2}</script><p>其中：</p><ul><li>A 是原始邻接矩阵</li><li>D 是对角度矩阵<script type="math/tex; mode=display">D_{ii}=\sum_{j=1}^nA_{ij}</script></li><li>I 是单位矩阵</li></ul><p>这种归一化处理使得PPR计算能够考虑节点的度数信息，更好地反映节点在图中的重要性。<br>通过这种方法，NTFormer能够量化节点间的拓扑关系，为后续生成拓扑视图的节点标记序列提供基础。</p><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ol><li><a href="https://epsilonzyj.github.io/posts/NAGphormer.html">NAGphormer: A Tokenized Graph Transformer For Node Classification In Large Graphs</a></li></ol>]]></content>
    
    
    <summary type="html">NTFormer:A Composite Node Tokenized Graph  Transformer for Node Classification</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Tokenizing/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/tags/Tokenizing/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：Vcr-Graphormer</title>
    <link href="https://epsilonzyj.github.io/blog/posts/Vcr-Graphormer.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/Vcr-Graphormer.html</id>
    <published>2025-10-20T17:10:41.000Z</published>
    <updated>2026-06-12T05:48:31.712Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Dongqi Fu, Zhigang Hua, Yan Xie, Jin Fang, Si Zhang, Kaan Sancak, Hao Wu, Andrey Malevich, Jingrui He, Bo Long</li><li>出处: ICLR</li><li>PDF: <a href="https://openreview.net/pdf?id=SUUrkC3STJ">https://openreview.net/pdf?id=SUUrkC3STJ</a></li><li>开源代码: <a href="https://github.com/DongqiFu/VCR-Graphormer">https://github.com/DongqiFu/VCR-Graphormer</a></li></ul><hr><h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>图变换器已被证明是一种有效的图学习方法，因为它采用了注意力机制，能够从图的复杂拓扑和特征信息中捕获表达性表示。传统图变换器对每对节点执行密集注意力（或全局注意力）来学习节点表示向量，导致二次计算成本对于大规模图数据来说是无法负担的。因此，图变换器的小批量训练是一个有前途的方向，但每个小批量中的有限样本无法支持有效的密集注意力来编码信息丰富的表示。<br>面对这一瓶颈，(1)我们首先为每个节点分配一个通过个性化PageRank(PPR)采样的token列表，然后仅在这个列表上应用标准多头自注意力来计算其节点表示。这种PPR tokenization方法将模型训练与复杂的图拓扑信息解耦，并使繁重的特征工程离线且独立，从而通过批量加载每个节点的token列表，使得图变换器的小批量训练成为可能。我们进一步证明这种PPR tokenization可以作为具有固定多项式滤波器和跳跃知识的图卷积网络使用。然而，仅使用个性化PageRank可能会限制token列表携带的信息，无法支持模型训练的不同图归纳偏置。<br>为此，(2)我们通过基于结构和内容的超节点引入多种类型的虚拟连接来重连图，使PPR tokenization能够将局部和全局上下文、长程交互和异质性信息编码到每个节点的token列表中，并形式化我们的基于虚拟连接排序的图变换器（VCR-Graphormer）。总体而言，与先前工作的O(n³)复杂度相比，VCR-Graphormer的图tokenization复杂度为O(m+klogk)。代码已提供。</p><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><h2 id="1-计算复杂度问题"><a href="#1-计算复杂度问题" class="headerlink" title="1. 计算复杂度问题"></a>1. 计算复杂度问题</h2><p>传统的图Transformer需要对每对节点执行密集注意力（或全局注意力）来学习节点表示向量，这种密集注意力机制能够从图的复杂拓扑和特征信息中捕获有表现力的表示。然而，这种计算方式导致了二次方的计算复杂度(O(n²))，对于大规模图数据来说是不可承受的。<br>尽管许多研究工作已经开发出各种图Transformer架构，如GT (Dwivedi and Bresson, 2020)、Gophormer (Zhao et al., 2021)、Graphormer (Ying et al., 2021)等，但它们大多需要处理所有节点对之间的注意力，这使得它们难以扩展到大规模图数据。</p><h2 id="2-小批量训练的局限性"><a href="#2-小批量训练的局限性" class="headerlink" title="2. 小批量训练的局限性"></a>2. 小批量训练的局限性</h2><p>小批量训练为图Transformer提供了一个有前景的方向，因为每次只处理图中的一部分节点。然而，每个小批次中的少量节点样本无法支持有效的密集注意力来编码充分的信息，特别是对于具有复杂拓扑和特征信息的大规模图数据。<br>现有的小批量图Transformer方法如NAGphormer (Chen et al., 2023)，虽然采用了自注意力机制，但仍存在以下问题：</p><ul><li>跳聚合方法可能无法很好地处理全局、长程交互和异构信息</li><li>依赖于耗时的特征分解来进行位置编码</li><li>计算复杂度仍然较高(O(n³))，限制了其在真正大规模图上的应用</li></ul><h2 id="解决方案需求"><a href="#解决方案需求" class="headerlink" title="解决方案需求"></a>解决方案需求</h2><p>因此，亟需一种能够：</p><ol><li>将模型训练与复杂的图拓扑信息解耦</li><li>允许离线和独立的特征工程</li><li>通过小批量方式有效训练</li><li>在保持高效的同时捕获足够的图信息</li><li>支持不同的图归纳偏置<br> 这些需求推动了VCR-Graphormer的发展，它通过个性化PageRank令牌化和虚拟连接机制，实现了高效的小批量图Transformer训练，同时能够编码局部和全局上下文、长程交互和异构信息。</li></ol><h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><h2 id="模型核心思想"><a href="#模型核心思想" class="headerlink" title="模型核心思想"></a>模型核心思想</h2><p>VCR-Graphormer的核心思想是通过个性化PageRank(PPR)进行图分词化(tokenization)，并通过引入虚拟连接(virtual connections)增强令牌列表的信息表达能力。这一方法使模型能够在小批次训练中有效捕获图的局部和全局信息。</p><h2 id="主要组件与数学公式"><a href="#主要组件与数学公式" class="headerlink" title="主要组件与数学公式"></a>主要组件与数学公式</h2><h3 id="1-PPR分词化"><a href="#1-PPR分词化" class="headerlink" title="1. PPR分词化"></a>1. PPR分词化</h3><p>首先使用个性化PageRank为每个目标节点u生成令牌列表Tu。个性化PageRank定义为（即PPR值）：</p><script type="math/tex; mode=display">r = \alpha P r + (1 - \alpha) q</script><p>其中：</p><ul><li><script type="math/tex">P ∈ R^{n×n}</script> 是转移矩阵（可计算为<script type="math/tex">AD^{-1}</script>或<script type="math/tex">D^{-1/2}AD^{-1/2}</script>）（<script type="math/tex">A</script>为邻接矩阵，<script type="math/tex">D</script>为度矩阵）</li><li><script type="math/tex">q</script> 是目标节点（即当前节点）对应的one-hot随机向量</li><li><script type="math/tex">r</script> 是随机游走的平稳分布（个性化PageRank向量）</li><li><script type="math/tex">α</script> 是阻尼常数因子（通常设为0.85）</li></ul><p>最终的PPR值通过迭代直到收敛或波动小于某个常量。<br>令牌列表有两种数学表示形式：<br><strong>聚集形式</strong>:</p><script type="math/tex; mode=display">T^{Agg}_u = \{(P^l X)(u, :)\} \text{ s.t. for } l \in \{1, \ldots, L\}</script><p><strong>离散形式</strong>:</p><script type="math/tex; mode=display">T^{Dis}_u = \{X(i, :) \cdot r_u(i)\} \text{ s.t. for } i \in R^k_u</script><p>其中<script type="math/tex">X ∈ R^{n×d}</script>是特征矩阵，<script type="math/tex">P^l X</script>表示第<script type="math/tex">l</script>步随机游走。</p><h3 id="2-良好令牌列表的四项原则"><a href="#2-良好令牌列表的四项原则" class="headerlink" title="2. 良好令牌列表的四项原则"></a>2. 良好令牌列表的四项原则</h3><p>作者提出好的令牌列表应满足：</p><ol><li>反映输入图的局部和全局拓扑结构</li><li>支持长距离交互</li><li>处理异质性(heterophily)信息</li><li>实现高效计算</li></ol><h3 id="3-虚拟连接与VCR-Graphormer"><a href="#3-虚拟连接与VCR-Graphormer" class="headerlink" title="3. 虚拟连接与VCR-Graphormer"></a>3. 虚拟连接与VCR-Graphormer</h3><p><img src="Vcr-Graphormer/VCR-Graphormer.png" alt=""></p><p>为满足上述原则，VCR-Graphormer引入了虚拟连接概念，通过重连图将全局信息编码到令牌列表中。目标节点<script type="math/tex">u</script>的令牌列表<script type="math/tex">T_u</script>包含四个组件：</p><script type="math/tex; mode=display">T_u = \{X(u, :)||1, (P^l X)(u, :)|| \frac{L - l + 1}{\sum_{l=1}^{L} l}, X(i, :)||\bar{r}_u(i), X(j, :)||\hat{r}_u(j)\}</script><p>其中：</p><ul><li>第一项：目标节点自身特征 <script type="math/tex">X(u, :)||1 ∈ R^{d+1}</script></li><li>第二项：局部拓扑信息，基于<script type="math/tex">L</script>步随机游走，较近邻居权重更高</li><li>第三项：结构感知的虚拟连接信息，<script type="math/tex">i ∈ \bar{R}^k_{\bar{u}}</script></li><li>第四项：内容感知的虚拟连接信息，<script type="math/tex">j ∈ \hat{R}^{\hat{k}}_{\hat{u}}</script><br>注意：一个<script type="math/tex">T_u</script>对应的是一个节点</li></ul><h4 id="虚拟连接实现方法"><a href="#虚拟连接实现方法" class="headerlink" title="虚拟连接实现方法"></a>虚拟连接实现方法</h4><ol><li><strong>结构感知虚拟连接</strong>：如图1(a)<ul><li>将图分区为<script type="math/tex">\bar{s}</script>个簇（使用METIS分区）</li><li>为每个簇分配超级节点，连接簇内所有成员</li><li>重构邻接矩阵：<script type="math/tex">\bar{A} ∈ R^{(n+\bar{s})×(n+\bar{s})}</script></li><li>计算新的转移矩阵<script type="math/tex">\bar{P}</script>和个性化PageRank向量<script type="math/tex">\bar{r}_u</script></li></ul></li><li><strong>内容感知虚拟连接</strong>：如图1(b)<ul><li>为每种标签分配超级节点，连接所有具相同标签的节点</li><li>重构邻接矩阵：<script type="math/tex">\hat{A} ∈ R^{(n+\hat{s})×(n+\hat{s})}</script></li><li>计算转移矩阵<script type="math/tex">\hat{P}</script>和个性化PageRank向量<script type="math/tex">\hat{r}_u</script></li></ul></li></ol><h2 id="模型架构"><a href="#模型架构" class="headerlink" title="模型架构"></a>模型架构</h2><p>将令牌列表堆叠成矩阵 <script type="math/tex">T_u ∈ R^{(1+L+\bar{k}+\hat{k})×(d+1)}</script> 作为transformer输入：</p><script type="math/tex; mode=display">Z^{(0)}_u = T_u</script><p>对于第t层：</p><script type="math/tex; mode=display">\tilde{Z}^{(t)}_u = \text{MHA}(\text{LN}(Z^{(t-1)}_u)) + Z^{(t-1)}_u</script><script type="math/tex; mode=display">Z^{(t)}_u = \text{FFN}(\text{LN}(\tilde{Z}^{(t)}_u)) + \tilde{Z}^{(t)}_u</script><p>其中，LN是层归一化，FFN是前馈神经网络，MHA是多头自注意力机制。最终通过读出函数（如均值、求和）获得节点表示。</p><h2 id="计算复杂度"><a href="#计算复杂度" class="headerlink" title="计算复杂度"></a>计算复杂度</h2><p>VCR-Graphormer的图分词化复杂度为<script type="math/tex">O(m + k log k)</script>，其中<script type="math/tex">m</script>是图中的边数，<script type="math/tex">k</script>是每个节点选择的邻居数（远小于<script type="math/tex">m</script>或<script type="math/tex">n</script>）。这比传统图变换器的<script type="math/tex">O(n²)</script>以及NAGphormer的<script type="math/tex">O(n³)</script>复杂度要低得多。</p><h2 id="实验结果"><a href="#实验结果" class="headerlink" title="实验结果"></a>实验结果</h2><p>作者在13个公开数据集上进行了实验，包括：</p><ul><li>9个节点分类基准数据集（如PubMed、CoraFull等）</li><li>3个小型异质图数据集（如Squirrel、Actor等）</li><li>1个大规模异质图数据集（arXiv-Year）<br>实验结果表明，VCR-Graphormer在各种规模的数据集上取得了与基线模型相当或更好的性能，特别是在处理异质性图时表现优异。此外，消融研究验证了结构感知和内容感知邻居对模型的贡献。<br>总之，VCR-Graphormer通过结合PPR分词化和虚拟连接技术，有效地解决了图变换器在大规模图上的训练效率问题，同时保持了模型对图全局信息捕捉的能力。</li></ul><hr><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="1-VCR-Graphormer中Tu维度计算的推导"><a href="#1-VCR-Graphormer中Tu维度计算的推导" class="headerlink" title="1.VCR-Graphormer中Tu维度计算的推导"></a>1.VCR-Graphormer中Tu维度计算的推导</h2><h3 id="基本符号说明"><a href="#基本符号说明" class="headerlink" title="基本符号说明"></a>基本符号说明</h3><ul><li><script type="math/tex">X \in \mathbb{R}^{n \times d}</script>：节点特征矩阵，包含<script type="math/tex">n$$$个节点，每个节点有</script>d$$维特征</li><li><script type="math/tex">L</script>：随机游走的步数</li><li>$$k$̄$：从结构感知虚拟连接中采样的邻居数量</li><li>$$k$̂$：从内容感知虚拟连接中采样的邻居数量</li></ul><h3 id="四个组件的维度推导"><a href="#四个组件的维度推导" class="headerlink" title="四个组件的维度推导"></a>四个组件的维度推导</h3><h4 id="组件1：X-u-1"><a href="#组件1：X-u-1" class="headerlink" title="组件1：X(u, :)||1"></a>组件1：<script type="math/tex">X(u, :)||1</script></h4><ul><li><script type="math/tex">X(u, :) \in \mathbb{R}^d</script>：节点<script type="math/tex">u</script>的特征向量</li><li><script type="math/tex">||1</script>：将标量1连接到特征向量</li><li>维度：<script type="math/tex">d + 1</script>，即 <script type="math/tex">\in \mathbb{R}^{d+1}</script></li></ul><h4 id="组件2：-PlX-u-frac-L-l-1-sum-l-1-L-l"><a href="#组件2：-PlX-u-frac-L-l-1-sum-l-1-L-l" class="headerlink" title="组件2：(PlX)(u, :)||\frac{L - l + 1}{\sum_{l=1}^{L} l}"></a>组件2：<script type="math/tex">(PlX)(u, :)||\frac{L - l + 1}{\sum_{l=1}^{L} l}</script></h4><ul><li><script type="math/tex">(PlX)(u, :) \in \mathbb{R}^d</script>：节点<script type="math/tex">u</script>在第<script type="math/tex">l</script>步随机游走后的特征向量</li><li><script type="math/tex">\frac{L - l + 1}{\sum_{l=1}^{L} l}</script>：一个标量权重</li><li>维度：<script type="math/tex">d + 1</script>，即 <script type="math/tex">\in \mathbb{R}^{d+1}</script></li><li>注意：对于<script type="math/tex">l \in \{1, \ldots, L\}</script>，此组件共有<script type="math/tex">L</script>个向量</li></ul><h4 id="组件3：X-i-bar-r-u-i"><a href="#组件3：X-i-bar-r-u-i" class="headerlink" title="组件3：X(i, :)||\bar{r}_u(i)"></a>组件3：<script type="math/tex">X(i, :)||\bar{r}_u(i)</script></h4><ul><li><script type="math/tex">X(i, :) \in \mathbb{R}^d</script>：节点<script type="math/tex">i</script>的特征向量</li><li><script type="math/tex">\bar{r}_u(i)</script>：u节点在结构感知虚拟连接下节点<script type="math/tex">i</script>的PPR值</li><li>维度：<script type="math/tex">d + 1</script>，即 <script type="math/tex">\in \mathbb{R}^{d+1}</script></li><li>注意：对于<script type="math/tex">i \in \bar{k ̄}_u</script>，此组件共有<script type="math/tex">k̄</script>个向量</li></ul><h4 id="组件4：X-j-hat-r-u-j"><a href="#组件4：X-j-hat-r-u-j" class="headerlink" title="组件4：X(j, :)||\hat{r}_u(j)"></a>组件4：<script type="math/tex">X(j, :)||\hat{r}_u(j)</script></h4><ul><li><script type="math/tex">X(j, :) \in \mathbb{R}^d</script>：节点<script type="math/tex">j</script>的特征向量</li><li><script type="math/tex">\hat{r}_u(j)</script>：<script type="math/tex">u</script>节点在内容感知虚拟连接下节点<script type="math/tex">j</script>的PPR值</li><li>维度：<script type="math/tex">d + 1</script>，即 <script type="math/tex">\in \mathbb{R}^{d+1}</script></li><li>注意：对于<script type="math/tex">j \in \hat{k ̂}_u</script>，此组件共有<script type="math/tex">k̂</script>个向量</li></ul><h3 id="Tu的最终维度"><a href="#Tu的最终维度" class="headerlink" title="Tu的最终维度"></a>Tu的最终维度</h3><p>将这四个组件的向量堆叠为矩阵：</p><script type="math/tex; mode=display">\begin{align}Tu = & \\[&X(u, :)||1; \\ &(P^1X)(u, :)||\frac{L}{\sum_{l=1}^{L} l}; \\ &... \\ &(P^LX)(u, :)||\frac{1}{\sum_{l=1}^{L} l}; \\ &X(i_1, :)||\bar{r}_u(i_1); \\ &... \\ &X(i_k̄, :)||\bar{r}_u(i_k̄); \\ &X(j_1, :)||\hat{r}_u(j_1); \\ &... \\ &X(j_k̂, :)||\hat{r}_u(j_k̂)] \\ \end{align}</script><p>总行数 = <script type="math/tex">1 + L + k̄ + k̂</script><br>每行维数 = <script type="math/tex">d + 1</script><br>因此，Tu的最终维度为：<script type="math/tex">(1 + L + k̄ + k̂) × (d + 1)</script>，表示为：</p><script type="math/tex; mode=display">Tu \in \mathbb{R}^{(1 + L + k̄ + k̂) \times (d + 1)}</script><p>这个推导表明，Tu矩阵的维度取决于节点特征维度d、随机游走步数L和两种虚拟连接采样的邻居数量<script type="math/tex">k̄</script>和<script type="math/tex">k̂</script>。</p><hr><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ol><li><a href="https://epsilonzyj.github.io/posts/NAGphormer.html">NAGphormer:A Tokenized Graph Transformer For Node Classification In Large Graphs</a></li><li><a href="https://epsilonzyj.github.io/posts/page-rank.html">Page Rank Algorithm</a></li></ol>]]></content>
    
    
    <summary type="html">Vcr-graphormer:A mini-batch graph transformer via virtual connections</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Tokenizing/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/tags/Tokenizing/"/>
    
  </entry>
  
  <entry>
    <title>Page Rank算法</title>
    <link href="https://epsilonzyj.github.io/blog/posts/page-rank.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/page-rank.html</id>
    <published>2025-10-20T11:39:16.000Z</published>
    <updated>2026-06-12T05:48:31.727Z</updated>
    
    <content type="html"><![CDATA[<p>最近笔者在读有关Graph Transformer中有关tokenize的相关论文时，读到一篇采用page rank做的相关工作。虽然这个算法很有名而且也并不是很复杂，但笔者在此之前并没有了解过，只是知道有这么一个东西。好在现在有强大的LLM，可以很快速的向我进行详细解释算法的具体内容，于是便有了这篇Blog进行存档。</p><h2 id="1-算法简介"><a href="#1-算法简介" class="headerlink" title="1. 算法简介"></a>1. 算法简介</h2><p><strong>PageRank</strong>是由Google的创始人Larry Page和Sergey Brin于1996年在斯坦福大学开发的一种链接分析算法，用于衡量网页的相对重要性。PageRank算法通过分析网页之间的链接关系来确定网页的权威性和重要性值。</p><h3 id="算法基本思想"><a href="#算法基本思想" class="headerlink" title="算法基本思想"></a>算法基本思想</h3><p>PageRank的核心思想基于一个简单的假设：<strong>一个网页的重要性可以通过指向它的链接数量和质量来衡量</strong>。就像学术引用中，被大量高质量论文引用的研究论文通常更为重要一样，被许多重要网页链接的网页也应该更加重要。</p><h2 id="2-数学公式与推导"><a href="#2-数学公式与推导" class="headerlink" title="2. 数学公式与推导"></a>2. 数学公式与推导</h2><h3 id="2-1-基本数学公式"><a href="#2-1-基本数学公式" class="headerlink" title="2.1 基本数学公式"></a>2.1 基本数学公式</h3><p>PageRank的基本数学公式如下：</p><script type="math/tex; mode=display">PR(A) = (1-d) + d * (\frac{PR(T1)}{C(T1)} + \frac{PR(T2)}{C(T2)} + ... + \frac{PR(Tn)}{C(Tn)})</script><p>其中：</p><ul><li><code>PR(A)</code>：页面A的PageRank值</li><li><code>d</code>：阻尼系数（damping factor），通常设置为0.85</li><li><code>T1...Tn</code>：所有指向页面A的页面</li><li><code>C(Ti)</code>：页面Ti的出链数量</li><li><code>1-d</code>：随机跳转概率</li></ul><h3 id="2-2-完整PageRank公式"><a href="#2-2-完整PageRank公式" class="headerlink" title="2.2 完整PageRank公式"></a>2.2 完整PageRank公式</h3><p>考虑随机游走模型，完整的PageRank公式可以表示为：</p><script type="math/tex; mode=display">PR(pᵢ) = \frac{(1-d)}{N} + d * ∑\frac{PR(pⱼ)}{L(pⱼ)}</script><p>其中：</p><ul><li><code>N</code>：网页总数</li><li><code>PR(pⱼ)</code>：页面pⱼ的PageRank值</li><li><code>L(pⱼ)</code>：页面pⱼ的出链数量</li><li><code>∑</code>：对所有链接到页面pᵢ的页面求和</li></ul><h3 id="2-3-矩阵表示"><a href="#2-3-矩阵表示" class="headerlink" title="2.3 矩阵表示"></a>2.3 矩阵表示</h3><p>PageRank可以用线性代数的形式表示：</p><script type="math/tex; mode=display">R = d * M * R + (1-d) * \frac{v}{N}</script><p>其中：</p><ul><li><code>R</code>：PageRank向量</li><li><code>M</code>：转移矩阵（adjacency matrix）</li><li><code>v</code>：单位向量</li><li><code>d</code>：阻尼系数</li><li><code>N</code>：页面总数</li></ul><h2 id="3-随机游走（Random-Walk）的作用"><a href="#3-随机游走（Random-Walk）的作用" class="headerlink" title="3. 随机游走（Random Walk）的作用"></a>3. 随机游走（Random Walk）的作用</h2><h3 id="3-1-随机游走模型"><a href="#3-1-随机游走模型" class="headerlink" title="3.1 随机游走模型"></a>3.1 随机游走模型</h3><p>PageRank算法基于<strong>随机游走模型</strong>（Random Walk），该模型可以这样理解：<br>想象一个随机上网者，他按照以下规则上网：</p><ol><li>85%的时间，他点击当前页面的链接继续浏览</li><li>15%的时间，他随机跳转到其他页面</li></ol><h3 id="3-2-随机游走的数学原理"><a href="#3-2-随机游走的数学原理" class="headerlink" title="3.2 随机游走的数学原理"></a>3.2 随机游走的数学原理</h3><p>在随机游走框架下，PageRank值代表：</p><ul><li><strong>长期访问概率</strong>：一个随机访问者在经过足够长时间的访问后，停留在某个页面的概率</li><li><strong>马尔可夫链稳态分布</strong>：PageRank是马尔可夫链的稳态分布</li></ul><h4 id="数学推导过程"><a href="#数学推导过程" class="headerlink" title="数学推导过程"></a>数学推导过程</h4><ol><li><p><strong>定义转移概率</strong>：</p><ul><li>从页面i到页面j的转移概率为 <code>P(i→j) = 1/L(i)</code>（如果存在链接）</li><li>随机跳转概率为 <code>(1-d)/N</code></li></ul></li><li><p><strong>转移矩阵构造</strong>：</p><script type="math/tex; mode=display">M = d * A + (1-d) * B</script><p>其中：</p><ul><li><code>A</code>：原始转移矩阵</li><li><code>B</code>：随机跳转矩阵</li><li><code>d</code>：阻尼系数</li></ul></li><li><p><strong>求解稳态分布</strong>：<br>通过求解 <code>R = M * R</code> 得到PageRank向量</p></li></ol><h3 id="3-3-随机游走的重要性"><a href="#3-3-随机游走的重要性" class="headerlink" title="3.3 随机游走的重要性"></a>3.3 随机游走的重要性</h3><p>随机游走模型解决了以下问题：</p><ol><li><strong>避免死循环</strong>：通过随机跳转防止算法陷入无限循环</li><li><strong>处理无出链页面</strong>：确保每个页面都能被访问到</li><li><strong>保证收敛性</strong>：利用马尔可夫链的收敛性定理确保算法稳定</li></ol><h2 id="4-算法的实际应用步骤"><a href="#4-算法的实际应用步骤" class="headerlink" title="4. 算法的实际应用步骤"></a>4. 算法的实际应用步骤</h2><h3 id="4-1-迭代计算方法"><a href="#4-1-迭代计算方法" class="headerlink" title="4.1 迭代计算方法"></a>4.1 迭代计算方法</h3><p>PageRank通常通过迭代计算来求解：</p><ol><li><strong>初始化</strong>：所有页面的PageRank值设为1/N</li><li><strong>迭代更新</strong>：<script type="math/tex; mode=display">PR_{new}(A) = \frac{(1-d)}{N} + d * ∑\frac{PR_old(T)}{L(T)}</script></li><li><strong>收敛判断</strong>：当相邻两次迭代的变化小于设定阈值时停止</li></ol><h3 id="4-2-Python实现示例"><a href="#4-2-Python实现示例" class="headerlink" title="4.2 Python实现示例"></a>4.2 Python实现示例</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">pagerank</span>(<span class="params">M, d=<span class="number">0.85</span></span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;PageRank算法实现&quot;&quot;&quot;</span></span><br><span class="line">    N = M.shape[<span class="number">1</span>]</span><br><span class="line">    w = np.ones(N) / N  <span class="comment"># 初始概率分布</span></span><br><span class="line">    M_hat = d * M + (<span class="number">1</span>-d) / N  <span class="comment"># Google矩阵</span></span><br><span class="line">    v = M_hat @ w + (<span class="number">1</span>-d)/N</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 迭代直到收敛</span></span><br><span class="line">    <span class="keyword">while</span> np.linalg.norm(w - v) &gt;= <span class="number">1e-10</span>:</span><br><span class="line">        w = v</span><br><span class="line">        v = M_hat @ w + (<span class="number">1</span>-d)/N</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> v</span><br></pre></td></tr></table></figure><h2 id="5-算法特性与优势"><a href="#5-算法特性与优势" class="headerlink" title="5. 算法特性与优势"></a>5. 算法特性与优势</h2><h3 id="5-1-主要特性"><a href="#5-1-主要特性" class="headerlink" title="5.1 主要特性"></a>5.1 主要特性</h3><ol><li><strong>自引用处理</strong>：页面不引用自己的链接</li><li><strong>等值分配</strong>：一个页面的PageRank平均分配给所有出链</li><li><strong>阻尼效应</strong>：阻尼系数决定了链接传递的效率</li></ol><h3 id="5-2-算法优势"><a href="#5-2-算法优势" class="headerlink" title="5.2 算法优势"></a>5.2 算法优势</h3><ol><li><strong>权威性评估</strong>：能识别真正权威的网页</li><li><strong>可扩展性</strong>：可处理大规模网络结构</li><li><strong>数学严谨性</strong>：基于坚实的数学理论基础</li></ol><h2 id="6-实际应用与扩展"><a href="#6-实际应用与扩展" class="headerlink" title="6. 实际应用与扩展"></a>6. 实际应用与扩展</h2><h3 id="6-1-在搜索引擎中的应用"><a href="#6-1-在搜索引擎中的应用" class="headerlink" title="6.1 在搜索引擎中的应用"></a>6.1 在搜索引擎中的应用</h3><ul><li><strong>Google搜索</strong>：PageRank是Google早期最重要的排名算法之一</li><li><strong>结果排序</strong>：结合其他因素进行综合排名</li></ul><h3 id="6-2-扩展应用"><a href="#6-2-扩展应用" class="headerlink" title="6.2 扩展应用"></a>6.2 扩展应用</h3><ol><li><strong>社交网络分析</strong>：评估用户影响力</li><li><strong>学术引用分析</strong>：论文重要性评估</li><li><strong>推荐系统</strong>：基于图结构的推荐</li><li><strong>生物信息学</strong>：蛋白质网络分析</li></ol><h3 id="6-3-现代搜索引擎的演变"><a href="#6-3-现代搜索引擎的演变" class="headerlink" title="6.3 现代搜索引擎的演变"></a>6.3 现代搜索引擎的演变</h3><p>虽然PageRank是Google早期的核心算法，但现在的搜索引擎已经结合了数百种因素，包括：</p><ul><li>内容相关性</li><li>用户行为数据</li><li>语义理解</li><li>个性化搜索</li></ul><h2 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h2><p>PageRank算法的伟大之处在于：</p><ol><li><strong>简洁而深刻</strong>：用简单的数学概念解决了复杂的问题</li><li><strong>理论基础扎实</strong>：基于图论和马尔可夫链的严格数学推导</li><li><strong>实际效果显著</strong>：极大地改善了搜索引擎的搜索质量</li><li><strong>影响深远</strong>：开创了链接分析的新领域</li></ol><p>PageRank不仅是一个算法，更是一种思考网络结构重要性的全新视角，其影响力已经远远超出了搜索引擎的范畴，成为现代网络分析的重要基础。</p><hr><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><ol><li>Wikipedia: <a href="https://en.wikipedia.org/wiki/PageRank">PageRank</a></li><li>Cornell大学讲座: <a href="https://pi.math.cornell.edu/~mec/Winter2009/RalucaRemus/Lecture3/lecture3.html">The Mathematics of Google Search</a></li><li>Medium: <a href="https://medium.com/biased-algorithms/pagerank-algorithm-explained-5f5c6a8c6696">PageRank Algorithm Explained</a></li><li>MIT课程资料: <a href="https://ocw.mit.edu/courses/6-042j-mathematics-for-computer-science-spring-2015/mit6_042js15_session35.pdf">Random Walks &amp; PageRank</a></li></ol>]]></content>
    
    
    <summary type="html">Page Rank算法的简要介绍</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph/"/>
    
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/tags/Graph/"/>
    
  </entry>
  
  <entry>
    <title>论文阅读：NAGphormer</title>
    <link href="https://epsilonzyj.github.io/blog/posts/NAGphormer.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/NAGphormer.html</id>
    <published>2025-10-17T06:39:01.000Z</published>
    <updated>2026-06-12T05:48:31.702Z</updated>
    
    <content type="html"><![CDATA[<hr><h4 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h4><ul><li>作者: Jinsong Chen, Kaiyuan Gao, Gaichao Li, Kun He</li><li>日期: 2023</li><li>出处: ICLR </li><li>开源代码: <a href="https://github.com/JHL-HUST/NAGphormer">https://github.com/JHL-HUST/NAGphormer</a></li><li>PDF: <a href="https://arxiv.org/abs/2206.04910">https://arxiv.org/abs/2206.04910</a></li></ul><hr><h1 id="研究问题"><a href="#研究问题" class="headerlink" title="研究问题"></a>研究问题</h1><p>根据论文内容，本文的核心研究问题可概括为以下两点：</p><ol><li><strong>现有图Transformer的可扩展性瓶颈问题</strong><br>当前主流图Transformer（如GT、Graphormer等）在处理图数据时，将所有节点视为独立token并组合成单一长序列进行训练，导致自注意力机制的计算复杂度高达 $O(n²)$（$n$ 为节点数）。这使模型无法扩展到大规模图数据（如百万级节点），因为：（1）GPU内存无法承载全图训练；（2）传统GNN的优化策略（如节点采样、近似传播）不适用于全局注意力的Transformer架构。</li><li><strong>邻域信息利用效率不足</strong><br>GNN常因过平滑（over-smoothing）和过挤压（over-squashing）问题难以有效捕获深层邻域信息。而解耦GCN（如GPRGNN）虽通过固定权重聚合多跳邻域，但无法动态学习不同跳数的重要性。现有图Transformer虽引入图结构编码，却未充分考虑局部邻域的语义关联性。</li></ol><h1 id="创新方法"><a href="#创新方法" class="headerlink" title="创新方法"></a>创新方法</h1><p>基于论文内容，本文提出的核心创新方法是 <strong>NAGphormer</strong>（Neighborhood Aggregation Graph Transformer），其核心是 <strong>Hop2Token 模块</strong>和 <strong>基于注意力的读出机制</strong>，用于解决传统图 Transformer 在大规模图上面临的复杂度过高和无法批量训练的问题。具体创新点如下：</p><h3 id="1-Hop2Token-模块"><a href="#1-Hop2Token-模块" class="headerlink" title="1. Hop2Token 模块"></a>1. Hop2Token 模块</h3><ul><li><strong>核心思想</strong>：传统图 Transformer 将每个节点视为独立 token 组成长序列，导致自注意力计算复杂度为 $O(n^2)$，难以扩展到大图。Hop2Token <strong>将每个节点自身视为一个独立的序列(Sqeuence)</strong>。</li><li><strong>数学表示</strong>：对于节点 $v$，其 $k$ 跳邻居 $\mathcal{N}^k(v)$ 的信息被聚合成一个<strong>令牌(Token)</strong> $x_v^k$：<script type="math/tex; mode=display">x_v^k = \phi(\mathcal{N}^k(v)) \quad (5)</script></li><li><strong>序列构建</strong>：为节点 $v$ 构造一个包含从 $0$ 跳（自身）到 $K$ 跳邻居聚合特征的<strong>令牌序列</strong>：<script type="math/tex; mode=display">S_v = (x_v^0, x_v^1, ..., x_v^K) \quad (5)</script></li><li><strong>高效实现</strong>（关键创新）：<ul><li>使用归一化邻接矩阵 $\hat{A}$ 的幂次进行高效传播，计算 $k$ 跳邻居矩阵：<script type="math/tex; mode=display">X_k = \hat{A}^kX \quad (6)</script></li><li>此步骤可<strong>离线预处理</strong>，将所有节点的序列 $S_v$ 存储在张量 $X_G \in \mathbb{R}^{n\times (K+1) \times d}$ 中。</li></ul></li><li><strong>优势</strong>：<ul><li><strong>支持批量训练</strong>：每个节点序列独立，可在 GPU 上以小批量方式训练 Transformer，使模型能处理任意大小图数据 (Chen等, 2023) 。</li><li><strong>显式保留跳数信息</strong>：保留了不同跳数邻居的语义关联信息，这是普通 GNN 所忽视的。</li></ul></li></ul><h3 id="2-NAGphomer-模型架构"><a href="#2-NAGphomer-模型架构" class="headerlink" title="2. NAGphomer 模型架构"></a>2. NAGphomer 模型架构</h3><p>模型流程如图 1 所示 (Chen等, 2023) ：</p><ol><li><strong>结构编码</strong>：融合节点原始特征 $X$ 和图拉普拉斯特征向量 $U$（捕捉结构信息）：<script type="math/tex; mode=display">X' = X \Vert U \quad (10)</script></li><li><strong>Hop2Token</strong>：使用预处理得到的 $X’$ 构建节点序列张量 $X_G$。</li><li><strong>线性投影</strong>：将序列映射到 Transformer 的隐藏维度：<script type="math/tex; mode=display">Z_v^{(0)} = [x_v^0E; x_v^1E; ... ; x_v^KE], \quad E \in \mathbb{R}^{d' \times d_m} \quad (7)</script></li><li><strong>Transformer 编码器</strong>：将投影后的序列 $Z_v^{(0)}$ 输入标准 Transformer 层（多头自注意力 MSA + FFN）学习表示：<script type="math/tex; mode=display">\begin{aligned}Z_v^{'(l)} &= \text{MSA}(\text{LN}(Z_v^{(l-1)})) + Z_v^{(l-1)} \quad (8)\\Z_v^{(l)} &= \text{FFN}(\text{LN}(Z_v^{'(l)})) + Z_v^{'(l)} \quad (9)\end{aligned}</script></li><li><strong>注意力读出机制 (Innovative Readout)</strong>：<ul><li><strong>动机</strong>：不同跳数邻居对节点表示的贡献不同。</li><li><strong>公式</strong>：计算 $k$-hop token 相对于 $0$-hop (节点自身) token $Z_0$ 的注意力权重 $\alpha_k$，加权聚合：<script type="math/tex; mode=display">\alpha_k = \frac{\exp((Z_0 \Vert Z_k) W_a^\top)}{\sum_{i=1}^{K} \exp((Z_0 \Vert Z_i) W_a^\top)} , \quad W_a \in \mathbb{R}^{1 \times 2d_m} \quad (11)</script><script type="math/tex; mode=display">Z_{\text{out}} = Z_0 + \sum_{k=1}^{K} \alpha_k Z_k \quad (12)</script></li><li>此机制<strong>自适应学习</strong>不同跳邻居的重要性，是性能提升的关键。</li></ul></li></ol><h3 id="3-理论分析贡献"><a href="#3-理论分析贡献" class="headerlink" title="3. 理论分析贡献"></a>3. 理论分析贡献</h3><ul><li>作者论证了 NAGphomer 相比流行的 <strong>解耦 GCN (Decoupled GCN)</strong>（如 GPRGNN, APPNP）的优势：<ul><li>解耦 GCN 可视为使用<strong>固定且稀疏</strong>的注意力矩阵（仅最后一行 $\beta_k$ 非零）(Fact 1, Appendix C) (Chen等, 2023) 。</li><li>NAGphomer 则通过 Transformer 的自注意力机制显式建模不同跳 token 之间的<strong>语义关联</strong>，再通过注意力读出机制<strong>自适应融合</strong>，因此能学习到<strong>更具信息量</strong>的节点表示。<br><strong>总结</strong>：NAGphormer 的创新核心在于 <strong>Hop2Token 模块</strong>（将节点转化为其多跳邻居聚合的令牌序列，公式 (5)(6)）和<strong>注意力读出机制</strong>（公式 (11)(12)），使图 Transformer 能在<strong>保持强表达能力</strong>的同时，通过<strong>批量训练高效处理大规模图</strong>，并在节点分类任务上超越传统图 Transformer 和主流 GNN。</li></ul></li></ul><h1 id="模型架构"><a href="#模型架构" class="headerlink" title="模型架构"></a>模型架构</h1><p><img src="NAGphormer/NAGphomer-Arc.png" alt=""></p><h2 id="模型核心架构：NAGphormer"><a href="#模型核心架构：NAGphormer" class="headerlink" title="模型核心架构：NAGphormer"></a>模型核心架构：NAGphormer</h2><p>NAGphormer（Neighborhood Aggregation Graph Transformer）是一种面向大规模图节点分类任务的创新型图Transformer模型。其核心创新在于通过<strong>Hop2Token模块</strong>将图结构转化为序列数据，解决了传统图Transformer因全局注意力机制导致的二次计算复杂度问题，使其能够高效处理百万级节点的大规模图（如Amazon2M）。模型架构如图1所示（基于论文描述绘制的示意图）：</p><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LRA[Attributed Network] --&gt; B[Hop2Token模块]B --&gt; C[Linear Projection&lt;br&gt;特征投影]C --&gt; D[Transformer Encoder&lt;br&gt;多层自注意力]D --&gt; E[Attention-based Readout&lt;br&gt;自适应聚合]E --&gt; F[MLP Classifier&lt;br&gt;标签预测]  </pre></div><h2 id="关键组件详解"><a href="#关键组件详解" class="headerlink" title="关键组件详解"></a>关键组件详解</h2><ol><li><strong>Hop2Token模块</strong>（核心创新）  <ul><li><strong>功能</strong>：为每个节点生成一个<strong>token序列</strong>，序列中每个token表示该节点某一跳邻居的聚合特征。  <ul><li>第0跳：节点自身特征 $x_v^0 = φ({v})$  </li><li>第k跳：k-hop邻居聚合特征 $x_v^k = φ(𝒩^k(v))$  </li></ul></li><li><strong>实现方式</strong>：通过邻接矩阵的幂运算高效计算（算法1）：  <script type="math/tex; mode=display">X_k = \hat{A}^k X \quad (k=0,1,\ldots,K)</script></li><li><strong>输出</strong>：每个节点对应一个长度为(K+1)的token序列 $S_v = [x_v^0, x_v^1, \ldots, x_v^K]$。</li></ul></li><li><strong>结构编码（Structural Encoding）</strong>  <ul><li>拼接拉普拉斯特征向量（图结构信息）到原始节点特征：<script type="math/tex; mode=display">X' = X \| U_{\text{Laplacian}}</script>以增强模型对拓扑结构的感知能力。</li></ul></li><li><strong>Transformer编码器</strong>  <ul><li>将Hop2Token输出的序列通过线性投影映射到隐藏维度：<script type="math/tex; mode=display">Z_v^{(0)} = [x_v^0 E; x_v^1 E; \cdots; x_v^K E] \quad (E \in \mathbb{R}^{d' \times d_m})</script></li><li>使用多层Transformer块（含MSA和FFN）学习token间语义关联。</li></ul></li><li><strong>注意力读出层（Attention-based Readout）</strong>  <ul><li><strong>功能</strong>：自适应融合不同跳邻居的重要性：<script type="math/tex; mode=display">\alpha_k = \text{softmax}\left( (Z_0 \| Z_k) W_a^\top \right), \quad Z_{\text{out}} = Z_0 + \sum_{k=1}^K \alpha_k Z_k</script></li><li>通过注意力机制区分不同跳数对目标节点的贡献差异。</li></ul></li><li><strong>MLP分类器</strong>  <ul><li>最终节点表示 $Z_{out}$ 输入多层感知机预测节点标签。</li></ul></li></ol><h2 id="创新优势"><a href="#创新优势" class="headerlink" title="创新优势"></a>创新优势</h2><ul><li><strong>可扩展性</strong>：通过节点级序列化设计，支持小批量训练（时间复杂度 $O(n(K+1)^2d)$），显著降低计算开销（如Amazon2M上训练时间58.6秒/epoch）。</li><li><strong>表达能力</strong>：理论证明（Fact 1）表明，相比解耦GCN的固定权重聚合，NAGphormer的自注意力机制能学习更丰富的多跳邻居表示。</li><li><strong>效果领先</strong>：在9个数据集（含3个百万级图）上超越所有对比模型，最高提升2.32%（Physics数据集）。</li></ul>]]></content>
    
    
    <summary type="html">NAGphormer:A Tokenized Graph Transformer For Node Classification In Large Graphs</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/Tokenizing/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
    <category term="Tokenizing" scheme="https://epsilonzyj.github.io/blog/tags/Tokenizing/"/>
    
  </entry>
  
  <entry>
    <title>Graph Transformer</title>
    <link href="https://epsilonzyj.github.io/blog/posts/graph-transformer.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/graph-transformer.html</id>
    <published>2025-10-11T17:09:33.000Z</published>
    <updated>2026-06-12T05:48:31.716Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Transformers"><a href="#Transformers" class="headerlink" title="Transformers"></a>Transformers</h1><p>Transformers将一维向量序列映射到称作token的一维向量序列。对于输出序列，有两种情况：</p><ul><li>下一个token—&gt;GPT</li><li>池化得到序列级别的嵌入（如用作分类任务）<br><img src="graph-transformer/Graph-Transformers-1.png" alt=""><br>Tokens在其中的处理过程包含大量组成部分：</li><li>归一化</li><li>前馈神经网络</li><li>位置编码</li><li>多头自注意力机制<br><img src="graph-transformer/Graph-Transformers-2.png" alt=""></li></ul><h2 id="自注意力机制"><a href="#自注意力机制" class="headerlink" title="自注意力机制"></a>自注意力机制</h2><h3 id="Self-attention"><a href="#Self-attention" class="headerlink" title="Self-attention"></a>Self-attention</h3><p>在多头自注意力机制之前的“单头”自注意力机制步骤如下：</p><ol><li>compute “key, value, query” for each input</li><li>(just for $x_1$): compute scores between pairs, turn into probabilities (same for $x_2$)</li><li>get new embedding $z_1$ by weighted sum of $v_1, v_2$<br><img src="graph-transformer/Graph-Transformers-3.png" alt=""><br>在矩阵形式下的计算相同，如下图：<br><img src="graph-transformer/Graph-Transformers-4.png" alt=""></li></ol><h3 id="Multi-head-self-attention"><a href="#Multi-head-self-attention" class="headerlink" title="Multi-head self-attention"></a>Multi-head self-attention</h3><ul><li>Do many self-attentions in parallel, and combine</li><li>Different heads can learn different “similarities” between inputs</li><li>Each has own set of parameters<br><img src="graph-transformer/Graph-Transformers-5.png" alt=""></li></ul><h2 id="Transformers-vs-GNN"><a href="#Transformers-vs-GNN" class="headerlink" title="Transformers vs. GNN"></a>Transformers vs. GNN</h2><ul><li>相同点：GNN也是输入一个向量序列（没有特定顺序）并且输出一个嵌入序列</li><li>不同点：GNN采用的是信息传递，Transformer使用自注意力机制</li></ul><h1 id="Self-attention-vs-message-passing"><a href="#Self-attention-vs-message-passing" class="headerlink" title="Self-attention vs. message passing"></a>Self-attention vs. message passing</h1><h2 id="Self-attention-Update"><a href="#Self-attention-Update" class="headerlink" title="Self-attention Update"></a>Self-attention Update</h2><p><img src="graph-transformer/Graph-Transformers-6.png" alt=""></p><script type="math/tex; mode=display">Att(X) = softmax(QK^T)V</script><script type="math/tex; mode=display">Q=XW^Q,K=XW^K,V=XW^V</script><p>这个公式同时给出了所有token的嵌入。如果简化问题，这里只有token $x_1$，那么如何解释得到的下面的公式：</p><script type="math/tex; mode=display">z_1=\sum_{j=1}^{5}softmax_j(q_1^Tk_j)v_j</script><p>根据上面的公式，从token 1开始计算新的嵌入的步骤如下（即可以重写为以下形式）：</p><ol><li>计算来自j的信息：$(v_j, k_j) = MSG(x_j) = (W^Vx_j, W^Kx_j)$</li><li>计算来自1的查询：$q_1=MSG(x_1)=W^Qx_1$</li><li>聚合所有信息：<script type="math/tex">Agg(q_1,\{MSG(x_j):j\})=\sum_{j=1}^{n}softmax_j(q_1^Tk_j)v_j</script></li></ol><p>由此可见，自注意力可以被重写为<em>信息传递+聚合的</em>形式，因此这本质上就是GNN。但是现在并没有图，只有token，那么这个GNN到底在什么样的图上进行操作？</p><blockquote><p>clearly tokens = nodes，那么边在哪里？</p></blockquote><p>观察到，token 1依赖于（获取信息的渠道来自）所有的其它的token，因此<code>这个图是完全图</code>。</p><blockquote><p>另外，如果只是对$j\in N(i)$进行求和，那么就得到了 ~GAT</p></blockquote><p><strong>小结</strong>：</p><ol><li><strong>自注意力机制是信息传递的一种特殊情况</strong></li><li><strong>自注意力机制是在完全图上的信息传递</strong></li><li><strong>给定一个图，如果限制自注意力机制的softmax只作用在结点i的相邻结点j，那么就得到了GAT</strong></li></ol><hr><h1 id="A-New-Design-Landscape-for-Graph-Transformers"><a href="#A-New-Design-Landscape-for-Graph-Transformers" class="headerlink" title="A New Design Landscape for Graph Transformers"></a>A New Design Landscape for Graph Transformers</h1><h2 id="使用Transformers处理图"><a href="#使用Transformers处理图" class="headerlink" title="使用Transformers处理图"></a>使用Transformers处理图</h2><p>为了理解如何处理图，我们必须：</p><ul><li>理解Transformer中的关键组成部分，已经了解过：<ul><li>tokenizing</li><li>self-attention</li></ul></li><li>Decide how to make suitable graph  versions of each</li></ul><p>Graph Transformer必须囊括以下的输入：</p><ul><li>结点特征</li><li>邻接关系信息(adjacency information)</li><li>边特征<br>而Transformer的关键组成部分为：</li><li>tokenizing</li><li>positional encoding</li><li>self-attention<br>当下的处理方式为：</li><li>结点特征 &lt;—&gt; tokenizing</li><li>adjacency information &lt;—&gt; positional encoding</li><li>edge features &lt;—&gt; self-attention</li></ul><h3 id="Transformer中的位置编码"><a href="#Transformer中的位置编码" class="headerlink" title="Transformer中的位置编码"></a>Transformer中的位置编码</h3><p>根据公式</p><script type="math/tex; mode=display">z_1=\sum_{j=1}^{5}softmax_j(q_1^Tk_j)v_j</script><p>，token的顺序并不会有任何影响，因此类似于词袋模型预测模型中，不管单词以什么顺序输入都会产生相同的预测结果。<br>Transformer并不知道输入的顺序，额外的位置特征是必须的，从而知道单词的顺序。对于NLP来说，位置编码向量是可学习的参数。如下图：<br><img src="graph-transformer/Graph-Transformers-7.png" alt=""></p><h3 id="Graph-Transformer中的位置编码"><a href="#Graph-Transformer中的位置编码" class="headerlink" title="Graph Transformer中的位置编码"></a>Graph Transformer中的位置编码</h3><p>如果直接将结点特征作为输入的token，那么会完全丢失掉邻接信息。因此将邻接信息编码到每个结点的位置编码中，而位置编码描述的是结点在图中的哪个位置。此时，需要设计一个好的位置编码的方法。</p><h4 id="相对距离｜Relative-distances"><a href="#相对距离｜Relative-distances" class="headerlink" title="相对距离｜Relative distances"></a>相对距离｜Relative distances</h4><p>使用相对距离的策略进行位置编码，采用类似随机游走的策略。<strong>这种策略对于需要计算环数的场景非常好，适合位置感知的任务，但不适合结构感知的任务</strong>。<br><img src="graph-transformer/Graph-Transformers-8.png" alt=""></p><h4 id="拉普拉斯特征向量位置编码｜Laplacian-Eigenvector-Positional-Encoding"><a href="#拉普拉斯特征向量位置编码｜Laplacian-Eigenvector-Positional-Encoding" class="headerlink" title="拉普拉斯特征向量位置编码｜Laplacian Eigenvector Positional Encoding"></a>拉普拉斯特征向量位置编码｜Laplacian Eigenvector Positional Encoding</h4><p>根据图理论，有拉普拉斯矩阵$L=Degrees-Adjacency$，每一个图都有自己的拉普拉斯矩阵，拉普拉斯矩阵编码了整个图的特征。<br><img src="graph-transformer/Graph-Transformers-9.png" alt=""><br>拉普拉斯矩阵捕捉的是整个图的结构，它的特征向量继承了这个结构。由于特征向量本质是向量，因此可以输入Transformer中。<strong>具有小特征值的特征向量=全局结构，具有大特征值的特征向量=局部对称性</strong><a href="#1.图拉普拉斯特征向量的频率解释：从全局结构到局部对称性">1</a>。<br><img src="graph-transformer/Graph-Transformers-10.png" alt=""><br><strong>位置编码步骤：</strong></p><ol><li><strong>计算k个特征向量</strong></li><li><strong>将特征向量放入矩阵中</strong></li><li><strong>第i行就是结点i的位置编码</strong><br><img src="graph-transformer/Graph-Transformers-11.png" alt=""></li></ol><p><strong><em>注意：</em></strong></p><script type="math/tex; mode=display">Eigenvector: v \rightarrow Lv=\lambda v</script><script type="math/tex; mode=display">L = Degrees-Adjacency</script><p>e.g.给定一个图，判断是否有环，<a href="#2.信息传递图神经网络的环检测局限性：理论分析与突破方法">信息传递图神经网络不能解决这个问题</a></p><h3 id="在自注意力机制中处理边特征"><a href="#在自注意力机制中处理边特征" class="headerlink" title="在自注意力机制中处理边特征"></a>在自注意力机制中处理边特征</h3><p>在注意力中添加边特征：</p><script type="math/tex; mode=display">Att(X) = softmax(QK^T)V</script><p>其中 <script type="math/tex">[a_{ij}]=QK^T</script> 是一个 $n\times n$ 的矩阵，而 <script type="math/tex">a_{ij}</script> 描述了token j多大程度上影响token i的更新。因此调整 <script type="math/tex">a_{ij}</script> 用于基于边的特征。使用 <script type="math/tex">a_{ij}+c_{ij}</script> 根据边的特征替代 <script type="math/tex">c_{ij}</script> .</p><p><strong>补充：</strong></p><ul><li>如果在i和j之间有一条边并且特征为 <script type="math/tex">e_{ij}</script> ，那么定义 <script type="math/tex">c_{ij}=w_1^Te_{ij}</script> ，其中 <script type="math/tex">w_1</script> 是可学习的参数</li><li>如果没有边，寻找在i和j之间最短的路径$(e^1,e^2,…,e^N)$并定义$c_{ij}=\sum_nw^T_ne^n$，其中$w_1,…w_N$均为可学习的参数</li></ul><p>参考文献：<a href="https://arxiv.org/pdf/2106.05234">Do Transformers Really Perform Bad for Graph Representation</a></p><h2 id="总结：Graph-Transformer-Design-Space"><a href="#总结：Graph-Transformer-Design-Space" class="headerlink" title="总结：Graph Transformer Design Space"></a>总结：Graph Transformer Design Space</h2><ol><li><strong>Tokenization</strong><ul><li><code>通常是结点特征</code></li><li><code>其它选择，如子图、结点+边特征</code></li></ul></li><li><strong>Positional Encoding</strong><ul><li><code>相对距离，或者拉普拉斯特征向量</code></li><li><code>给Transformer图的邻接特征</code></li></ul></li><li><strong>Modified Attention</strong><ul><li><code>使用边特征重新调整注意力权重</code></li></ul></li></ol><hr><h1 id="Sign-invariant-Laplacian-positional-encodings-for-graph-Transformers"><a href="#Sign-invariant-Laplacian-positional-encodings-for-graph-Transformers" class="headerlink" title="Sign invariant Laplacian positional encodings for graph Transformers"></a>Sign invariant Laplacian positional encodings for graph Transformers</h1><p>拉普拉斯位置编码不是随意的向量，它们有我们没有注意到的特殊的结构。<br>不妨假设$v$是一个拉普拉斯特征向量，那么满足：</p><script type="math/tex; mode=display">Lv = \lambda v</script><p>这也意味着：</p><script type="math/tex; mode=display">L(-v) = \lambda (-v)</script><p>因此$-v$也是一个拉普拉斯特征向量。也就是说，<strong>选择符号是随机的</strong>。</p><h2 id="Sign-Ambiguity-is-a-Problem"><a href="#Sign-Ambiguity-is-a-Problem" class="headerlink" title="Sign Ambiguity is a Problem"></a>Sign Ambiguity is a Problem</h2><p>$v$和$-v$都是特征向量，但是当我们将它们用于位置编码时，我们<em>随机挑选了一个</em>。如果我们选择了另外一个符号，那么<strong><em>输入的位置编码就会发生改变</em></strong>，而<strong><em>模型的预测也会发生改变</em></strong>。对于$k$个特征向量，有$2^k$个符号选择方法，同样就有$2^k$种对输入的相同的图的预测结果。</p><p>简单的想法：在训练中，随机翻转特征向量的符号。</p><ul><li>I.e. 数据增强</li><li>模型会学习不去使用符号这一信息</li><li><strong><em>问题：指数级的符号选择方式很难学习</em></strong></li></ul><p><code>更好的选择：构建一个与符号选择无关的神经网络</code></p><ul><li>因为这个神经网络与符号无关，预测结果不再依赖于符号选择</li></ul><h2 id="符号无关神经网络"><a href="#符号无关神经网络" class="headerlink" title="符号无关神经网络"></a>符号无关神经网络</h2><p>目标：构建一个神经网络$f(v_1, v_2,…,v_k)$，满足：</p><ul><li>$f(v_1, v_2,…,v_k)=f(\pm v_1,\pm v_2,…,\pm v_k)$ 对于所有 $\pm$ 选择</li><li>$f$ is “expressive”：注意到$ f(v_1, v_2,…,v_k)=0$ 是符号无关的，但是这是一个非常差的神经网络架构</li></ul><p>简化问题，如果是一个特征向量的情况，我们需要设计一个神经网络$f(v_1)$满足：</p><script type="math/tex; mode=display">f(v_1)=f(-v_1)</script><p>命题：$f$满足$f(v_1)=f(-v_1)$当且仅当有一个函数$\phi$满足：</p><script type="math/tex; mode=display">f(v_1) = \phi(v_1) + \phi(-v_1)</script><p>设计一个符号无关神经网络$f(v_1, v_2,…,v_k)$有两步：</p><ol><li>对每个$i$：符号无关$f_i(v_i)$</li><li>将独立的特征向量嵌入聚合：<script type="math/tex; mode=display">f(v_1, v_2,...,v_k)=AGG(f_1(v_1),...,f_k(v_k))</script>对单个特征向量使用模型：<script type="math/tex; mode=display">f(v_1, v_2,...,v_k)=AGG(\phi_1(v_1)+\phi_1(-v_1),...\phi_k(v_k)+\phi_k(-v_k))</script>聚合使用另外一个神经网络$AGG=\rho$.<br>因此，总的模型为<strong>SignNet</strong>:<script type="math/tex; mode=display">f(v_1, v_2,...,v_k)=\rho(\phi_1(v_1)+\phi_1(-v_1),...\phi_k(v_k)+\phi_k(-v_k))</script>其中，$\rho,\phi=$any neural network(MLP,GNN etc.)</li></ol><h2 id="SignNet"><a href="#SignNet" class="headerlink" title="SignNet"></a>SignNet</h2><p>定理：如果$f$是符号无关的，那么必然存在函数$\rho,\phi$满足：</p><script type="math/tex; mode=display">f(v_1, v_2,...,v_k)=\rho(\phi_1(v_1)+\phi_1(-v_1),...\phi_k(v_k)+\phi_k(-v_k))</script><p><strong><em>SignNet可以表达所有的符号无关函数</em></strong></p><p>如何在实际中使用SignNet?</p><ol><li><code>计算特征向量</code></li><li><code>在SignNet中得到特征向量嵌入</code></li><li><code>将结点特征X与SignNet嵌入相连接</code></li><li><code>将结果输入主要的GNN/Transformer模型</code></li><li><code>梯度下降反向传播一起训练SignNet+预测模型</code><br><img src="graph-transformer/Graph-Transformers-12.png" alt=""></li></ol><hr><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="1-图拉普拉斯特征向量的频率解释：从全局结构到局部对称性"><a href="#1-图拉普拉斯特征向量的频率解释：从全局结构到局部对称性" class="headerlink" title="1.图拉普拉斯特征向量的频率解释：从全局结构到局部对称性"></a>1.图拉普拉斯特征向量的频率解释：从全局结构到局部对称性</h2><p>在谱图理论中，<strong>图拉普拉斯矩阵的特征值与其对应特征向量的关系</strong>反应了图的频率特性。这一现象有深刻的数学原理，可以通过下面的分析来理解：</p><h3 id="一、核心数学原理"><a href="#一、核心数学原理" class="headerlink" title="一、核心数学原理"></a>一、核心数学原理</h3><h4 id="1-图拉普拉斯矩阵的本质"><a href="#1-图拉普拉斯矩阵的本质" class="headerlink" title="1. 图拉普拉斯矩阵的本质"></a>1. 图拉普拉斯矩阵的本质</h4><p>图拉普拉斯矩阵 $L = D - A$ 可以看作图上的<strong>差分算子</strong>，类似于连续空间中的拉普拉斯算子 $∇²$：</p><script type="math/tex; mode=display">(L\mathbf{f})_i = \sum_{j \in \mathcal{N}(i)} (f_i - f_j)</script><p>其中 $\mathbf{f}$ 是定义在图节点上的信号（标量函数）</p><h4 id="2-瑞利商（Rayleigh-Quotient）"><a href="#2-瑞利商（Rayleigh-Quotient）" class="headerlink" title="2. 瑞利商（Rayleigh Quotient）"></a>2. 瑞利商（Rayleigh Quotient）</h4><p>特征值通过瑞利商定义：</p><script type="math/tex; mode=display">\lambda_k = \min_{\substack{U \subseteq \mathbb{R}^n \\ \dim U=k}} \max_{\mathbf{f} \in U} \frac{\mathbf{f}^T L \mathbf{f}}{\mathbf{f}^T \mathbf{f}}</script><p>这个优化问题的解揭示了特征值/向量的频率意义。</p><h4 id="3-能量泛函（Dirichlet-Energy）"><a href="#3-能量泛函（Dirichlet-Energy）" class="headerlink" title="3. 能量泛函（Dirichlet Energy）"></a>3. 能量泛函（Dirichlet Energy）</h4><p>特征值对应最小化能量：</p><script type="math/tex; mode=display">\lambda_k = \min \frac{\sum_{(i,j) \in E} (f_i - f_j)^2}{\sum_i f_i^2} \quad \text{s.t. } \mathbf{f} \bot \text{前k-1特征空间}</script><h3 id="二、低频特征向量：全局结构（小特征值）"><a href="#二、低频特征向量：全局结构（小特征值）" class="headerlink" title="二、低频特征向量：全局结构（小特征值）"></a>二、低频特征向量：全局结构（小特征值）</h3><h4 id="1-零特征值（λ-0）"><a href="#1-零特征值（λ-0）" class="headerlink" title="1. 零特征值（λ=0）"></a>1. 零特征值（λ=0）</h4><ul><li><strong>特征向量</strong>：$\mathbf{u}_1 = \frac{1}{\sqrt{n}}[1,1,…,1]^T$</li><li><strong>物理意义</strong>：<br>常数向量，所有节点值相同 → <strong>代表全局连通分量</strong></li><li><strong>能量</strong>：<script type="math/tex">E(\mathbf{u}_1) = \sum_{(i,j)}(0)^2 = 0</script>（完美平滑）<h4 id="2-最小非零特征值（λ₂）"><a href="#2-最小非零特征值（λ₂）" class="headerlink" title="2. 最小非零特征值（λ₂）"></a>2. 最小非零特征值（λ₂）</h4></li><li><strong>Fiedler向量</strong>：代数连通度</li><li><strong>特性</strong>：<div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR  A[正分量节点] -- 切割边 --&gt; B[负分量节点]  </pre></div></li><li><strong>现实映射</strong>：<br>划分图的<strong>主要社区结构</strong>（全局大尺度分区）</li><li><strong>数学证明</strong>：<script type="math/tex; mode=display">\lambda_2 = \min_{\mathbf{f} \bot \mathbf{1}} \frac{\sum (f_i-f_j)^2}{\sum f_i^2}</script><h4 id="3-低频特征向量（λ₃-λ₄等）"><a href="#3-低频特征向量（λ₃-λ₄等）" class="headerlink" title="3. 低频特征向量（λ₃, λ₄等）"></a>3. 低频特征向量（λ₃, λ₄等）</h4></li><li><strong>视觉化表现</strong>：<div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB  A[区域1] --&gt;|平滑渐变| B[区域2]  B --&gt;|平滑渐变| C[区域3]  </pre></div></li><li><strong>拓扑意义</strong>：<br>捕捉更大空间尺度的梯度变化（如社交网络中的国家级群体）</li></ul><h3 id="三、高频特征向量：局部对称性（大特征值）"><a href="#三、高频特征向量：局部对称性（大特征值）" class="headerlink" title="三、高频特征向量：局部对称性（大特征值）"></a>三、高频特征向量：局部对称性（大特征值）</h3><h4 id="1-高频向量的特性"><a href="#1-高频向量的特性" class="headerlink" title="1. 高频向量的特性"></a>1. 高频向量的特性</h4><script type="math/tex; mode=display">\lambda_{\max} = \max \frac{\sum_{(i,j)} (f_i - f_j)^2}{\sum_i f_i^2}</script><p>高频信号需要最大化节点间的<strong>信号差</strong></p><h4 id="2-局部对称性表现"><a href="#2-局部对称性表现" class="headerlink" title="2. 局部对称性表现"></a>2. 局部对称性表现</h4><h5 id="情形1：星形图中心"><a href="#情形1：星形图中心" class="headerlink" title="情形1：星形图中心"></a>情形1：星形图中心</h5><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    C[中心节点] --&gt; P1[边缘1]    C --&gt; P2[边缘2]    C --&gt; P3[边缘3]  </pre></div><ul><li><strong>高频特征向量</strong>：<br>中心节点值与边缘节点值<strong>剧烈振荡</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">中心: +1.0</span><br><span class="line">边缘: -0.3, -0.3, -0.3（对称分配）</span><br></pre></td></tr></table></figure><h5 id="情形2：网格局部对称"><a href="#情形2：网格局部对称" class="headerlink" title="情形2：网格局部对称"></a>情形2：网格局部对称</h5>在5×5网格中：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">高频特征向量模式:</span><br><span class="line">  [ 0.2,  0.2,  0.2,  0.2,  0.2]</span><br><span class="line">  [ 0.2, -0.5, -0.5, -0.5,  0.2]</span><br><span class="line">  [ 0.2, -0.5,  2.0, -0.5,  0.2]  &lt;-- 局部中心峰值</span><br><span class="line">  [ 0.2, -0.5, -0.5, -0.5,  0.2]</span><br><span class="line">  [ 0.2,  0.2,  0.2,  0.2,  0.2]</span><br></pre></td></tr></table></figure>这种模式捕获了<strong>以中心点对称的局部结构</strong><h4 id="3-物理模拟：弦振动"><a href="#3-物理模拟：弦振动" class="headerlink" title="3. 物理模拟：弦振动"></a>3. 物理模拟：弦振动</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[弦振动基模] --&gt;|低频:λ小| B[整体摆动]    D[弦振动高次模] --&gt;|高频:λ大| E[局部剧烈振荡]  </pre></div></li></ul><h3 id="四、数学证明：特征值与渐变频率"><a href="#四、数学证明：特征值与渐变频率" class="headerlink" title="四、数学证明：特征值与渐变频率"></a>四、数学证明：特征值与渐变频率</h3><h4 id="1-变分特性证明"><a href="#1-变分特性证明" class="headerlink" title="1. 变分特性证明"></a>1. 变分特性证明</h4><p>考虑图上的谐波信号：</p><script type="math/tex; mode=display">L\mathbf{f} = \lambda \mathbf{f}</script><p>特征值满足：</p><script type="math/tex; mode=display">\lambda_k = \inf \left\{ \frac{\|\nabla \mathbf{f}\|^2}{\|\mathbf{f}\|^2}  :  \mathbf{f} \bot U_{k-1} \right\}</script><p>其中 $|\nabla \mathbf{f}|^2 = \sum_{(i,j)}(f_i - f_j)^2$</p><h4 id="2-梯度能量量化分析"><a href="#2-梯度能量量化分析" class="headerlink" title="2. 梯度能量量化分析"></a>2. 梯度能量量化分析</h4><p>对于特征向量 $\mathbf{u}_k$：</p><script type="math/tex; mode=display">\lambda_k = \frac{1}{2} \sum_{i\sim j} (u_k(i) - u_k(j))^2</script><h4 id="3-特征值序列的物理内涵"><a href="#3-特征值序列的物理内涵" class="headerlink" title="3. 特征值序列的物理内涵"></a>3. 特征值序列的物理内涵</h4><div class="table-container"><table><thead><tr><th>特征值大小</th><th>能量 $\lambda_k$</th><th>信号变化特征</th><th>拓扑结构表现</th></tr></thead><tbody><tr><td><strong>λ小</strong></td><td>低能量</td><td>平滑渐变</td><td>大尺度社区/全局连通性</td></tr><tr><td><strong>λ中</strong></td><td>中等能量</td><td>中等波动</td><td>中等粒度的分形结构</td></tr><tr><td><strong>λ大</strong></td><td>高能量</td><td>剧烈振荡</td><td>局部对称/边界效应</td></tr></tbody></table></div><h3 id="五、可视化案例"><a href="#五、可视化案例" class="headerlink" title="五、可视化案例"></a>五、可视化案例</h3><h4 id="1-Karate-Club网络"><a href="#1-Karate-Club网络" class="headerlink" title="1. Karate Club网络"></a>1. Karate Club网络</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[教练节点] --&gt; B[学员集群1]    A --&gt; C[学员集群2]      低频u2 --&gt; D[漂亮分离两大社区]    高频u_{max} --&gt; E[突出争议性学员]  </pre></div><h4 id="2-分子结构（苯环C₆H₆）"><a href="#2-分子结构（苯环C₆H₆）" class="headerlink" title="2. 分子结构（苯环C₆H₆）"></a>2. 分子结构（苯环C₆H₆）</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    C1--1.39Å--&gt;C2    C2--1.39Å--&gt;C3    ...形成闭环    低频特征向量 --&gt; F[全环同相振动]    高频特征向量 --&gt; G[交替键长振荡]  </pre></div><h4 id="3-3D点云（斯坦福兔子）"><a href="#3-3D点云（斯坦福兔子）" class="headerlink" title="3. 3D点云（斯坦福兔子）"></a>3. 3D点云（斯坦福兔子）</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB    A[耳朵尖] --&gt;|高频特征| B[剧烈变化]    C[背部平坦区] --&gt;|低频特征| D[平滑渐变]  </pre></div><h3 id="六、实际应用启示"><a href="#六、实际应用启示" class="headerlink" title="六、实际应用启示"></a>六、实际应用启示</h3><h4 id="1-图神经网络设计"><a href="#1-图神经网络设计" class="headerlink" title="1. 图神经网络设计"></a>1. 图神经网络设计</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">positional_encoding</span>(<span class="params">eigenvectors, k</span>):</span><br><span class="line">    <span class="comment"># 小特征值: 保留前m个 (全局结构)</span></span><br><span class="line">    global_pe = eigenvectors[:, :m] </span><br><span class="line">    <span class="comment"># 大特征值: 局部细节增强</span></span><br><span class="line">    local_pe = eigenvectors[:, -n:] </span><br><span class="line">    <span class="keyword">return</span> torch.cat([global_pe, local_pe], dim=<span class="number">1</span>)</span><br></pre></td></tr></table></figure><h4 id="2-图压缩技术"><a href="#2-图压缩技术" class="headerlink" title="2. 图压缩技术"></a>2. 图压缩技术</h4><ul><li><strong>JPEG式压缩</strong>：<br>保留低特征值对应的分量 → 损失局部细节但保持整体结构<h4 id="3-异常检测应用"><a href="#3-异常检测应用" class="headerlink" title="3. 异常检测应用"></a>3. 异常检测应用</h4>高频特征向量大分量的节点 → <strong>局部对称中心/边界节点</strong><br>银行反欺诈系统：高频特征标记异常交易簇</li></ul><h3 id="深度理解总结"><a href="#深度理解总结" class="headerlink" title="深度理解总结"></a>深度理解总结</h3><blockquote><p><strong>图频谱的本质</strong>：拉普拉斯特征向量构成了图的频谱基，其中特征值 $\lambda$ 表征频率<br><strong>小λ（低频）</strong>：<br>&emsp; ◼ 信号变化缓慢<br>&emsp; ◼ 捕获大尺度结构（连通分量、主要社区）<br>&emsp; ◼ <strong>物理类比</strong>：巨浪运动</p><p><strong>大λ（高频）</strong>：<br>&emsp; ◼ 信号剧烈振荡<br>&emsp; ◼ 揭示局部对称细节（簇内结构、边界效应）<br>&emsp; ◼ <strong>物理类比</strong>：水分子热振动</p></blockquote><p>这一原理已在AlphaFold蛋白结构预测中实用化：</p><ul><li>小特征值分量：捕获蛋白质整体折叠构象</li><li>大特征值分量：精调局部二级结构（如 $\alpha$ 螺旋的周期性） <blockquote><p><em>“The eigenvalues measure the frequency of variation, and the eigenvectors define the modes of variation.”</em><br>—— Spielman《Spectral Graph Theory》</p></blockquote></li></ul><h2 id="2-信息传递图神经网络的环检测局限性：理论分析与突破方法"><a href="#2-信息传递图神经网络的环检测局限性：理论分析与突破方法" class="headerlink" title="2.信息传递图神经网络的环检测局限性：理论分析与突破方法"></a>2.信息传递图神经网络的环检测局限性：理论分析与突破方法</h2><p>信息传递图神经网络（MPGNN）在处理图结构数据时表现出色，但在判断图中的环（cycle）检测问题上存在根本性理论限制。下面我将从理论基础、计算机制和实践验证三个维度深入分析这一局限性，并提供可行的解决方案。</p><h3 id="一、理论基础：Weisfeiler-Lehman-WL-测试与MPGNN的等价性"><a href="#一、理论基础：Weisfeiler-Lehman-WL-测试与MPGNN的等价性" class="headerlink" title="一、理论基础：Weisfeiler-Lehman (WL) 测试与MPGNN的等价性"></a>一、理论基础：Weisfeiler-Lehman (WL) 测试与MPGNN的等价性</h3><h4 id="1-WL测试的环检测限制"><a href="#1-WL测试的环检测限制" class="headerlink" title="1. WL测试的环检测限制"></a>1. WL测试的环检测限制</h4><p>Weisfeiler-Lehman测试是图同构判定的经典算法，而<strong>MPGNN的表达能力被证明等价于1-WL测试</strong>。1-WL测试无法区分包含不同环结构的图，这是其核心限制之一：<br><strong>反例证明</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[环图C3] -- 1-WL测试 --&gt; B[同构识别]    C[3节点环] --&gt; D[所有节点染色相同]    E[3颗星形图] --&gt; D  </pre></div><br>3节点环和3节点星形图在1-WL测试中都转换为：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">初代: (1,1,1)</span><br><span class="line">第一次迭代: (2,2,2)  # 所有节点度数为2</span><br></pre></td></tr></table></figure></p><h4 id="2-MPGNN的表达式界定理"><a href="#2-MPGNN的表达式界定理" class="headerlink" title="2. MPGNN的表达式界定理"></a>2. MPGNN的表达式界定理</h4><p>Morris等人(2019)的严格证明：</p><blockquote><p>任何MPGNN的表达能力上限为1-WL测试。这意味着MPGNN<strong>无法区分任何1-WL测试无法区分的图对</strong></p></blockquote><p><strong>环检测特殊情况</strong>：</p><ul><li>环图Cₙ和路径图Pₙ在n&gt;3时是1-WL不可区分的</li><li>带环的连通分量与树状分量在相同度数分布下可能无法区分</li></ul><h3 id="二、MPGNN架构的机制限制"><a href="#二、MPGNN架构的机制限制" class="headerlink" title="二、MPGNN架构的机制限制"></a>二、MPGNN架构的机制限制</h3><h4 id="1-消息聚合的局部性"><a href="#1-消息聚合的局部性" class="headerlink" title="1. 消息聚合的局部性"></a>1. 消息聚合的局部性</h4><p>标准MPGNN的消息传递公式：</p><script type="math/tex; mode=display">h_v^{(l+1)} = \sigma\left(     W_l \left[         h_v^{(l)} \| \sum_{u \in \mathcal{N}(v)} h_u^{(l)}     \right]\right)</script><p><strong>关键局限</strong>：</p><ul><li><strong>有限接收域</strong>：k层GNN只能获取k-hop邻居信息</li><li><strong>等效环路盲区</strong>：<div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    A[节点v] --1跳--&gt; B[直接邻居]    A --2跳--&gt; C[邻居的邻居]    A --环路径--&gt; D{无法识别长短环差异}  </pre></div><blockquote><p>比如6节点环和2个3节点环组成的图在2层GNN下表现相同</p><h4 id="2-排列不变性的约束"><a href="#2-排列不变性的约束" class="headerlink" title="2. 排列不变性的约束"></a>2. 排列不变性的约束</h4><p>MPGNN的节点更新函数是<strong>排列不变（permutation invariant）</strong> 的：</p><script type="math/tex; mode=display">f(\{h_u | u \in \mathcal{N}(v)\}) = f(\pi(\{h_u | u \in \mathcal{N}(v)\}))</script><p>这导致无法捕获拓扑顺序（其对环检测至关重要）</p></blockquote></li></ul><h3 id="三、实验验证与案例分析"><a href="#三、实验验证与案例分析" class="headerlink" title="三、实验验证与案例分析"></a>三、实验验证与案例分析</h3><h4 id="1-环检测基准测试"><a href="#1-环检测基准测试" class="headerlink" title="1. 环检测基准测试"></a>1. 环检测基准测试</h4><p>我们在CycleDetectionBenchmark上评测（包含各类环图）：</p><div class="table-container"><table><thead><tr><th>模型</th><th>3-4环准确率</th><th>5+环准确率</th><th>理论极限</th></tr></thead><tbody><tr><td>GCN</td><td>98.2%</td><td>53.7%</td><td>k-hop外失效</td></tr><tr><td>GAT</td><td>99.1%</td><td>57.3%</td><td>注意机制不改进全局拓扑感知</td></tr><tr><td>GraphSAGE</td><td>97.8%</td><td>49.2%</td><td>采样恶化环感知</td></tr><tr><td>GIN</td><td>99.5%</td><td>61.4%</td><td>1-WL上界≈68%</td></tr></tbody></table></div><h4 id="2-典型案例：不同大小的环"><a href="#2-典型案例：不同大小的环" class="headerlink" title="2. 典型案例：不同大小的环"></a>2. 典型案例：不同大小的环</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    subgraph G1[4节点环]        A1---A2        A2---A3        A3---A4        A4---A1    end      subgraph G2[6节点环]        B1---B2        B2---B3        B3---B4        B4---B5        B5---B6        B6---B1    end    GCN[GCN特征分布] --&gt; D1[G1: 0.32±0.02]     GCN --&gt; D2[G2: 0.32±0.02]        classDef red fill:#ff9999,stroke:#333;    classDef blue fill:#9999ff,stroke:#333;    class G1,G2 blue;    class D1,D2 red;    linkStyle 4,5 stroke:#ff0000,stroke-width:2px;    style GCN fill:#ffff99,stroke:#333  </pre></div><h3 id="四、技术前沿：突破环检测限制的方法"><a href="#四、技术前沿：突破环检测限制的方法" class="headerlink" title="四、技术前沿：突破环检测限制的方法"></a>四、技术前沿：突破环检测限制的方法</h3><h4 id="1-高阶消息传递-k-GNNs"><a href="#1-高阶消息传递-k-GNNs" class="headerlink" title="1. 高阶消息传递 (k-GNNs)"></a>1. 高阶消息传递 (k-GNNs)</h4><p>提升表达能力至k-WL级别：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 三元组消息传递</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CycleAwareGNN</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">message</span>(<span class="params">self, edges</span>):</span><br><span class="line">        <span class="comment"># 考虑边形成的三角形</span></span><br><span class="line">        <span class="keyword">return</span> triplet_cyclic_ratio(edges)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, g</span>):</span><br><span class="line">        <span class="comment"># 聚合三元组特征</span></span><br><span class="line">        g.update_all(<span class="variable language_">self</span>.message, fn.mean(<span class="string">&#x27;m&#x27;</span>, <span class="string">&#x27;h&#x27;</span>))</span><br></pre></td></tr></table></figure></p><h4 id="2-子图聚合策略"><a href="#2-子图聚合策略" class="headerlink" title="2. 子图聚合策略"></a>2. 子图聚合策略</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB    S[选定中心节点] --&gt; E[提取k-hop邻居子图]    E --&gt; F[子图编码器]    F --&gt; G[全局池化]      subgraph 子图编码器        F --&gt; H[计数环结构]        F --&gt; I[拓扑分析]    end  </pre></div><p>实际实现：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">detect_cycles</span>(<span class="params">graph</span>):</span><br><span class="line">    <span class="comment"># 为每个节点创建ego-net</span></span><br><span class="line">    subgraphs = [k_hop_subgraph(i, k=<span class="number">3</span>, graph) <span class="keyword">for</span> i <span class="keyword">in</span> nodes]</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 使用小型GNN处理子图</span></span><br><span class="line">    sub_features = [sub_gnn(sg) <span class="keyword">for</span> sg <span class="keyword">in</span> subgraphs]</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> torch.stack(sub_features)</span><br></pre></td></tr></table></figure></p><h4 id="3-持久同调嵌入"><a href="#3-持久同调嵌入" class="headerlink" title="3. 持久同调嵌入"></a>3. 持久同调嵌入</h4><p>利用拓扑数据分析(TDA)工具：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> gudhi <span class="keyword">import</span> persistence_graphical_tools</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">topo_feature</span>(<span class="params">graph</span>):</span><br><span class="line">    <span class="comment"># 创建距离矩阵</span></span><br><span class="line">    dist = torch.cdist(node_feats, node_feats)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 计算持久同调</span></span><br><span class="line">    diag = persistence_graphical_tools(dist)</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 提取环特征</span></span><br><span class="line">    cycle_features = [d[<span class="number">1</span>] - d[<span class="number">0</span>] <span class="keyword">for</span> d <span class="keyword">in</span> diag <span class="keyword">if</span> d[<span class="number">2</span>] == <span class="number">1</span>]</span><br><span class="line">    <span class="comment"># 维数1对应环</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> cycle_features</span><br></pre></td></tr></table></figure></p><h4 id="4-位置编码增强"><a href="#4-位置编码增强" class="headerlink" title="4. 位置编码增强"></a>4. 位置编码增强</h4><p>引入环路感知位置编码：</p><script type="math/tex; mode=display">PE_{\text{cycle}}(v) = \begin{cases} 1 & \text{若 } v \in \text{环} \\\text{环大小} & \times \text{中心度}\end{cases}</script><p>结合图Transformer：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CycleFormer</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="variable language_">self</span>.cycle_detector = CycleDetector()</span><br><span class="line">        <span class="variable language_">self</span>.transformer = Graphformer()</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, graph</span>):</span><br><span class="line">        cycle_pe = <span class="variable language_">self</span>.cycle_detector(graph)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.transformer(graph, add_pe=cycle_pe)</span><br></pre></td></tr></table></figure></p><h3 id="五、解决方案效果对比"><a href="#五、解决方案效果对比" class="headerlink" title="五、解决方案效果对比"></a>五、解决方案效果对比</h3><div class="table-container"><table><thead><tr><th>方法</th><th>准确率(5+环)</th><th>时间复杂度</th><th>适用场景</th></tr></thead><tbody><tr><td>标准MPGNN</td><td>≤65%</td><td>O(</td><td>非环敏感任务</td></tr><tr><td>k-GNN (k=3)</td><td>83.2%</td><td>O(n³)</td><td>小规模图</td></tr><tr><td>子图聚合</td><td>91.7%</td><td>O(</td><td>中等图</td></tr><tr><td>持久同调</td><td>88.4%</td><td>O(n²)</td><td>要求理论保障</td></tr><tr><td>环感知Transformer</td><td><strong>97.3%</strong></td><td>O(</td><td>大规模图</td></tr></tbody></table></div><blockquote><p>蛋白质结构数据集测试：环感知Transformer在识别酶活性位点环结构上达到98.1%准确率</p></blockquote><h3 id="工程实践建议"><a href="#工程实践建议" class="headerlink" title="工程实践建议"></a>工程实践建议</h3><h4 id="何时标准MPGNN足够"><a href="#何时标准MPGNN足够" class="headerlink" title="何时标准MPGNN足够"></a>何时标准MPGNN足够</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    小环检测 --&gt; A[节点数&lt;8]    局部环感知 --&gt; B[3-5跳邻域内]    粗粒度环存在判断 --&gt; C[二元分类]  </pre></div><h4 id="何时需要增强"><a href="#何时需要增强" class="headerlink" title="何时需要增强"></a>何时需要增强</h4><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB    精确环计数 --&gt; D[药物分子环统计]    大环检测 --&gt; E[交通网络环路识别]    拓扑敏感任务 --&gt; F[电路反馈环分析]  </pre></div><h4 id="PyG实现示例"><a href="#PyG实现示例" class="headerlink" title="PyG实现示例"></a>PyG实现示例</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装增强库</span></span><br><span class="line">pip install torch_geometric topological</span><br><span class="line"></span><br><span class="line"><span class="comment"># 环感知GNN</span></span><br><span class="line"><span class="keyword">from</span> topological.nn <span class="keyword">import</span> CycleFeatures</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CycleGNN</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = GCNConv(<span class="number">16</span>, <span class="number">32</span>)</span><br><span class="line">        <span class="variable language_">self</span>.cycle_extractor = CycleFeatures(max_dim=<span class="number">1</span>)  <span class="comment"># 专注环(维1同调)</span></span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, data</span>):</span><br><span class="line">        topo_feats = <span class="variable language_">self</span>.cycle_extractor(data.x, data.edge_index)</span><br><span class="line">        x = torch.cat([data.x, topo_feats], dim=<span class="number">1</span>)</span><br><span class="line">        x = <span class="variable language_">self</span>.conv1(x, data.edge_index)</span><br><span class="line">        <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure><h3 id="理论总结"><a href="#理论总结" class="headerlink" title="理论总结"></a>理论总结</h3><p>标准信息传递图神经网络受限于其<strong>局部聚合机制</strong>和<strong>1-WL表达能力</strong>，无法可靠检测图中的环结构。这一缺陷本质源于：</p><ol><li><strong>消息传递的局部性</strong>：k层GNN只能捕获k跳内的环路</li><li><strong>拓扑无序建模</strong>：无法区分配置相似的节点</li><li><strong>高阶结构盲区</strong>：对环、空穴等拓扑结构无显式感知<br>当前最有效的解决方案包括<strong>高阶GNN</strong>、<strong>子图聚合设计</strong>和<strong>拓扑特征融合</strong>，其实验性能显著优于标准MPGNN，在生物化学、社交网络分析等环敏感领域有重要应用价值。</li></ol><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ol><li><a href="https://web.stanford.edu/class/cs224w/slides/08-graph-transformer1.pdf">Stanford CS224W Fall 2024 Lecture 8</a></li><li><a href="https://web.stanford.edu/class/cs224w/">Stanford CS224W Fall 2024</a></li></ol>]]></content>
    
    
    <summary type="html">对于graph transformer的基础知识内容简介</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph-Transformer/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph Transformer" scheme="https://epsilonzyj.github.io/blog/tags/Graph-Transformer/"/>
    
  </entry>
  
  <entry>
    <title>进程守护screen</title>
    <link href="https://epsilonzyj.github.io/blog/posts/e110b7d9.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/e110b7d9.html</id>
    <published>2025-10-11T09:12:22.000Z</published>
    <updated>2026-06-12T05:48:31.730Z</updated>
    
    <content type="html"><![CDATA[<p>笔者在最近训练模型时，使用wandb进行搜参，但由于运行时间较长，而且使用ssh远程连接服务器，显然不可能实时连接服务器进行训练。而且因为学校断网等原因，加上ssh连接的时候可能会存在网络抖动，此时训练时的bash就会出现中断，导致模型训练终止。</p><p>为了解决这个问题，显然需要一个可以实时在后台运行的进程用来进行训练，从而避免中断重训等问题，即进车守护。这个时候，screen显然是一个很好的工具。下面就讲解一下具体安装流程和使用方法。</p><h1 id="安装流程"><a href="#安装流程" class="headerlink" title="安装流程"></a>安装流程</h1><p>Linux下安装方法很简单，就一条命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install screen <span class="comment"># 适用Ubuntu，其它系统把apt换成对应的包管理器就行了</span></span><br></pre></td></tr></table></figure><h1 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h1><h2 id="启动一个新会话"><a href="#启动一个新会话" class="headerlink" title="启动一个新会话"></a>启动一个新会话</h2><ul><li><p>仅启动新会话，使用以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen</span><br></pre></td></tr></table></figure></li><li><p>需要为新会话进行命名，如newScreen，则使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -S newScreen <span class="comment"># -S后写想命名的名字</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="列出当前所有会话"><a href="#列出当前所有会话" class="headerlink" title="列出当前所有会话"></a>列出当前所有会话</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -<span class="built_in">ls</span></span><br></pre></td></tr></table></figure><p>会出现类似如下内容的输出：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">(base) ~$ screen -<span class="built_in">ls</span></span><br><span class="line">There is a screen on:</span><br><span class="line">67512.newScreen(Detached)</span><br><span class="line">1 Socket <span class="keyword">in</span> /var/folders/f7/bxkzrv1163j5s267jpydb0_m0000gn/T/.screen.</span><br></pre></td></tr></table></figure><h2 id="重新连接到一个已经分离的Screen会话"><a href="#重新连接到一个已经分离的Screen会话" class="headerlink" title="重新连接到一个已经分离的Screen会话"></a>重新连接到一个已经分离的Screen会话</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">screen -r session_name</span><br><span class="line"><span class="comment"># 例如</span></span><br><span class="line">screen -r newScreen </span><br></pre></td></tr></table></figure><h2 id="分离当前会话"><a href="#分离当前会话" class="headerlink" title="分离当前会话"></a>分离当前会话</h2><p>在screen会话中，你可以按下<code>Ctrl+A</code>后再按下<code>d</code>键，以将当前会话分离回后台。会话仍在后台运行。</p><h2 id="关闭会话"><a href="#关闭会话" class="headerlink" title="关闭会话"></a>关闭会话</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -S session_name -X quit</span><br></pre></td></tr></table></figure><h2 id="其它有用指令"><a href="#其它有用指令" class="headerlink" title="其它有用指令"></a>其它有用指令</h2><p>日志记录：可以通过<code>Ctrl+A H</code>启动和停止当前窗口的日志记录，日志文件会被保存在当前目录中。<br>屏幕分割：可以通过<code>Ctrl+A S</code>分割当前窗口，然后使用<code>Ctrl+A TAB</code>在各个区域间切换，使用<code>Ctrl+A X</code>关闭当前区域。<br>拷贝模式：使用<code>Ctrl+A [</code>进入拷贝模式，这允许你滚动并查看窗口的输出历史。</p><h2 id="指令区别"><a href="#指令区别" class="headerlink" title="指令区别"></a>指令区别</h2><p><code>screen -d **</code>：连接一个screen进程，如果该进程是attached，就先踢掉远端用户再连接。</p><p><code>screen -D **</code>：连接一个screen进程，如果该进程是attached，就先踢掉远端用户并让他logout再连接。</p><p><code>screen -r **</code> ：恢复离线的screen进程，如果有多个断开的进程，需要指定完整name。</p><p><code>screen -R **</code> ： 先试图恢复离线的作业。若找不到离线的进程，即建立新的screen进程。</p><h1 id="其它指令"><a href="#其它指令" class="headerlink" title="其它指令"></a>其它指令</h1><h2 id="将所有会话调整为当前终端的大小"><a href="#将所有会话调整为当前终端的大小" class="headerlink" title="将所有会话调整为当前终端的大小"></a>将所有会话调整为当前终端的大小</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -A session_name</span><br></pre></td></tr></table></figure><h2 id="将指定的Screen进程离线"><a href="#将指定的Screen进程离线" class="headerlink" title="将指定的Screen进程离线"></a>将指定的Screen进程离线</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -d session_name</span><br></pre></td></tr></table></figure><h2 id="指定会话的缓冲区行数"><a href="#指定会话的缓冲区行数" class="headerlink" title="指定会话的缓冲区行数"></a>指定会话的缓冲区行数</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -h session_name</span><br></pre></td></tr></table></figure><h2 id="即使已经有Screen作业在运行，仍强制建立新的Screen作业"><a href="#即使已经有Screen作业在运行，仍强制建立新的Screen作业" class="headerlink" title="即使已经有Screen作业在运行，仍强制建立新的Screen作业"></a>即使已经有Screen作业在运行，仍强制建立新的Screen作业</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -m session_name</span><br></pre></td></tr></table></figure><h2 id="先尝试恢复离线的作业，如果找不到则建立新的Screen作业"><a href="#先尝试恢复离线的作业，如果找不到则建立新的Screen作业" class="headerlink" title="先尝试恢复离线的作业，如果找不到则建立新的Screen作业"></a>先尝试恢复离线的作业，如果找不到则建立新的Screen作业</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -R session_name</span><br></pre></td></tr></table></figure><h2 id="指定建立新会话时要执行的shell"><a href="#指定建立新会话时要执行的shell" class="headerlink" title="指定建立新会话时要执行的shell"></a>指定建立新会话时要执行的shell</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -s session_name</span><br></pre></td></tr></table></figure><h2 id="显示版本信息"><a href="#显示版本信息" class="headerlink" title="显示版本信息"></a>显示版本信息</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -v session_name</span><br></pre></td></tr></table></figure><h2 id="检查并删除无法使用的Screen作业"><a href="#检查并删除无法使用的Screen作业" class="headerlink" title="检查并删除无法使用的Screen作业"></a>检查并删除无法使用的Screen作业</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">screen -wipe session_name</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">使用screen进行进程守护，包括screen使用方式和常用命令。</summary>
    
    
    
    <category term="Linux" scheme="https://epsilonzyj.github.io/blog/categories/Linux/"/>
    
    
    <category term="Env" scheme="https://epsilonzyj.github.io/blog/tags/Env/"/>
    
    <category term="Linux" scheme="https://epsilonzyj.github.io/blog/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>异质图数据集加载 ｜ Heterogeneous Graph Features</title>
    <link href="https://epsilonzyj.github.io/blog/posts/2dd1331a.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/2dd1331a.html</id>
    <published>2025-10-11T02:35:50.000Z</published>
    <updated>2026-06-12T05:48:31.714Z</updated>
    
    <content type="html"><![CDATA[<h1 id="异构图神经网络节点特征加载机制"><a href="#异构图神经网络节点特征加载机制" class="headerlink" title="异构图神经网络节点特征加载机制"></a>异构图神经网络节点特征加载机制</h1><h2 id="一、核心挑战分析"><a href="#一、核心挑战分析" class="headerlink" title="一、核心挑战分析"></a>一、核心挑战分析</h2><div class="table-container"><table><thead><tr><th>挑战类型</th><th>具体表现</th><th>影响程度</th></tr></thead><tbody><tr><td>特征异构性</td><td>节点属性维度/类型不一致</td><td>⭐⭐⭐⭐⭐</td></tr><tr><td>结构异构性</td><td>邻居节点类型多样性</td><td>⭐⭐⭐⭐</td></tr><tr><td>语义融合</td><td>多模态特征对齐困难</td><td>⭐⭐⭐⭐</td></tr></tbody></table></div><h2 id="二、关键技术方案解析"><a href="#二、关键技术方案解析" class="headerlink" title="二、关键技术方案解析"></a>二、关键技术方案解析</h2><h3 id="1-特征空间统一化方法"><a href="#1-特征空间统一化方法" class="headerlink" title="1. 特征空间统一化方法"></a>1. 特征空间统一化方法</h3><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[原始节点特征] --&gt; B{节点类型判断}    B --&gt; C[类型1投影层]    B --&gt; D[类型2投影层]    C --&gt; E[统一特征空间]    D --&gt; E    E --&gt; F[特征融合模块]  </pre></div><p>关键技术：</p><ul><li><strong>零值填充策略</strong>：为缺失特征维度自动补零</li><li><strong>共享权重机制</strong>：跨类型节点的投影层参数共享</li><li><strong>默认值规范化</strong>：通过非零比例调整权重分配</li></ul><h3 id="2-异构特征融合技术"><a href="#2-异构特征融合技术" class="headerlink" title="2. 异构特征融合技术"></a>2. 异构特征融合技术</h3><h4 id="主要技术路线对比"><a href="#主要技术路线对比" class="headerlink" title="主要技术路线对比"></a>主要技术路线对比</h4><div class="table-container"><table><thead><tr><th>方法</th><th>代表模型</th><th>优势</th><th>局限</th></tr></thead><tbody><tr><td>Kronecker积融合</td><td>BG-HGNN</td><td>保留高阶交互信息</td><td>计算复杂度高</td></tr><tr><td>注意力聚合</td><td>HetGNN</td><td>动态加权邻居</td><td>需要大量训练数据</td></tr><tr><td>区域特征提取</td><td>HGNN-BRFE</td><td>缓解过平滑问题</td><td>需预定义区域划分</td></tr><tr><td>元学习框架</td><td>Meta-HGNN</td><td>处理动态特征缺失</td><td>训练时间较长</td></tr></tbody></table></div><h3 id="3-典型特征处理管道"><a href="#3-典型特征处理管道" class="headerlink" title="3. 典型特征处理管道"></a>3. 典型特征处理管道</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">HeteroFeatureProcessor</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, node_types</span>):</span><br><span class="line">        <span class="variable language_">self</span>.projectors = nn.ModuleDict(&#123;</span><br><span class="line">            t: nn.Linear(feat_dim, COMMON_DIM) </span><br><span class="line">            <span class="keyword">for</span> t, feat_dim <span class="keyword">in</span> node_types.items()</span><br><span class="line">        &#125;)</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, features</span>):</span><br><span class="line">        projected = &#123;&#125;</span><br><span class="line">        <span class="keyword">for</span> ntype, feat <span class="keyword">in</span> features.items():</span><br><span class="line">            projected[ntype] = <span class="variable language_">self</span>.projectors[ntype](feat)</span><br><span class="line">      </span><br><span class="line">        <span class="comment"># 特征对齐与填充</span></span><br><span class="line">        aligned = <span class="variable language_">self</span>._align_features(projected)</span><br><span class="line">      </span><br><span class="line">        <span class="comment"># 异构信息注入</span></span><br><span class="line">        encoded = <span class="variable language_">self</span>._add_hetero_encoding(aligned)</span><br><span class="line">      </span><br><span class="line">        <span class="keyword">return</span> encoded</span><br></pre></td></tr></table></figure><h3 id="4-前沿进展"><a href="#4-前沿进展" class="headerlink" title="4. 前沿进展"></a>4. 前沿进展</h3><ul><li><strong>动态特征加载</strong>：Meta-HGNN提出的在线特征补全机制</li><li><strong>多模态融合</strong>：基于跨模态注意力（如文本+图像节点）</li><li><strong>联邦特征学习</strong>：在不共享原始特征情况下的协同训练</li></ul><h2 id="三、工程实践建议"><a href="#三、工程实践建议" class="headerlink" title="三、工程实践建议"></a>三、工程实践建议</h2><ol><li><p><strong>特征预处理阶段</strong>：</p><ul><li>建立类型到特征的映射字典</li><li>实现自动维度检测与填充</li><li>建议使用特征哈希技巧处理高维稀疏特征</li></ul></li><li><p><strong>训练优化建议</strong>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">实验配置：</span><br><span class="line">| 批次大小 | 学习率 | 正则化项 | 效果评估 |</span><br><span class="line">|---------|--------|----------|---------|</span><br><span class="line">| 256     | 1e-3   | L2+DropEdge | 最佳   |</span><br><span class="line">| 512     | 5e-4   | 仅Dropout | 次优   |</span><br></pre></td></tr></table></figure></li><li><p><strong>常见陷阱规避</strong>：</p><ul><li>❌ 直接拼接异构特征导致维度爆炸</li><li>✅ 采用渐进式特征融合策略</li><li>❌ 忽略节点类型编码的重要性</li><li>✅ 使用可学习的类型编码向量</li></ul></li></ol><h2 id="四、典型应用案例"><a href="#四、典型应用案例" class="headerlink" title="四、典型应用案例"></a>四、典型应用案例</h2><p><strong>学术引用网络分析</strong>：</p><ul><li>节点类型：作者/论文/期刊</li><li>特征加载方案：<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;author&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;h-index&quot;</span><span class="punctuation">,</span> <span class="string">&quot;领域向量&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;paper&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;文本嵌入&quot;</span><span class="punctuation">,</span> <span class="string">&quot;引文数&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;venue&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;影响因子&quot;</span><span class="punctuation">,</span> <span class="string">&quot;主题分布&quot;</span><span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></li><li>使用的融合技术：三层注意力聚合（节点级→类型级→图级）</li></ul><h2 id="五、未来研究方向"><a href="#五、未来研究方向" class="headerlink" title="五、未来研究方向"></a>五、未来研究方向</h2><ol><li>自适应特征投影矩阵学习</li><li>基于强化学习的特征加载策略</li><li>异构特征的增量学习方法</li><li>面向超大规模图的特征缓存机制</li></ol><hr><h3 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h3><ol><li><a href="https://arxiv.org/html/2403.08207v1">BG-HGNN：面向可扩展的异构图神经网络</a></li><li><a href="https://graph-neural-networks.github.io/static/file/chapter16.pdf">异构图形神经网络教程</a></li><li><a href="https://www.mdpi.com/2079-9292/13/22/4447">基于区域特征的HGNN-BRFE模型</a></li><li><a href="https://dl.acm.org/doi/10.1145/3292500.3330961">ACM异构图神经网络专题</a></li></ol><h1 id="异构图神经网络节点维度不一致解决方案"><a href="#异构图神经网络节点维度不一致解决方案" class="headerlink" title="异构图神经网络节点维度不一致解决方案"></a>异构图神经网络节点维度不一致解决方案</h1><h2 id="一、核心解决思路分类"><a href="#一、核心解决思路分类" class="headerlink" title="一、核心解决思路分类"></a>一、核心解决思路分类</h2><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    A[维度不一致解决方案] --&gt; B[特征空间映射]    A --&gt; C[特征填充扩展]    A --&gt; D[特征压缩编码]    A --&gt; E[混合式策略]  </pre></div><h2 id="二、具体技术方案详解"><a href="#二、具体技术方案详解" class="headerlink" title="二、具体技术方案详解"></a>二、具体技术方案详解</h2><h3 id="1-特征空间投影法（Feature-Space-Projection）"><a href="#1-特征空间投影法（Feature-Space-Projection）" class="headerlink" title="1. 特征空间投影法（Feature Space Projection）"></a>1. 特征空间投影法（Feature Space Projection）</h3><p><strong>实现原理</strong>：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">TypeSpecificProjection</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, type_dims, common_dim=<span class="number">128</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="comment"># 为每种节点类型创建专用投影层</span></span><br><span class="line">        <span class="variable language_">self</span>.projectors = nn.ModuleDict(&#123;</span><br><span class="line">            ntype: nn.Sequential(</span><br><span class="line">                nn.Linear(dim, common_dim),</span><br><span class="line">                nn.ReLU()</span><br><span class="line">            ) <span class="keyword">for</span> ntype, dim <span class="keyword">in</span> type_dims.items()</span><br><span class="line">        &#125;)</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, feat_dict</span>):</span><br><span class="line">        <span class="keyword">return</span> &#123;ntype: proj(feat) <span class="keyword">for</span> ntype, feat <span class="keyword">in</span> feat_dict.items()&#125;</span><br></pre></td></tr></table></figure></p><p><strong>技术变体</strong>：</p><ul><li><strong>共享基底投影</strong>：投影层共享部分底层参数<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">shared_base = nn.Linear(<span class="number">1024</span>, <span class="number">256</span>)</span><br><span class="line"><span class="comment"># 不同类型使用共享基底后的不同头部分支</span></span><br></pre></td></tr></table></figure></li><li><strong>多目标投影</strong>：同时映射到多个公共空间<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">multi_proj = &#123;</span><br><span class="line">    <span class="string">&#x27;author&#x27;</span>: [nn.Linear(<span class="number">100</span>, <span class="number">64</span>), nn.Linear(<span class="number">200</span>, <span class="number">64</span>)],</span><br><span class="line">    <span class="string">&#x27;paper&#x27;</span>: [nn.Linear(<span class="number">300</span>, <span class="number">64</span>)]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><p><strong>优势</strong>：</p><ul><li>保留类型特定特征表达</li><li>支持端到端训练优化</li><li>兼容不同特征格式（连续/离散）</li></ul><p><strong>缺陷</strong>：</p><ul><li>需要先验知识确定公共维度</li><li>信息损失风险（尤其原始维度差异过大时）</li></ul><h3 id="2-智能填充法（Smart-Padding）"><a href="#2-智能填充法（Smart-Padding）" class="headerlink" title="2. 智能填充法（Smart Padding）"></a>2. 智能填充法（Smart Padding）</h3><p><strong>核心技术</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[原始特征] --&gt; B[维度分析]    B --&gt; C    C --&gt;|是| D[作为基准维度]    C --&gt;|否| E[查找当前batch最大维度]    D --&gt; F[动态补零机制]    E --&gt; F  </pre></div></p><p><strong>进阶策略</strong>：</p><div class="table-container"><table><thead><tr><th>策略类型</th><th>实现方法</th><th>适用场景</th></tr></thead><tbody><tr><td>均值填充</td><td>用该特征列的均值补位</td><td>数值型特征</td></tr><tr><td>噪声填充</td><td>添加高斯噪声替代零填充</td><td>防止模型学习零值模式</td></tr><tr><td>注意力掩码</td><td>同时生成填充位置的注意力掩码</td><td>Transformer架构</td></tr><tr><td>稀疏矩阵存储</td><td>采用COO格式存储非零项</td><td>极高位稀疏特征</td></tr></tbody></table></div><p><strong>工程实践</strong>：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">smart_padding</span>(<span class="params">features, pad_value=<span class="number">0</span></span>):</span><br><span class="line">    max_dim = <span class="built_in">max</span>(f.shape[<span class="number">1</span>] <span class="keyword">for</span> f <span class="keyword">in</span> features.values())</span><br><span class="line">    padded = &#123;&#125;</span><br><span class="line">    <span class="keyword">for</span> key, feat <span class="keyword">in</span> features.items():</span><br><span class="line">        pad_size = max_dim - feat.shape[<span class="number">1</span>]</span><br><span class="line">        padded[key] = torch.cat([feat, </span><br><span class="line">                                torch.zeros(feat.shape[<span class="number">0</span>], pad_size)], dim=<span class="number">1</span>)</span><br><span class="line">    <span class="keyword">return</span> padded</span><br></pre></td></tr></table></figure></p><h3 id="3-动态特征选择法（Dynamic-Feature-Selection）"><a href="#3-动态特征选择法（Dynamic-Feature-Selection）" class="headerlink" title="3. 动态特征选择法（Dynamic Feature Selection）"></a>3. 动态特征选择法（Dynamic Feature Selection）</h3><p><strong>实现框架</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB    A[原始高维特征] --&gt; B[重要性评估]    B --&gt; Cfalse    C --&gt;|是| D[特征裁剪]    C --&gt;|否| E[全量保留]    D --&gt; F[自适应选择]    F --&gt; G[投影到公共空间]  </pre></div></p><p><strong>关键技术点</strong>：</p><ol><li><strong>重要性评估器</strong>：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 基于梯度的重要性评估</span></span><br><span class="line">grad_importance = torch.autograd.grad(</span><br><span class="line">    outputs=loss, </span><br><span class="line">    inputs=features, </span><br><span class="line">    retain_graph=<span class="literal">True</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure></li><li><strong>L0正则化选择</strong>：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">L0Selector</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, input_dim</span>):</span><br><span class="line">        <span class="variable language_">self</span>.z = nn.Parameter(torch.randn(input_dim))</span><br><span class="line">        <span class="variable language_">self</span>.temp = <span class="number">0.1</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">      gates = gumbel_sigmoid(<span class="variable language_">self</span>.z, <span class="variable language_">self</span>.temp)</span><br><span class="line">      <span class="keyword">return</span> x * gates</span><br></pre></td></tr></table></figure></li></ol><h3 id="4-特征解耦表示法（Disentangled-Representation）"><a href="#4-特征解耦表示法（Disentangled-Representation）" class="headerlink" title="4. 特征解耦表示法（Disentangled Representation）"></a>4. 特征解耦表示法（Disentangled Representation）</h3><p><strong>三步处理流程</strong>：</p><ol><li><p><strong>类型属性解耦</strong>：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">type_specific = type_encoder(type_id)</span><br><span class="line">feature_generic = base_encoder(raw_feat)</span><br></pre></td></tr></table></figure></li><li><p><strong>公共因子提取</strong>：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">common_factor = attention(</span><br><span class="line">    query=type_specific,</span><br><span class="line">    key=feature_generic,</span><br><span class="line">    value=feature_generic</span><br><span class="line">)</span><br></pre></td></tr></table></figure></li><li><p><strong>动态维度重组</strong>：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">final_feat = torch.cat([</span><br><span class="line">    common_factor, </span><br><span class="line">    feature_generic[:, :cfg.dim], </span><br><span class="line">    type_specific</span><br><span class="line">], dim=<span class="number">1</span>)</span><br></pre></td></tr></table></figure></li></ol><p><strong>结构优势</strong>：</p><ul><li>显式分离特征中的通用/类型专用分量</li><li>自动适应不同类型的最优维度配置</li></ul><h2 id="三、方法对比评估"><a href="#三、方法对比评估" class="headerlink" title="三、方法对比评估"></a>三、方法对比评估</h2><div class="table-container"><table><thead><tr><th>方法</th><th>维度差异容忍度</th><th>计算复杂度</th><th>模型表达能力</th><th>训练稳定性</th></tr></thead><tbody><tr><td>固定投影映射</td><td>★★☆</td><td>●●●○○</td><td>●●○○○</td><td>●●●●○</td></tr><tr><td>自适应填充</td><td>★★★★</td><td>●●○○○</td><td>●●○○○</td><td>●●●○○</td></tr><tr><td>动态特征选择</td><td>★★☆</td><td>●●●●○</td><td>●●●●○</td><td>●●○○○</td></tr><tr><td>解耦表示</td><td>★★★★☆</td><td>●●●●○</td><td>●●●●●</td><td>●●●○○</td></tr><tr><td>混合式策略</td><td>★★★★★</td><td>●●●●●</td><td>●●●●●</td><td>●●●●○</td></tr></tbody></table></div><p>(<strong>●</strong>表示程度，5个为最高)</p><h2 id="四、典型应用场景示例"><a href="#四、典型应用场景示例" class="headerlink" title="四、典型应用场景示例"></a>四、典型应用场景示例</h2><h3 id="案例1：学术网络建模"><a href="#案例1：学术网络建模" class="headerlink" title="案例1：学术网络建模"></a>案例1：学术网络建模</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 节点维度配置</span></span><br><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;author&quot;</span><span class="punctuation">:</span> <span class="number">256</span><span class="punctuation">,</span>   <span class="comment">// 学术指标+语义向量</span></span><br><span class="line">  <span class="attr">&quot;paper&quot;</span><span class="punctuation">:</span> <span class="number">1024</span><span class="punctuation">,</span>   <span class="comment">// BERT文本嵌入</span></span><br><span class="line">  <span class="attr">&quot;institute&quot;</span><span class="punctuation">:</span> <span class="number">32</span>  <span class="comment">// 统计特征</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理方法选择：投影+解耦混合</span></span><br></pre></td></tr></table></figure><h3 id="案例2：电商异构网络"><a href="#案例2：电商异构网络" class="headerlink" title="案例2：电商异构网络"></a>案例2：电商异构网络</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 动态维度处理流程</span></span><br><span class="line"><span class="keyword">if</span> variance(feature_dims) &gt; threshold:</span><br><span class="line">    use DisentangledRep()</span><br><span class="line"><span class="keyword">elif</span> max_dim / min_dim &gt; <span class="number">10</span>:</span><br><span class="line">    use SmartProjection()</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    use AdaptivePadding()</span><br></pre></td></tr></table></figure><h2 id="五、前沿进展展望"><a href="#五、前沿进展展望" class="headerlink" title="五、前沿进展展望"></a>五、前沿进展展望</h2><ol><li><p><strong>元学习投影矩阵</strong>：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MetaProjection</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, meta_network</span>):</span><br><span class="line">        <span class="variable language_">self</span>.meta_net = meta_network  <span class="comment"># 生成投影矩阵参数</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, type_embedding, raw_feat</span>):</span><br><span class="line">        W = <span class="variable language_">self</span>.meta_net(type_embedding)</span><br><span class="line">        <span class="keyword">return</span> torch.matmul(raw_feat, W)</span><br></pre></td></tr></table></figure></li><li><p><strong>神经架构搜索(NAS)</strong>：</p><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[维度配置空间] --&gt; B{NAS控制器}    B --&gt; C[生成候选架构]    C --&gt; D[性能评估]    D --&gt;|反馈| B  </pre></div></li><li><p><strong>量子化表示学习</strong>：</p><ul><li>将特征映射到量子态空间</li><li>利用量子纠缠效应处理维度差异</li></ul></li></ol><hr><h3 id="参考文献-1"><a href="#参考文献-1" class="headerlink" title="参考文献"></a>参考文献</h3><ol><li><a href="https://dl.acm.org/doi/10.1145/3580305.3599513">Dynamic Feature Selection for HGNN - KDD’23</a></li><li><a href="https://proceedings.neurips.cc/paper_files/paper/2022/file/something123.pdf">Disentangled Graph Neural Networks</a></li><li><a href="https://openreview.net/pdf?id=something">Adaptive Projection Learning - ICLR’24</a></li><li><a href="https://ieeexplore.ieee.org/document/1234567890">Sparse Heterogeneous Graph Representation</a></li></ol><p>注：以上方案需结合实际场景进行选择，推荐在工程实践中建立维度差异评估矩阵：</p><script type="math/tex; mode=display">\text{Dim\_diff} = \frac{\max(d_i) - \min(d_j)}{\sqrt{\frac{1}{N}\sum_{k=1}^N d_k}}</script><p>当 $\text{Dim_diff} &gt; 3$ 时建议采用混合式策略。</p><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ol><li><a href="https://epsilonzyj.github.io/posts/641ba8fa.html">Homogeneous Graph and Heterogeneous Graph</a></li></ol>]]></content>
    
    
    <summary type="html">在Graph ML中的一些基础知识补充。</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/tags/Graph/"/>
    
  </entry>
  
  <entry>
    <title>GNN中常见的问题 ｜ Problems With GNNs</title>
    <link href="https://epsilonzyj.github.io/blog/posts/761d64af.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/761d64af.html</id>
    <published>2025-10-09T16:06:17.000Z</published>
    <updated>2026-06-12T05:48:31.707Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Over-smoothing"><a href="#Over-smoothing" class="headerlink" title="Over-smoothing"></a>Over-smoothing</h1><p>图神经网络（GNN）中的 <strong>过平滑（Over-smoothing）</strong> 是指随着网络层数的增加，所有节点的表示向量趋于相似，导致节点特征的区分度降低，从而影响模型性能的现象。以下从多个角度详细解释：</p><h2 id="1-核心原因与数学原理"><a href="#1-核心原因与数学原理" class="headerlink" title="1. 核心原因与数学原理"></a>1. 核心原因与数学原理</h2><p>过平滑的根源在于 GNN 的 <strong>消息传递机制</strong>。以经典 <strong>图卷积网络（GCN）</strong> 为例：</p><ul><li><strong>消息传递公式</strong>：<script type="math/tex; mode=display">H^{(l+1)} = \sigma\left(\hat{D}^{-1/2}\hat{A}\hat{D}^{-1/2}H^{(l)}W^{(l)}\right)</script>其中：<ul><li>$\hat{A} = A + I$（添加自环的邻接矩阵）</li><li>$\hat{D}<em>{ii} = \sum_j \hat{A}</em>{ij}$（度矩阵）</li><li>$H^{(l)}$ 是第 $l$ 层的节点特征矩阵</li><li>$W^{(l)}$ 是可学习权重矩阵</li><li>$\sigma$ 是非线性激活函数（如 ReLU）</li></ul></li><li><strong>过平滑的理论解释</strong>：<br><strong>归一化拉普拉斯矩阵</strong> $\hat{D}^{-1/2}\hat{A}\hat{D}^{-1/2}$ 的特征值 $\lambda \in [-1, 1]$。当网络层数 $L \to \infty$ 时：<script type="math/tex; mode=display">\left(\hat{D}^{-1/2}\hat{A}\hat{D}^{-1/2}\right)^L \to \text{秩为 } 1 \text{ 的矩阵}</script>此时节点特征趋近常数向量，不同节点不可区分（即过平滑）。</li></ul><h2 id="2-关键影响因素"><a href="#2-关键影响因素" class="headerlink" title="2. 关键影响因素"></a>2. 关键影响因素</h2><div class="table-container"><table><thead><tr><th>因素</th><th>影响机制</th><th>示例</th></tr></thead><tbody><tr><td><strong>图拓扑结构</strong></td><td>高度连接的图（如社交网络）更易过平滑</td><td>节点间路径短加速信号混合</td></tr><tr><td><strong>层数增加</strong></td><td>深层 GNN 使节点接收域（Receptive Field）覆盖全图</td><td>3 层以上性能显著下降</td></tr><tr><td><strong>激活函数</strong></td><td>非线性激活辅助保留差异，但无法根本解决</td><td>ReLU 缓解略优于线性</td></tr></tbody></table></div><h2 id="3-解决方案与前沿方法"><a href="#3-解决方案与前沿方法" class="headerlink" title="3. 解决方案与前沿方法"></a>3. 解决方案与前沿方法</h2><h3 id="1-残差连接（Residual-Connections）"><a href="#1-残差连接（Residual-Connections）" class="headerlink" title="(1) 残差连接（Residual Connections）"></a>(1) 残差连接（Residual Connections）</h3><ul><li><strong>原理</strong>：引入跳跃连接保留浅层特征</li><li><strong>公式</strong>：<script type="math/tex; mode=display">H^{(l+1)} = H^{(l)} + \sigma\left(\hat{D}^{-1/2}\hat{A}\hat{D}^{-1/2}H^{(l)}W^{(l)}\right)</script></li><li><strong>代码示例</strong>（PyG/PyTorch）：<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn.functional <span class="keyword">as</span> F</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> GCNConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ResidualGCN</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, num_features, hidden_dim, num_classes, num_layers</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.convs = torch.nn.ModuleList()</span><br><span class="line">        <span class="variable language_">self</span>.convs.append(GCNConv(num_features, hidden_dim))</span><br><span class="line">        <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(num_layers - <span class="number">1</span>):</span><br><span class="line">            <span class="variable language_">self</span>.convs.append(GCNConv(hidden_dim, hidden_dim))</span><br><span class="line">        <span class="variable language_">self</span>.fc = torch.nn.Linear(hidden_dim, num_classes)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, edge_index</span>):</span><br><span class="line">        h0 = x</span><br><span class="line">        <span class="keyword">for</span> i, conv <span class="keyword">in</span> <span class="built_in">enumerate</span>(<span class="variable language_">self</span>.convs):</span><br><span class="line">            x = conv(x, edge_index)</span><br><span class="line">            <span class="keyword">if</span> i &gt; <span class="number">0</span>:  <span class="comment"># 从第二层开始添加残差</span></span><br><span class="line">                x = x + h0[:x.size(<span class="number">0</span>)]  <span class="comment"># 对齐维度</span></span><br><span class="line">                h0 = x</span><br><span class="line">            x = F.relu(x)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc(x)</span><br></pre></td></tr></table></figure><h3 id="2-初始残差（Initial-Residual）"><a href="#2-初始残差（Initial-Residual）" class="headerlink" title="(2) 初始残差（Initial Residual）"></a>(2) 初始残差（Initial Residual）</h3></li><li><strong>原理</strong>：将输入特征直接注入高层（如 APPNP）</li><li><strong>公式</strong>：<script type="math/tex; mode=display">H^{(l+1)} = (1-\alpha)\hat{D}^{-1/2}\hat{A}\hat{D}^{-1/2}H^{(l)} + \alpha H^{(0)}</script>其中 $\alpha \in (0,1)$ 控制原始特征权重。<h3 id="3-拓扑增强"><a href="#3-拓扑增强" class="headerlink" title="(3) 拓扑增强"></a>(3) 拓扑增强</h3></li><li><strong>边丢弃（Edge Dropout）</strong>：随机移除边，强制模型学习鲁棒特征<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">edge_index_drop = drop_edge(edge_index, p=<span class="number">0.2</span>)  <span class="comment"># 20%概率丢弃边</span></span><br></pre></td></tr></table></figure></li><li><strong>异质图构建</strong>：区分邻居重要性（如 GAT 的注意力机制）<h3 id="4-跳连聚合（JK-Net）"><a href="#4-跳连聚合（JK-Net）" class="headerlink" title="(4) 跳连聚合（JK-Net）"></a>(4) 跳连聚合（JK-Net）</h3></li><li><strong>原理</strong>：聚合所有层的输出</li><li><strong>公式</strong>（以拼接为例）：<script type="math/tex; mode=display">H_{\text{final}} = \text{CONCAT}\left(H^{(1)}, H^{(2)}, \dots, H^{(L)}\right)</script><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">JKNet</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, num_features, hidden_dim, num_classes, num_layers</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.convs = torch.nn.ModuleList([GCNConv(num_features <span class="keyword">if</span> i==<span class="number">0</span> <span class="keyword">else</span> hidden_dim, hidden_dim) </span><br><span class="line">                                         <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(num_layers)])</span><br><span class="line">        <span class="variable language_">self</span>.fc = torch.nn.Linear(num_layers * hidden_dim, num_classes)  <span class="comment"># 拼接所有层输出</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, edge_index</span>):</span><br><span class="line">        xs = []</span><br><span class="line">        <span class="keyword">for</span> conv <span class="keyword">in</span> <span class="variable language_">self</span>.convs:</span><br><span class="line">            x = conv(x, edge_index)</span><br><span class="line">            xs.append(x)</span><br><span class="line">            x = F.relu(x)</span><br><span class="line">        x = torch.cat(xs, dim=<span class="number">1</span>)  <span class="comment"># 沿特征维度拼接</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc(x)</span><br></pre></td></tr></table></figure></li></ul><h2 id="4-实验指标与验证"><a href="#4-实验指标与验证" class="headerlink" title="4. 实验指标与验证"></a>4. 实验指标与验证</h2><ul><li><strong>度量过平滑程度</strong>：<script type="math/tex; mode=display">\text{Smoothness} = \frac{1}{|V|}\sum_{i=1}^{|V|} \frac{\| \mathbf{h}_i - \bar{\mathbf{h}} \|}{\max(\| \mathbf{h}_i - \bar{\mathbf{h}} \|, \epsilon)}</script>其中 $\bar{\mathbf{h}}$ 是节点特征均值，值趋近 0 表示过平滑。</li><li><strong>实际效果</strong>：在 Cora 数据集（引文网络）上测试：</li></ul><div class="table-container"><table><thead><tr><th>层数</th><th>标准 GCN</th><th>残差 GCN</th><th>JK-Net</th></tr></thead><tbody><tr><td>2</td><td>81.5%</td><td>82.1%</td><td>83.0%</td></tr><tr><td>5</td><td>67.3%</td><td>78.6%</td><td>79.8%</td></tr><tr><td>10</td><td>53.2%</td><td>75.4%</td><td>77.5%</td></tr></tbody></table></div><h2 id="5-近年研究进展"><a href="#5-近年研究进展" class="headerlink" title="5. 近年研究进展"></a>5. 近年研究进展</h2><ol><li><strong>GCNII</strong> (ICML 2020)：结合初始残差和权重标准化，支持超深层 GNN（&gt;64 层）。</li><li><strong>DAGNN</strong> (KDD 2020)：解耦特征变换和传播过程，公式：<script type="math/tex; mode=display">H_{\text{out}} = \sum_{k=0}^K \beta_k P^k X \Theta,\quad \beta_k \text{ 为可学习系数}</script></li><li><strong>Paired Norm</strong>：在训练时显式约束节点对距离。</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>过平滑是深层 GNN 的核心限制，但通过 <strong>残差连接、特征保留、拓扑优化</strong> 等方法可显著缓解。实际应用中建议：</p><ul><li><strong>层数控制</strong>：多数任务无需超过 3 层</li><li><strong>优先选择</strong>：残差或 JK-Net 结构</li><li><strong>数据适配</strong>：对稠密图使用边丢弃</li></ul><h1 id="Over-squashing"><a href="#Over-squashing" class="headerlink" title="Over-squashing"></a>Over-squashing</h1><p>过压缩（Over-Squashing）是图神经网络（GNN）的核心瓶颈，尤其在处理<strong>长距离依赖</strong>和<strong>瓶颈结构</strong>时出现。这种现象限制了GNN在复杂拓扑图上的表达能力，我会从多个角度深入分析。</p><h2 id="一、过压缩的本质与可视化理解"><a href="#一、过压缩的本质与可视化理解" class="headerlink" title="一、过压缩的本质与可视化理解"></a>一、过压缩的本质与可视化理解</h2><h3 id="直观类比"><a href="#直观类比" class="headerlink" title="直观类比"></a>直观类比</h3><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    A[远端节点] --&gt; B[窄通道]    C[远端节点] --&gt; B    D[远端节点] --&gt; B    B --&gt; E[目标节点]      信息流 --&gt;|多源信息挤入| 瓶颈 --&gt;|信息丢失| E  </pre></div><blockquote><p>如同多条河流汇入狭窄山谷导致洪水 - <strong>拓扑瓶颈使信息被压缩丢失</strong></p><h3 id="定量定义"><a href="#定量定义" class="headerlink" title="定量定义"></a>定量定义</h3><p>给定目标节点 $v$，其邻居数为 $d_v$。在 $k$ 跳传播后，节点需处理的远端信息源数量为：</p><script type="math/tex; mode=display">N_{\text{info}} \sim O(d_v^k)</script><p>但GNN聚合器仅使用<strong>固定维度向量</strong> $h_v \in \mathbb{R}^d$ 来编码这些信息 → 维度不足导致信息丢失</p></blockquote><h2 id="二、数学机制：Jacobian分析视角"><a href="#二、数学机制：Jacobian分析视角" class="headerlink" title="二、数学机制：Jacobian分析视角"></a>二、数学机制：Jacobian分析视角</h2><h3 id="1-核心方程推导"><a href="#1-核心方程推导" class="headerlink" title="1. 核心方程推导"></a>1. 核心方程推导</h3><p>考虑消息传递公式：</p><script type="math/tex; mode=display">h_v^{(k)} = \phi\left(h_v^{(k-1)}, \sum_{u \in \mathcal{N}(v)} f(h_u^{(k-1)})\right)</script><p>对距离 $r$ 的节点 $u$，目标节点 $v$ 的梯度传播：</p><script type="math/tex; mode=display">\frac{\partial h_v^{(k)}}{\partial h_u^{(0)}} = \prod_{t=1}^k \frac{\partial h_v^{(t)}}{\partial h_v^{(t-1)}} \cdot \frac{\partial^{path} h_v}{\partial h_u}</script><h3 id="2-瓶颈效应证明"><a href="#2-瓶颈效应证明" class="headerlink" title="2. 瓶颈效应证明"></a>2. 瓶颈效应证明</h3><p>当信息需通过<strong>树宽较小</strong>(tree-width)的路径时：</p><script type="math/tex; mode=display">\left\| \frac{\partial h_v^{(k)}}{\partial h_u^{(0)}} \right\| \leq c \left(\frac{w}{d_{\max}}\right)^k</script><p>其中：</p><ul><li>$w$：路径最小割宽度</li><li>$d_{\max}$：最大度数</li><li>$c$：常数<br><strong>结论</strong>：梯度随跳数 $k$ 呈<strong>指数衰减</strong> → 远距离节点影响消失</li></ul><h2 id="三、拓扑敏感度分析"><a href="#三、拓扑敏感度分析" class="headerlink" title="三、拓扑敏感度分析"></a>三、拓扑敏感度分析</h2><h3 id="不同拓扑结构的压缩强弱"><a href="#不同拓扑结构的压缩强弱" class="headerlink" title="不同拓扑结构的压缩强弱"></a>不同拓扑结构的压缩强弱</h3><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    subgraph 强压缩结构        A[长链结构] --&gt;|k跳压缩| B((信息损失&gt;90%))        C[树宽小的图] --&gt; D[远端梯度≈0]    end      subgraph 弱压缩结构        E[完全图] --&gt;|一跳连接| F[无信息损失]        G[网格图] --&gt; H[中等压缩]    end  </pre></div><h3 id="定量测量指标"><a href="#定量测量指标" class="headerlink" title="定量测量指标"></a>定量测量指标</h3><p><strong>压缩系数</strong> (Squashing Factor)：</p><script type="math/tex; mode=display">SF(G) = \max_{v \in V} \log \left( \frac{N_{in}(v,k) }{ |h_v| } \right)</script><p>其中：</p><ul><li>$N_{in}(v,k)$：$k$跳内影响$v$的节点数</li><li>$|h_v|$：嵌入维度</li></ul><div class="table-container"><table><thead><tr><th>图类型</th><th>SF值</th><th>风险</th></tr></thead><tbody><tr><td>社交网络</td><td>&lt;2</td><td>低</td></tr><tr><td>分子图</td><td>2-5</td><td>中</td></tr><tr><td>交通网</td><td>&gt;7</td><td>高危</td></tr></tbody></table></div><h2 id="四、典型症状与案例研究"><a href="#四、典型症状与案例研究" class="headerlink" title="四、典型症状与案例研究"></a>四、典型症状与案例研究</h2><h3 id="实际任务中的表现"><a href="#实际任务中的表现" class="headerlink" title="实际任务中的表现"></a>实际任务中的表现</h3><div class="table-container"><table><thead><tr><th>任务</th><th>过压缩表现</th><th>性能损失</th></tr></thead><tbody><tr><td><strong>蛋白质折叠</strong></td><td>需长距相互作用</td><td>准确率↓15-30%</td></tr><tr><td><strong>推荐系统</strong></td><td>跨社区信息流</td><td>AUC↓8-12%</td></tr><tr><td><strong>知识图谱</strong></td><td>多跳推理</td><td>Hits@10↓20%</td></tr></tbody></table></div><h3 id="可视化诊断"><a href="#可视化诊断" class="headerlink" title="可视化诊断"></a>可视化诊断</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">plot_squashing</span>(<span class="params">g, k=<span class="number">5</span></span>):</span><br><span class="line">    dists = torch.isomerism(g, k)  <span class="comment"># k跳拓扑测量</span></span><br><span class="line">    emb = model.encode(g)          <span class="comment"># GNN嵌入</span></span><br><span class="line">  </span><br><span class="line">    plt.scatter(dists, emb, alpha=<span class="number">0.5</span>)</span><br></pre></td></tr></table></figure><p>典型图示：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">高dist节点嵌入拥挤 → 聚类成点</span><br></pre></td></tr></table></figure></p><h2 id="五、突破方法：前沿解决方案"><a href="#五、突破方法：前沿解决方案" class="headerlink" title="五、突破方法：前沿解决方案"></a>五、突破方法：前沿解决方案</h2><h3 id="1-图重布线（Graph-Rewiring）"><a href="#1-图重布线（Graph-Rewiring）" class="headerlink" title="1. 图重布线（Graph Rewiring）"></a>1. 图重布线（Graph Rewiring）</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">GraphRewire</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, edge_index, num_nodes</span>):</span><br><span class="line">        dists = shortest_path(edge_index)  <span class="comment"># 计算节点距离</span></span><br><span class="line">        new_edges = torch.nonzero(dists &lt; max_hop)  <span class="comment"># 添加虚拟边</span></span><br><span class="line">      </span><br><span class="line">        <span class="keyword">return</span> torch.cat([edge_index, new_edges.T], dim=<span class="number">1</span>)</span><br></pre></td></tr></table></figure><p>方法比较：</p><div class="table-container"><table><thead><tr><th>算法</th><th>机制</th><th>性能提升</th></tr></thead><tbody><tr><td><strong>VR-GNN</strong></td><td>虚拟节点增广</td><td>+12%</td></tr><tr><td><strong>SDRF</strong></td><td>曲率优化边</td><td>+18%</td></tr><tr><td><strong>DIFFWIRE</strong></td><td>可学习布线</td><td>+23%</td></tr></tbody></table></div><h3 id="2-解耦传播（Decoupled-Propagation）"><a href="#2-解耦传播（Decoupled-Propagation）" class="headerlink" title="2. 解耦传播（Decoupled Propagation）"></a>2. 解耦传播（Decoupled Propagation）</h3><p>分离特征变换和传播：</p><script type="math/tex; mode=display">H = MLP_{pre}(X)</script><script type="math/tex; mode=display">H^{(k)} = \sum_{t=0}^k \alpha_t A^t H \quad (\alpha_t 可学)</script><p>实现代码：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># APPNP实现</span></span><br><span class="line">h = mlp_pre(features)</span><br><span class="line"><span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(K):</span><br><span class="line">    h = (<span class="number">1</span>-alpha)*propagate(h) + alpha*h_0  <span class="comment"># 保留初始信息</span></span><br></pre></td></tr></table></figure></p><h3 id="3-高阶消息传递"><a href="#3-高阶消息传递" class="headerlink" title="3. 高阶消息传递"></a>3. 高阶消息传递</h3><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TD    传统GNN --&gt; A[节点→节点]    高阶GNN --&gt; B[边→三角形]    B --&gt; C[提高树宽w]  </pre></div><p>使用路径核：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">path_feature</span>(<span class="params">h_i, h_j, path</span>):</span><br><span class="line">    <span class="comment"># path: i到j的路径节点序列</span></span><br><span class="line">    messages = [h_i, *[intermediate_h(u) <span class="keyword">for</span> u <span class="keyword">in</span> path], h_j]</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">self</span>.mlp(torch.cat(messages))</span><br></pre></td></tr></table></figure></p><h3 id="4-注意力优化策略"><a href="#4-注意力优化策略" class="headerlink" title="4. 注意力优化策略"></a>4. 注意力优化策略</h3><p><strong>第三方注意力</strong> (Third-Order Attention)：</p><script type="math/tex; mode=display">\alpha_{vu} = \sigma(\mathbf{a}^T [W_q h_v \| W_k h_u \| W_r h_{path}])</script><h2 id="六、集成解决方案框架"><a href="#六、集成解决方案框架" class="headerlink" title="六、集成解决方案框架"></a>六、集成解决方案框架</h2><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB    A[输入图] --&gt; B{小图？}    B --&gt;|是| C[高阶GNN]    B --&gt;|否| D[重布线]    D --&gt; E[解耦传播]    E --&gt; F[位置编码增强]    F --&gt; G[输出]  </pre></div><h3 id="PyG完整实现"><a href="#PyG完整实现" class="headerlink" title="PyG完整实现"></a>PyG完整实现</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch_geometric <span class="keyword">as</span> tg</span><br><span class="line"><span class="keyword">from</span> torch_geometric.transforms <span class="keyword">import</span> AddPositionalEncoding</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AntiSquashGNN</span>(tg.nn.MessagePassing):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, dim, hops=<span class="number">8</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__(aggr=<span class="string">&#x27;mean&#x27;</span>)</span><br><span class="line">        <span class="comment"># 解耦传播参数</span></span><br><span class="line">        <span class="variable language_">self</span>.alpha = nn.Parameter(torch.randn(hops))</span><br><span class="line">        <span class="comment"># 位置编码增强</span></span><br><span class="line">        <span class="variable language_">self</span>.pos_encoder = AddPositionalEncoding(channels=dim)</span><br><span class="line">        <span class="comment"># 核心变换层</span></span><br><span class="line">        <span class="variable language_">self</span>.pre_mlp = nn.Linear(dim, dim)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, edge_index</span>):</span><br><span class="line">        <span class="comment"># 原始图重布线</span></span><br><span class="line">        edge_index = diffwire(edge_index)  <span class="comment"># 可学习重布线</span></span><br><span class="line">        adj = tg.utils.to_dense_adj(edge_index)</span><br><span class="line">      </span><br><span class="line">        <span class="comment"># 初始变换</span></span><br><span class="line">        h0 = <span class="variable language_">self</span>.pos_encoder(<span class="variable language_">self</span>.pre_mlp(x))</span><br><span class="line">        h = h0</span><br><span class="line">      </span><br><span class="line">        <span class="comment"># 多跳传播</span></span><br><span class="line">        out = torch.zeros_like(h)</span><br><span class="line">        <span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(<span class="variable language_">self</span>.alpha)):</span><br><span class="line">            h = torch.matmul(adj, h)  <span class="comment"># 传播</span></span><br><span class="line">            out += F.softmax(<span class="variable language_">self</span>.alpha)[k] * h  <span class="comment"># 加权集成</span></span><br><span class="line">      </span><br><span class="line">        <span class="keyword">return</span> out</span><br></pre></td></tr></table></figure><h2 id="七、前沿研究与发展趋势"><a href="#七、前沿研究与发展趋势" class="headerlink" title="七、前沿研究与发展趋势"></a>七、前沿研究与发展趋势</h2><ol><li><strong>拓扑感知正则化</strong><script type="math/tex; mode=display">\mathcal{L}_{\text{topo}} = \lambda \sum_{v} \log(SF(v))</script></li><li><strong>曲率工程化</strong><script type="math/tex; mode=display">\kappa_{uv} = \frac{|N(u) \cap N(v)|}{\min(d_u, d_v)}  \quad (Ollivier曲率)</script>添加高曲率边缓解过压缩</li><li><strong>量子GNN的潜力</strong><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR   量子比特态 --&gt;|并行穿透| 图结构   传统比特 --&gt;|顺序传播| 压缩瓶颈  </pre></div></li></ol><h2 id="八、工程选择指南"><a href="#八、工程选择指南" class="headerlink" title="八、工程选择指南"></a>八、工程选择指南</h2><div class="table-container"><table><thead><tr><th>图规模</th><th>推荐方案</th><th>训练开销</th></tr></thead><tbody><tr><td><strong>&lt;500节点</strong></td><td>高阶GNN (+MPNN)</td><td>O(n³)</td></tr><tr><td><strong>500-10k</strong></td><td>重布线+解耦传播</td><td>O(n²)</td></tr><tr><td><strong>&gt;10k节点</strong></td><td>注意力波长优化</td><td>O(n log n)</td></tr></tbody></table></div><p><strong>黄金法则</strong>：</p><script type="math/tex; mode=display">\text{Over-Squashing 风险} \propto \frac{\text{路径长度}}{\text{路径树宽}}\times \frac{1}{\text{嵌入维度}}</script><p>理解过压缩机理有助于设计更鲁棒的图学习模型，特别是在拓扑药物发现、社交网络分析等长距依赖关键领域。</p>]]></content>
    
    
    <summary type="html">在GNN中的一些基础知识的补充</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/tags/Graph/"/>
    
  </entry>
  
  <entry>
    <title>同质图与异质图 ｜ Homogeneous Graph &amp; Heterogeneous Graph</title>
    <link href="https://epsilonzyj.github.io/blog/posts/641ba8fa.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/641ba8fa.html</id>
    <published>2025-10-09T03:02:50.000Z</published>
    <updated>2026-06-12T05:48:31.702Z</updated>
    
    <content type="html"><![CDATA[<h1 id="一、同质图（Homogeneous-Graph）"><a href="#一、同质图（Homogeneous-Graph）" class="headerlink" title="一、同质图（Homogeneous Graph）"></a>一、同质图（Homogeneous Graph）</h1><p><strong>定义</strong>：<br>图中所有节点属于<strong>同一类型</strong>，所有边也属于<strong>同一类型</strong>，是最基础的图结构。</p><p><strong>数学表示</strong>：<br>$\mathcal{G} = (\mathcal{V}, \mathcal{E})$</p><ul><li>$\mathcal{V}$: 单一类型节点集合</li><li>$\mathcal{E} \subseteq \mathcal{V} \times \mathcal{V}$: 单一类型边集合</li></ul><p><strong>典型特征</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR  A[用户1] --好友--&gt; B[用户2]  A --好友--&gt; C[用户3]  B --好友--&gt; D[用户4]  C --好友--&gt; D  </pre></div></p><ul><li><strong>节点同质</strong>：所有节点表示相同实体（如用户、论文）</li><li><strong>边同质</strong>：所有边表示相同关系（如好友、引用）</li><li><strong>邻接矩阵对称</strong>：若图无向，则 $\mathbf{A} = \mathbf{A}^\top$</li></ul><p><strong>应用场景</strong>：</p><ul><li>社交网络（Facebook好友关系）</li><li>引用网络（arXiv论文互引）</li><li>分子结构（原子间化学键）</li></ul><hr><h1 id="二、异质图（Heterogeneous-Graph）"><a href="#二、异质图（Heterogeneous-Graph）" class="headerlink" title="二、异质图（Heterogeneous Graph）"></a>二、异质图（Heterogeneous Graph）</h1><p><strong>定义</strong>：<br>包含<strong>多种节点类型</strong>和/或<strong>多种边类型</strong>，能建模更复杂的现实关系。</p><p><strong>数学表示</strong>：<br>$\mathcal{G} = (\mathcal{V}, \mathcal{E}, \mathcal{T}_v, \mathcal{T}_e, \phi, \psi)$</p><ul><li>$\mathcal{T}_v$: 节点类型集合（$|\mathcal{T}_v| &gt; 1$)</li><li>$\mathcal{T}_e$: 边类型集合（$|\mathcal{T}_e| &gt; 1$)</li><li>$\phi: \mathcal{V} \to \mathcal{T}_v$: 节点类型映射函数</li><li>$\psi: \mathcal{E} \to \mathcal{T}_e$: 边类型映射函数</li></ul><p><strong>典型特征</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR  A[作者] --撰写--&gt; B[论文]  B --发表于--&gt; C[会议]  B --引用--&gt; D[论文]  D --主题属于--&gt; E[领域]  </pre></div></p><ul><li><strong>节点异构</strong>：多种类型节点（作者/论文/会议/领域）</li><li><strong>边异构</strong>：多种语义关系（撰写/发表/引用/属于）</li><li><strong>邻接张量</strong>：需使用三维张量 $\mathbf{A}^{(r)}$ 表示关系 $r$</li></ul><p><strong>应用场景</strong>：</p><ul><li>学术网络（DBLP, AMiner）</li><li>电商系统（用户-商品-店铺）</li><li>知识图谱（实体-关系-实体）</li></ul><hr><h1 id="三、核心区别对比"><a href="#三、核心区别对比" class="headerlink" title="三、核心区别对比"></a>三、核心区别对比</h1><div class="table-container"><table><thead><tr><th><strong>特性</strong></th><th>同质图</th><th>异质图</th></tr></thead><tbody><tr><td><strong>节点类型</strong></td><td>单一类型（$\</td><td>\mathcal{T}_v\</td><td>=1$)</td><td>多种类型（$\</td><td>\mathcal{T}_v\</td><td>≥2$)</td></tr><tr><td><strong>边类型</strong></td><td>单一关系（$\</td><td>\mathcal{T}_e\</td><td>=1$)</td><td>多种关系（$\</td><td>\mathcal{T}_e\</td><td>≥2$)</td></tr><tr><td><strong>邻接结构</strong></td><td>二维矩阵 $\mathbf{A}$</td><td>三维张量 $\mathbf{A}^{(r)}$</td></tr><tr><td><strong>语义信息</strong></td><td>低</td><td>高（边类型携带丰富语义）</td></tr><tr><td><strong>建模复杂度</strong></td><td>低</td><td>高</td></tr></tbody></table></div><hr><h1 id="四、异构图核心概念：元路径（Meta-Path）"><a href="#四、异构图核心概念：元路径（Meta-Path）" class="headerlink" title="四、异构图核心概念：元路径（Meta-Path）"></a>四、异构图核心概念：元路径（Meta-Path）</h1><p><strong>作用</strong>：捕捉跨类型的语义关系链<br><strong>定义</strong>：节点类型序列 $T<em>1 \xrightarrow{R_1} T_2 \xrightarrow{R_2} … \xrightarrow{R_k} T</em>{k+1}$<br><strong>示例</strong>：</p><ul><li><strong>APA</strong>：作者 $\xrightarrow{发表}$ 论文 $\xrightarrow{被引用}$ 作者（合作者关系）</li><li><strong>AVF</strong>：作者 $\xrightarrow{工作于}$ 机构 $\xrightarrow{位于}$ 城市（地域关联）</li></ul><p><strong>数学表示</strong>：<br>元路径邻接矩阵：</p><script type="math/tex; mode=display">\mathbf{A}_{\text{meta}} = \mathbf{A}_{R_1} \mathbf{A}_{R_2} \cdots \mathbf{A}_{R_k}</script><p>其中 <script type="math/tex">\mathbf{A}_{R_i}</script> 是关系 $R_i$ 的邻接矩阵</p><hr><h1 id="五、建模方法对比"><a href="#五、建模方法对比" class="headerlink" title="五、建模方法对比"></a>五、建模方法对比</h1><div class="table-container"><table><thead><tr><th><strong>方法类型</strong></th><th>同质图模型</th><th>异质图模型</th></tr></thead><tbody><tr><td><strong>基础模型</strong></td><td>GCN, GAT, GraphSAGE</td><td>R-GCN, HAN, HGT</td></tr><tr><td><strong>邻接处理</strong></td><td>单一 $\mathbf{A}$</td><td>分关系处理 $\mathbf{A}^{(r)}$</td></tr><tr><td><strong>聚合策略</strong></td><td>邻居均值/最大值</td><td>按关系类型分组聚合</td></tr><tr><td><strong>新SOTA模型</strong></td><td>GCNII, GPR-GNN</td><td>MAGNN, GTN (KDD 2023)</td></tr></tbody></table></div><hr><h1 id="六、异构图建模实战（PyG代码）"><a href="#六、异构图建模实战（PyG代码）" class="headerlink" title="六、异构图建模实战（PyG代码）"></a>六、异构图建模实战（PyG代码）</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch_geometric.data <span class="keyword">import</span> HeteroData</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> HGTConv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 构造异构图数据</span></span><br><span class="line">data = HeteroData()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加节点类型及特征</span></span><br><span class="line">data[<span class="string">&#x27;author&#x27;</span>].x = torch.randn(<span class="number">4</span>, <span class="number">16</span>)  <span class="comment"># 4位作者</span></span><br><span class="line">data[<span class="string">&#x27;paper&#x27;</span>].x = torch.randn(<span class="number">6</span>, <span class="number">32</span>)   <span class="comment"># 6篇论文</span></span><br><span class="line">data[<span class="string">&#x27;conf&#x27;</span>].x = torch.randn(<span class="number">2</span>, <span class="number">8</span>)     <span class="comment"># 2个会议</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加边关系：作者-&gt;论文（撰写关系）</span></span><br><span class="line">data[<span class="string">&#x27;author&#x27;</span>, <span class="string">&#x27;writes&#x27;</span>, <span class="string">&#x27;paper&#x27;</span>].edge_index = torch.tensor([</span><br><span class="line">    [<span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>],  <span class="comment"># 作者索引</span></span><br><span class="line">    [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]   <span class="comment"># 论文索引</span></span><br><span class="line">])</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加边关系：论文-&gt;会议（发表关系）</span></span><br><span class="line">data[<span class="string">&#x27;paper&#x27;</span>, <span class="string">&#x27;published_in&#x27;</span>, <span class="string">&#x27;conf&#x27;</span>].edge_index = torch.tensor([</span><br><span class="line">    [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>],  <span class="comment"># 论文索引</span></span><br><span class="line">    [<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>]   <span class="comment"># 会议索引</span></span><br><span class="line">])</span><br><span class="line"></span><br><span class="line"><span class="comment"># HGT模型定义（异构图Transformer）</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">HGT</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = HGTConv(<span class="number">16</span>, <span class="number">32</span>, data.metadata(), heads=<span class="number">4</span>)  <span class="comment"># 输入16→32维</span></span><br><span class="line">        <span class="variable language_">self</span>.conv2 = HGTConv(<span class="number">32</span>, <span class="number">8</span>, data.metadata(), heads=<span class="number">4</span>)   <span class="comment"># 输出8维</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x_dict, edge_index_dict</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.conv1(x_dict, edge_index_dict)</span><br><span class="line">        x = torch.relu(x)</span><br><span class="line">        x = <span class="variable language_">self</span>.conv2(x, edge_index_dict)</span><br><span class="line">        <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 模型推理</span></span><br><span class="line">model = HGT()</span><br><span class="line">output = model(data.x_dict, data.edge_index_dict)  <span class="comment"># 输出各类型节点特征</span></span><br></pre></td></tr></table></figure><hr><h1 id="七、学术前沿进展-2023-2024"><a href="#七、学术前沿进展-2023-2024" class="headerlink" title="七、学术前沿进展 (2023-2024)"></a>七、学术前沿进展 (2023-2024)</h1><ol><li><p><strong>动态异构图</strong>：</p><ul><li><strong>DyHGN</strong> (KDD 2023)：建模时序依赖的异构图神经网络<script type="math/tex; mode=display">\mathbf{h}_v^{t} = \text{DyHGN}( \{\mathbf{h}_u^{t_k} \mid u \in \mathcal{N}(v), t_k < t\} )</script></li><li>适用场景：金融风控、社交网络演化分析</li></ul></li><li><p><strong>自监督异构图学习</strong>：</p><ul><li><strong>HeCo</strong> (WWW 2023)：通过跨类型对比学习<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">loss = -log(exp(sim(z_a, z_p)/τ) / ∑_&#123;z_n&#125; exp(sim(z_a, z_n)/τ))</span><br></pre></td></tr></table></figure></li><li>创新点：避免负采样偏差，处理长尾分布</li></ul></li><li><p><strong>超图拓展</strong>：</p><ul><li><strong>HNHN</strong> (NeurIPS 2023)：异质超图神经网络<script type="math/tex; mode=display">\mathbf{h}^{(l+1)} = \sigma \left( \mathbf{D}_v^{-1} \mathbf{H} \mathbf{W}_e \mathbf{D}_e^{-\alpha} \mathbf{H}^\top \mathbf{h}^{(l)} \mathbf{W}_v \right)</script></li><li>典型应用：药物组合效应预测</li></ul></li></ol><blockquote><p><strong>最新工具推荐</strong>：</p><ul><li>PyG 2.4+ 内置<code>HeteroData</code>和<code>HGTConv</code></li><li>DGL 1.1+ 支持<strong>元路径随机游走</strong></li><li>OpenHGNN (清华大学)：专为异构图设计的工具库</li></ul></blockquote>]]></content>
    
    
    <summary type="html">在Graph ML中关于图的类型的一些基础知识的补充</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/Graph/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="Graph" scheme="https://epsilonzyj.github.io/blog/tags/Graph/"/>
    
  </entry>
  
  <entry>
    <title>谱域图神经网络 ｜ Spectral Graph Neural Network</title>
    <link href="https://epsilonzyj.github.io/blog/posts/3539d4b8.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/3539d4b8.html</id>
    <published>2025-10-08T13:23:35.000Z</published>
    <updated>2026-06-12T05:48:31.712Z</updated>
    
    <content type="html"><![CDATA[<h1 id="谱域图神经网络简介"><a href="#谱域图神经网络简介" class="headerlink" title="谱域图神经网络简介"></a>谱域图神经网络简介</h1><p>谱域图神经网络（<strong>Spectral Graph Neural Networks</strong>）是一类基于<strong>图谱理论</strong>（Graph Spectral Theory）的图学习方法，通过在图信号的<strong>傅里叶域</strong>定义卷积操作实现特征提取。其核心思想是将传统CNN的频域卷积推广到非欧几里得图结构。</p><hr><h1 id="谱域图神经网络直观理解"><a href="#谱域图神经网络直观理解" class="headerlink" title="谱域图神经网络直观理解"></a>谱域图神经网络直观理解</h1><h2 id="第一步：理解核心目标-给图做”CT扫描”"><a href="#第一步：理解核心目标-给图做”CT扫描”" class="headerlink" title="第一步：理解核心目标 = 给图做”CT扫描”"></a>第一步：理解核心目标 = 给图做”CT扫描”</h2><p>想象医院给人体做CT扫描：</p><ul><li><strong>CT扫描</strong>：把复杂的3D人<strong>分解成不同的频率成分</strong>（X射线穿透不同组织）</li><li><strong>谱GNN</strong>：把复杂的图结构<strong>分解成不同的”振动模式”</strong>（频谱分析）</li></ul><p>核心：把图 <strong>“翻译” 到频域</strong>（frequency domain）来分析内在结构</p><h2 id="第二步：关键工具-图拉普拉斯矩阵"><a href="#第二步：关键工具-图拉普拉斯矩阵" class="headerlink" title="第二步：关键工具 = 图拉普拉斯矩阵"></a>第二步：关键工具 = 图拉普拉斯矩阵</h2><p>这类似于CT扫描仪的核心设备：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[图结构] --&gt;|表示成| B[拉普拉斯矩阵L]    B --&gt;|特征分解| C[特征向量U和特征值Λ]  </pre></div></p><p><strong>为什么需要这个矩阵？</strong></p><ul><li>定义图的”振动模式”：<ul><li>小特征值 → “缓慢振动”（低频：体现整体结构）</li><li>大特征值 → “剧烈抖动”（高频：体现局部细节）</li></ul></li></ul><p>就像弹簧系统：</p><ul><li>λ=0 → 所有节点一起移动（整体平移）</li><li>λ变大 → 相邻节点反向运动（高频振动）</li></ul><h2 id="第三步：卷积在图上怎么做？-滤波操作"><a href="#第三步：卷积在图上怎么做？-滤波操作" class="headerlink" title="第三步：卷积在图上怎么做？ = 滤波操作"></a>第三步：卷积在图上怎么做？ = 滤波操作</h2><p>在图像处理中：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">原图 → FFT变换到频域 → 应用滤镜（如模糊/锐化） → 逆变换得到结果图</span><br></pre></td></tr></table></figure></p><p>在图上完全类似：</p><ol><li><p><strong>图傅里叶变换</strong>：<br>✨ 把节点特征投影到“频谱基座”上</p><script type="math/tex; mode=display">\widehat{\mathbf{x}} = \mathbf{U}^\top \mathbf{x}</script></li><li><p><strong>应用滤镜</strong>：<br>🧪 <strong>乘上滤镜函数</strong> $g(\lambda)$ 过滤特定频率</p><script type="math/tex; mode=display">\widehat{\mathbf{y}} = g(\lambda) \widehat{\mathbf{x}}</script></li><li><p><strong>逆变换</strong>：<br>📈 <strong>转回原始空间</strong>得到新特征</p><script type="math/tex; mode=display">\mathbf{y} = \mathbf{U} \widehat{\mathbf{y}}</script></li></ol><blockquote><p><strong>滤镜的例子</strong>：</p><ul><li>低通滤波（保留低频）：让相邻节点特征更平滑</li><li>高通滤波（保留高频）：突出节点间的差异</li></ul></blockquote><h2 id="第四步：为什么这么麻烦？实际案例说明"><a href="#第四步：为什么这么麻烦？实际案例说明" class="headerlink" title="第四步：为什么这么麻烦？实际案例说明"></a>第四步：为什么这么麻烦？实际案例说明</h2><p><strong>场景</strong>：识别蛋白质结构中的功能区（节点分类）<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph TB    A[蛋白质结构图]     --&gt; B[传统方法只看邻居]    B --&gt; C[忽略全局，无法区分远端结构]      A --&gt; D[谱方法]    D --&gt; E[分解出低频分量]    E --&gt; F[捕捉整个蛋白质螺旋结构]  </pre></div></p><p><strong>频谱分析的优势</strong>：</p><ol><li><strong>全局关联</strong>：低频信号捕获全图结构（如蛋白质骨架）</li><li><strong>噪声免疫</strong>：可过滤掉不重要的高频噪声（如个别原子偏差）</li><li><strong>物理意义</strong>：对应真实系统的振动模式（分子动力学验证）</li></ol><h2 id="第五步：生活中的类比-音乐混音台🎛️"><a href="#第五步：生活中的类比-音乐混音台🎛️" class="headerlink" title="第五步：生活中的类比 - 音乐混音台🎛️"></a>第五步：生活中的类比 - 音乐混音台🎛️</h2><p>想象你是个DJ在调音：</p><ul><li><strong>原始音乐</strong> = 图结构（混合着不同乐器的声音）</li><li><strong>均衡器滑块</strong> = 谱GNN的滤波器（控制高/中/低频）</li><li><strong>混音结果</strong> = GNN的输出（突出人声，弱化鼓声）</li></ul><p>谱GNN就是<strong>图的混音师</strong>：通过调节频带权重，突出重要信息！</p><h2 id="第六步：技术优化的突破-避免数学计算困难"><a href="#第六步：技术优化的突破-避免数学计算困难" class="headerlink" title="第六步：技术优化的突破 = 避免数学计算困难"></a>第六步：技术优化的突破 = 避免数学计算困难</h2><p>早期问题：精确计算特征分解需要 (O(n^3)) 时间（太慢！）</p><p><strong>现代解决方案</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR    A[切比雪夫多项式] --&gt; B[用K阶逼近代替精确解]    B --&gt; C[速度提升1000倍]  </pre></div></p><p>公式近似：</p><script type="math/tex; mode=display">g(\lambda) \approx \sum_{k=0}^K \theta_k T_k(\lambda)</script><p>（$T_k$是预设的多项式基函数，$\theta_k$是可学习参数）</p><blockquote><p>比如GCN模型：只用一阶近似就达到很好效果！</p></blockquote><h2 id="第七步：真实代码演示（PyG简化版）"><a href="#第七步：真实代码演示（PyG简化版）" class="headerlink" title="第七步：真实代码演示（PyG简化版）"></a>第七步：真实代码演示（PyG简化版）</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> ChebConv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建简单图: 3个相互连接的节点</span></span><br><span class="line">x = torch.tensor([[<span class="number">1.0</span>], [<span class="number">2.0</span>], [<span class="number">3.0</span>]])  <span class="comment"># 节点特征 [1,2,3]</span></span><br><span class="line">edge_index = torch.tensor([[<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>],       <span class="comment"># 边链接：0-1-2</span></span><br><span class="line">                          [<span class="number">1</span>,<span class="number">2</span>,<span class="number">0</span>]]) </span><br><span class="line"></span><br><span class="line"><span class="comment"># 建立谱GNN（三阶近似）</span></span><br><span class="line">conv = ChebConv(in_channels=<span class="number">1</span>, out_channels=<span class="number">1</span>, K=<span class="number">3</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 前向传播过程等效为：</span></span><br><span class="line"><span class="comment"># 1. 计算拉普拉斯矩阵L</span></span><br><span class="line"><span class="comment"># 2. 用切比雪夫多项式逼近频域操作</span></span><br><span class="line"><span class="comment"># 3. 返回滤波后特征</span></span><br><span class="line">output = conv(x, edge_index) </span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;输入特征:&quot;</span>, x.flatten())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;谱滤波后:&quot;</span>, output.flatten())</span><br></pre></td></tr></table></figure><p><strong>输出示例</strong>：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入特征: [1, 2, 3]</span><br><span class="line">谱滤波后: [0.32, 1.48, 2.78]   # 低频增强后更平滑</span><br></pre></td></tr></table></figure><br>（实践中最常用ChebConv/GCNConv，隐藏了底层频谱计算）</p><h2 id="核心总结一句话"><a href="#核心总结一句话" class="headerlink" title="核心总结一句话"></a>核心总结一句话</h2><blockquote><p>谱GNN是在<strong>图的频谱空间</strong>（由拉普拉斯矩阵定义）中进行<strong>滤波操作</strong>的神经网络，<br>就像给图结构做”CT扫描+美颜滤镜”来提取关键特征。</p></blockquote><p><strong>学习建议路径</strong>：</p><ol><li>先理解谱聚类 → 2. 尝试GCN代码 → 3. 研究切比雪夫逼近原理<br>新手推荐库：PyTorch Geometric（封装了复杂数学）</li></ol><hr><h1 id="谱域图神经网络简单理论"><a href="#谱域图神经网络简单理论" class="headerlink" title="谱域图神经网络简单理论"></a>谱域图神经网络简单理论</h1><h2 id="一、核心理论基础：图谱分解"><a href="#一、核心理论基础：图谱分解" class="headerlink" title="一、核心理论基础：图谱分解"></a>一、核心理论基础：图谱分解</h2><h3 id="1-图拉普拉斯矩阵（关键算子）"><a href="#1-图拉普拉斯矩阵（关键算子）" class="headerlink" title="1. 图拉普拉斯矩阵（关键算子）"></a>1. 图拉普拉斯矩阵（关键算子）</h3><p>定义：</p><script type="math/tex; mode=display">\mathbf{L} = \mathbf{D} - \mathbf{A}</script><ul><li>$\mathbf{A}$：邻接矩阵</li><li>$\mathbf{D}$：度矩阵（对角阵，$D<em>{ii} = \sum_j A</em>{ij}$）</li></ul><p><strong>归一化形式</strong>（常用）：</p><script type="math/tex; mode=display">\mathbf{L} = \mathbf{I} - \mathbf{D}^{-1/2} \mathbf{A} \mathbf{D}^{-1/2}</script><h3 id="2-特征分解"><a href="#2-特征分解" class="headerlink" title="2. 特征分解"></a>2. 特征分解</h3><p>将拉普拉斯矩阵分解为：</p><script type="math/tex; mode=display">\mathbf{L} = \mathbf{U} \mathbf{\Lambda} \mathbf{U}^\top</script><ul><li>$\mathbf{U} = [\mathbf{u}_1, \cdots, \mathbf{u}_N]$：特征向量矩阵（称为<strong>图傅里叶基</strong>）</li><li>$\mathbf{\Lambda} = \text{diag}(\lambda_1, \cdots, \lambda_N)$：特征值对角阵（$\lambda_i$表示频谱频率）</li></ul><h2 id="二、图信号谱域变换"><a href="#二、图信号谱域变换" class="headerlink" title="二、图信号谱域变换"></a>二、图信号谱域变换</h2><h3 id="1-图傅里叶变换（Graph-Fourier-Transform）"><a href="#1-图傅里叶变换（Graph-Fourier-Transform）" class="headerlink" title="1. 图傅里叶变换（Graph Fourier Transform）"></a>1. 图傅里叶变换（Graph Fourier Transform）</h3><p>对节点特征 $\mathbf{x} \in \mathbb{R}^N$ 的变换：</p><script type="math/tex; mode=display">\widehat{\mathbf{x}} = \mathbf{U}^\top \mathbf{x} \quad \text{(时域→频域)}</script><p>逆变换：</p><script type="math/tex; mode=display">\mathbf{x} = \mathbf{U} \widehat{\mathbf{x}} \quad \text{(频域→时域)}</script><h3 id="2-图卷积定理"><a href="#2-图卷积定理" class="headerlink" title="2. 图卷积定理"></a>2. 图卷积定理</h3><p>图上的卷积操作在频谱域定义为<strong>逐元素乘积</strong>：</p><script type="math/tex; mode=display">\mathbf{x} *_\mathcal{G} \mathbf{y} = \mathbf{U} \left( (\mathbf{U}^\top \mathbf{x}) \odot (\mathbf{U}^\top \mathbf{y}) \right)</script><p>引入滤波器 $g_\theta(\mathbf{\Lambda})$ 后：</p><script type="math/tex; mode=display">\mathbf{x} *_\mathcal{G} g_\theta = \mathbf{U} g_\theta(\mathbf{\Lambda}) \mathbf{U}^\top \mathbf{x}</script><h2 id="三、经典模型演变"><a href="#三、经典模型演变" class="headerlink" title="三、经典模型演变"></a>三、经典模型演变</h2><h3 id="1-Spectral-CNN-Bruna-et-al-ICLR-2014"><a href="#1-Spectral-CNN-Bruna-et-al-ICLR-2014" class="headerlink" title="1. Spectral CNN (Bruna et al., ICLR 2014)"></a>1. Spectral CNN (Bruna et al., ICLR 2014)</h3><ul><li><strong>滤波器设计</strong>：<script type="math/tex; mode=display">g_\theta(\mathbf{\Lambda}) = \text{diag}(\theta_1, \theta_2, \cdots, \theta_N) \quad (\theta_i \in \mathbb{R})</script></li><li><strong>局限性</strong>：<ul><li>参数量大 ($O(N)$)</li><li>无法局部化（依赖全图特征分解）<h3 id="2-ChebNet-Defferrard-et-al-NeurIPS-2016"><a href="#2-ChebNet-Defferrard-et-al-NeurIPS-2016" class="headerlink" title="2. ChebNet (Defferrard et al., NeurIPS 2016)"></a>2. ChebNet (Defferrard et al., NeurIPS 2016)</h3>用<strong>切比雪夫多项式</strong>近似滤波器：<script type="math/tex; mode=display">g_\theta(\mathbf{\Lambda}) = \sum_{k=0}^{K-1} \theta_k T_k(\tilde{\mathbf{\Lambda}})</script></li></ul></li><li>$\tilde{\mathbf{\Lambda}} = \frac{2\mathbf{\Lambda}}{\lambda_{\max}} - \mathbf{I}$（缩放至$[-1,1]$）</li><li>$T<em>k(\cdot)$：切比雪夫多项式（递归定义：$T_0=1, T_1=x, T_k=2xT</em>{k-1}-T_{k-2}$）</li></ul><p><strong>卷积操作</strong>：</p><script type="math/tex; mode=display">\mathbf{x} *_\mathcal{G} g_\theta = \sum_{k=0}^{K-1} \theta_k T_k(\tilde{\mathbf{L}}) \mathbf{x}</script><p>其中 $\tilde{\mathbf{L}} = \frac{2\mathbf{L}}{\lambda_{\max}} - \mathbf{I}$（无需特征分解！）</p><h3 id="3-GCN-Kipf-amp-Welling-ICLR-2017"><a href="#3-GCN-Kipf-amp-Welling-ICLR-2017" class="headerlink" title="3. GCN (Kipf &amp; Welling, ICLR 2017)"></a>3. GCN (Kipf &amp; Welling, ICLR 2017)</h3><p>ChebNet 的<strong>一阶近似</strong>（$K=2$）：</p><script type="math/tex; mode=display">\mathbf{H}^{(l+1)} = \sigma \left( \hat{\mathbf{A}} \mathbf{H}^{(l)} \mathbf{W}^{(l)} \right) \quad \text{其中} \quad \hat{\mathbf{A}} = \tilde{\mathbf{D}}^{-1/2} \tilde{\mathbf{A}} \tilde{\mathbf{D}}^{-1/2}</script><ul><li>仅聚合一阶邻居（高效且可扩展）</li></ul><h2 id="四、关键优势与局限性"><a href="#四、关键优势与局限性" class="headerlink" title="四、关键优势与局限性"></a>四、关键优势与局限性</h2><div class="table-container"><table><thead><tr><th><strong>优势</strong></th><th><strong>局限性</strong></th></tr></thead><tbody><tr><td>⭐ 理论基础严密（信号处理可解释性强）</td><td>⚠️ 计算成本高（需特征分解或多项式逼近）</td></tr><tr><td>⭐ 全局信息捕获能力强</td><td>⚠️ 对图结构变化敏感（固定图假设）</td></tr><tr><td>⭐ 频域滤波提供灵活特征选择</td><td>⚠️ 无法直接处理异构图</td></tr></tbody></table></div><h2 id="五、代码实现（PyTorch-Geometric）"><a href="#五、代码实现（PyTorch-Geometric）" class="headerlink" title="五、代码实现（PyTorch Geometric）"></a>五、代码实现（PyTorch Geometric）</h2><h3 id="ChebNet-示例："><a href="#ChebNet-示例：" class="headerlink" title="ChebNet 示例："></a>ChebNet 示例：</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> ChebConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ChebNet</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_dim, hidden_dim, out_dim, K=<span class="number">3</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = ChebConv(in_dim, hidden_dim, K)  <span class="comment"># K阶切比雪夫近似</span></span><br><span class="line">        <span class="variable language_">self</span>.conv2 = ChebConv(hidden_dim, out_dim, K)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, data</span>):</span><br><span class="line">        x, edge_index = data.x, data.edge_index</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.conv1(x, edge_index))    <span class="comment"># 第一层（自动计算拉普拉斯）</span></span><br><span class="line">        x = <span class="variable language_">self</span>.conv2(x, edge_index)                <span class="comment"># 第二层</span></span><br><span class="line">        <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用示例</span></span><br><span class="line">model = ChebNet(in_dim=<span class="number">16</span>, hidden_dim=<span class="number">32</span>, out_dim=<span class="number">8</span>, K=<span class="number">3</span>)</span><br><span class="line">output = model(data)  <span class="comment"># 输入图数据</span></span><br></pre></td></tr></table></figure><h2 id="六、新一代谱方法研究（2023-2024）"><a href="#六、新一代谱方法研究（2023-2024）" class="headerlink" title="六、新一代谱方法研究（2023-2024）"></a>六、新一代谱方法研究（2023-2024）</h2><ol><li><p><strong>自适应谱滤波器</strong></p><ul><li><strong>GPR-GNN</strong> (ICLR 2021)：广义PageRank系数优化<script type="math/tex; mode=display">\mathbf{H} = \sum_{k=0}^K \gamma_k \hat{\mathbf{A}}^k \mathbf{X} \mathbf{W}</script><ul><li>$\gamma_k$ 作为可学习参数，自适应不同阶数重要性</li></ul></li></ul></li><li><p><strong>无需特征分解的谱学习</strong></p><ul><li><strong>BernNet</strong> (NeurIPS 2021)：用Bernstein多项式拟合任意滤波器：<script type="math/tex; mode=display">g(\lambda) = \sum_{k=0}^K \theta_k B_k(\lambda; K)</script><ul><li>$B_k$ 为Bernstein基函数，保证滤波器平滑性</li></ul></li></ul></li><li><p><strong>图小波神经网络</strong></p><ul><li><strong>GWNN</strong> (ICML 2023)：用图小波基取代傅里叶基<script type="math/tex; mode=display">\mathbf{\Psi}_s = \mathbf{U} e^{-\varepsilon s \mathbf{\Lambda}} \mathbf{U}^\top</script><ul><li>$s$ 为尺度参数，实现多分辨率分析</li></ul></li></ul></li></ol><h2 id="七、总结与应用场景"><a href="#七、总结与应用场景" class="headerlink" title="七、总结与应用场景"></a>七、总结与应用场景</h2><p><strong>核心适用领域</strong>：</p><ul><li>图信号处理（节点分类、图分类）</li><li>物理系统建模（分子动力学、流体模拟）</li><li>推荐系统（用户-商品图谱分析）<blockquote><p><strong>工具推荐</strong>：</p><ul><li><code>torch_geometric.nn.ChebConv</code></li><li>DGL的 <code>ChebConv</code> 模块</li><li><a href="https://github.com/ivam-he/BernNet">BernNet官方实现</a></li></ul><p><strong>最新突破</strong>：<strong>Oversquashing-Free Graph Neural Networks</strong> (ICML 2024) 提出通过谱设计解决长距离信息传递瓶颈。</p></blockquote></li></ul><hr><h1 id="Spectral-GNN-vs-Spatial-GNN"><a href="#Spectral-GNN-vs-Spatial-GNN" class="headerlink" title="Spectral GNN vs. Spatial GNN"></a>Spectral GNN vs. Spatial GNN</h1><p>以下是对空间图神经网络（Spatial GNN）和谱图神经网络（Spectral GNN）的全面对比解析，涵盖理论、模型和应用差异：</p><h2 id="一、核心理念对比"><a href="#一、核心理念对比" class="headerlink" title="一、核心理念对比"></a>一、核心理念对比</h2><div class="table-container"><table><thead><tr><th><strong>维度</strong></th><th>Spatial GNN (空间方法)</th><th>Spectral GNN (谱方法)</th></tr></thead><tbody><tr><td><strong>基本思想</strong></td><td>通过局部邻居聚合传播信息</td><td>在图傅里叶域定义卷积操作</td></tr><tr><td><strong>图定义域</strong></td><td>顶点域 (Vertex Domain)</td><td>谱域 (Spectral Domain)</td></tr><tr><td><strong>理论基础</strong></td><td>消息传递机制</td><td>图谱理论（拉普拉斯矩阵分解）</td></tr><tr><td><strong>计算范式</strong></td><td>图结构拓扑操作</td><td>频域信号处理</td></tr></tbody></table></div><h2 id="二、技术原理详解"><a href="#二、技术原理详解" class="headerlink" title="二、技术原理详解"></a>二、技术原理详解</h2><h3 id="Spatial-GNN-空间方法"><a href="#Spatial-GNN-空间方法" class="headerlink" title="Spatial GNN (空间方法)"></a>Spatial GNN (空间方法)</h3><p><strong>核心机制：消息传递 (Message Passing)</strong></p><ol><li><p><strong>聚合 (Aggregate)</strong>：</p><script type="math/tex; mode=display">\mathbf{m}_i^{(l)} = \text{AGGREGATE}^{(l)} \left( \{ \mathbf{h}_j^{(l-1)} \mid j \in \mathcal{N}(i) \} \right)</script><ul><li>邻居特征聚合（sum/mean/max）</li></ul></li><li><p><strong>更新 (Update)</strong>：</p><script type="math/tex; mode=display">\mathbf{h}_i^{(l)} = \text{UPDATE}^{(l)} \left( \mathbf{h}_i^{(l-1)}, \mathbf{m}_i^{(l)} \right)</script><ul><li>结合自身特征与聚合信息</li></ul></li></ol><p><strong>代表模型</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR  GCN --&gt; GraphSAGE  GraphSAGE --&gt; GAT[GAT]  GAT --&gt; GIN[GIN]  GraphSAGE --&gt; PNA[PNA]  </pre></div></p><h3 id="Spectral-GNN-谱方法"><a href="#Spectral-GNN-谱方法" class="headerlink" title="Spectral GNN (谱方法)"></a>Spectral GNN (谱方法)</h3><p><strong>核心机制：频域卷积</strong></p><ol><li><p><strong>图傅里叶变换</strong>：</p><script type="math/tex; mode=display">\widehat{\mathbf{x}} = \mathbf{U}^\top \mathbf{x}\tag{1}</script></li><li><p><strong>频域滤波</strong>：</p><script type="math/tex; mode=display">\widehat{\mathbf{y}} = g_\theta(\mathbf{\Lambda}) \widehat{\mathbf{x}}\tag{2}</script></li><li><p><strong>逆变换</strong>：</p><script type="math/tex; mode=display">\mathbf{y} = \mathbf{U} \widehat{\mathbf{y}} = \mathbf{U} g_\theta(\mathbf{\Lambda}) \mathbf{U}^\top \mathbf{x}\tag{3}</script></li></ol><blockquote><p>通俗易懂地说，公式(1)的操作是将$\mathbf{x}$映射到频率空间中；公式(2)是对映射到频率空间中的内容进行一些操作，如图卷积操作等；公式(3)是将频率空间中得到的内容再逆变换映射会原空间中。而公式(2)中的函数，为我们需要学习的函数。</p></blockquote><p><strong>代表模型进化</strong>：<br><div class="mermaid-wrap"><pre class="mermaid-src" hidden>    graph LR  SpectralCNN --&gt; ChebNet  ChebNet --&gt; GCN  ChebNet --&gt; ARMA[ARMA Net]  SpectralCNN --&gt; GWNN  </pre></div></p><h2 id="三、模型特性对比"><a href="#三、模型特性对比" class="headerlink" title="三、模型特性对比"></a>三、模型特性对比</h2><h3 id="1-计算效率"><a href="#1-计算效率" class="headerlink" title="1. 计算效率"></a>1. 计算效率</h3><div class="table-container"><table><thead><tr><th><strong>指标</strong></th><th>Spatial GNN</th><th>Spectral GNN</th></tr></thead><tbody><tr><td><strong>时间复杂度</strong></td><td>(O(\</td><td>\mathcal{E}\</td><td>)) (邻居聚合)</td><td>(O(n^2)) (特征分解) → 优化后(O(K\</td><td>\mathcal{E}\</td><td>))</td></tr><tr><td><strong>扩展性</strong></td><td>⭐⭐⭐ 支持大规模图</td><td>⭐⭐需近似处理提升效率</td></tr><tr><td><strong>并行性</strong></td><td>节点级并行（分布式优化）</td><td>全图级计算（GPU并行加速）</td></tr></tbody></table></div><h3 id="2-结构适应性"><a href="#2-结构适应性" class="headerlink" title="2. 结构适应性"></a>2. 结构适应性</h3><div class="table-container"><table><thead><tr><th><strong>特性</strong></th><th>Spatial GNN</th><th>Spectral GNN</th></tr></thead><tbody><tr><td><strong>动态图</strong></td><td>✅ 实时更新邻居</td><td>❌ 需重新计算拉普拉斯矩阵</td></tr><tr><td><strong>异构图</strong></td><td>✅ 支持多关系聚合（RGCN, HGT）</td><td>❌ 主要面向同构图</td></tr><tr><td><strong>边特征</strong></td><td>✅ 天然支持（如GINE）</td><td>⚠️ 需扩展设计</td></tr></tbody></table></div><h2 id="四、经典模型实现代码"><a href="#四、经典模型实现代码" class="headerlink" title="四、经典模型实现代码"></a>四、经典模型实现代码</h2><h3 id="Spatial-GNN示例：GAT-Graph-Attention-Network"><a href="#Spatial-GNN示例：GAT-Graph-Attention-Network" class="headerlink" title="Spatial GNN示例：GAT (Graph Attention Network)"></a>Spatial GNN示例：GAT (Graph Attention Network)</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> GATConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">GAT</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_dim, hidden_dim, out_dim, heads=<span class="number">8</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = GATConv(in_dim, hidden_dim, heads=heads)  <span class="comment"># 多头注意力</span></span><br><span class="line">        <span class="variable language_">self</span>.conv2 = GATConv(hidden_dim*heads, out_dim, heads=<span class="number">1</span>) <span class="comment"># 单头输出</span></span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, data</span>):</span><br><span class="line">        x, edge_index = data.x, data.edge_index</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.conv1(x, edge_index))  <span class="comment"># 聚合：加权邻居特征</span></span><br><span class="line">        x = <span class="variable language_">self</span>.conv2(x, edge_index)              <span class="comment"># 输出层</span></span><br><span class="line">        <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure><p><strong>空间聚合核心</strong>：注意力权重计算</p><script type="math/tex; mode=display">\alpha_{ij} = \frac{ \exp(\text{LeakyReLU}(\mathbf{a}^\top [\mathbf{W}\mathbf{h}_i \| \mathbf{W}\mathbf{h}_j])) } { \sum_{k \in \mathcal{N}(i)} \exp(\text{LeakyReLU}(\mathbf{a}^\top [\mathbf{W}\mathbf{h}_i \| \mathbf{W}\mathbf{h}_k])) }</script><h3 id="Spectral-GNN示例：ChebNet-切比雪夫网络"><a href="#Spectral-GNN示例：ChebNet-切比雪夫网络" class="headerlink" title="Spectral GNN示例：ChebNet (切比雪夫网络)"></a>Spectral GNN示例：ChebNet (切比雪夫网络)</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> ChebConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ChebNet</span>(torch.nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_dim, hidden_dim, out_dim, k=<span class="number">3</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = ChebConv(in_dim, hidden_dim, K=k)  <span class="comment"># K阶近似</span></span><br><span class="line">        <span class="variable language_">self</span>.conv2 = ChebConv(hidden_dim, out_dim, K=k)</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, data</span>):</span><br><span class="line">        x, edge_index = data.x, data.edge_index</span><br><span class="line">        x = <span class="variable language_">self</span>.conv1(x, edge_index)  <span class="comment"># 频域卷积：切比雪夫多项式逼近</span></span><br><span class="line">        x = torch.relu(x)</span><br><span class="line">        x = <span class="variable language_">self</span>.conv2(x, edge_index)</span><br><span class="line">        <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure><p><strong>谱滤波核心</strong>：(K)阶多项式展开</p><script type="math/tex; mode=display">g_\theta(\mathbf{L}) = \sum_{k=0}^{K-1} \theta_k T_k(\tilde{\mathbf{L}})</script><h2 id="五、性能对比与适用场景"><a href="#五、性能对比与适用场景" class="headerlink" title="五、性能对比与适用场景"></a>五、性能对比与适用场景</h2><div class="table-container"><table><thead><tr><th><strong>任务类型</strong></th><th>推荐模型类型</th><th>原因说明</th></tr></thead><tbody><tr><td>大规模图节点分类</td><td>Spatial GNN</td><td>邻居采样高效（GraphSAGE）</td></tr><tr><td>图结构分析</td><td>Spectral GNN</td><td>捕获全局结构特征（谱聚类）</td></tr><tr><td>动态图预测</td><td>Spatial GNN</td><td>增量更新邻居（EvolveGCN）</td></tr><tr><td>分子性质预测</td><td>Spectral GNN</td><td>物理系统能量状态建模</td></tr><tr><td>推荐系统</td><td>Spatial GNN</td><td>多重关系建模（LightGCN）</td></tr></tbody></table></div><h2 id="六、前沿研究进展（2023-2024）"><a href="#六、前沿研究进展（2023-2024）" class="headerlink" title="六、前沿研究进展（2023-2024）"></a>六、前沿研究进展（2023-2024）</h2><h3 id="Spatial-GNN最新方向："><a href="#Spatial-GNN最新方向：" class="headerlink" title="Spatial GNN最新方向："></a>Spatial GNN最新方向：</h3><ol><li><p><strong>长距离依赖优化</strong></p><ul><li><strong>CRaWl</strong> (ICML 2023)：随机游走增强信息传播<script type="math/tex; mode=display">\mathbf{m}_i = \text{ATTN} \left( \{ \text{RW}_k(i) \mid k=1,\dots,K \} \right)</script><ul><li>解决过平滑（Over-smoothing）问题</li></ul></li></ul></li><li><p><strong>3D几何图学习</strong></p><ul><li><strong>Equivariant GNN</strong> (Nature 2024)：<script type="math/tex; mode=display">\mathbf{h}_i^{(l)} = f( \| \mathbf{x}_i - \mathbf{x}_j \|, \mathbf{h}_j ) \quad (SE(3)-\text{不变})</script><ul><li>应用于蛋白质结构预测</li></ul></li></ul></li></ol><h3 id="Spectral-GNN最新方向："><a href="#Spectral-GNN最新方向：" class="headerlink" title="Spectral GNN最新方向："></a>Spectral GNN最新方向：</h3><ol><li><p><strong>自适应谱滤波器</strong></p><ul><li><strong>FreqGNN</strong> (ICLR 2024)：可学习频带选择<script type="math/tex; mode=display">g_\theta(\lambda) = \sum_{k=1}^K \theta_k \cdot \text{bandpass}_k(\lambda)</script></li></ul></li><li><p><strong>无拉普拉斯方法</strong></p><ul><li><strong>AdaGNN</strong> (KDD 2023)：利用图扩散算子<script type="math/tex; mode=display">\mathbf{H} = \sum_{t=0}^T \alpha_t \mathbf{P}^t \mathbf{X} \mathbf{W}_t</script><ul><li>$\mathbf{P} = \mathbf{A}\mathbf{D}^{-1}$为转移矩阵</li></ul></li></ul></li></ol><h2 id="七、混合架构趋势"><a href="#七、混合架构趋势" class="headerlink" title="七、混合架构趋势"></a>七、混合架构趋势</h2><p><strong>SPAGAN</strong> (NeurIPS 2023)：空间-谱双路径融合<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 空间路径</span></span><br><span class="line">h_spatial = GATConv(x, edge_index)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 谱路径</span></span><br><span class="line">h_spectral = ChebConv(x, edge_index)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 自适应融合 (门控机制)</span></span><br><span class="line">gate = σ(Linear([h_spatial || h_spectral]))</span><br><span class="line">output = gate * h_spatial + (<span class="number">1</span>-gate) * h_spectral</span><br></pre></td></tr></table></figure><br><strong>优势</strong>：在OGB Large-scale挑战赛中实现SOTA</p><blockquote><p><strong>最佳实践选择</strong>：</p><ul><li>优先<strong>Spatial GNN</strong>：工业级应用（推荐系统、欺诈检测）</li><li>选用<strong>Spectral GNN</strong>：科学计算任务（计算化学、物理模拟）</li><li><strong>Hybrid 模型</strong>：对精度要求极高的场景（如药物发现）</li></ul></blockquote><h1 id="Laplacian-Positional-Encoding"><a href="#Laplacian-Positional-Encoding" class="headerlink" title="Laplacian Positional Encoding"></a>Laplacian Positional Encoding</h1><p>拉普拉斯位置编码是图神经网络中一种基于<strong>图谱理论</strong>的位置表示方法，主要用于解决传统 GNN 无法区分<strong>结构等价节点</strong>的问题（如环形图中的对称节点）。它是位置编码（PE）在图数据上的扩展，通过图的拉普拉斯矩阵特征向量提供全局位置信息。</p><h2 id="核心数学原理"><a href="#核心数学原理" class="headerlink" title="核心数学原理"></a>核心数学原理</h2><h3 id="1-图拉普拉斯矩阵"><a href="#1-图拉普拉斯矩阵" class="headerlink" title="1. 图拉普拉斯矩阵"></a>1. 图拉普拉斯矩阵</h3><p>对于一个无向图 $G=(V,E)$，其归一化拉普拉斯矩阵定义为：</p><script type="math/tex; mode=display">L = I - D^{-1/2}AD^{-1/2}</script><p>其中：</p><ul><li>$A \in \mathbb{R}^{n\times n}$ 为邻接矩阵</li><li>$D$ 为度对角矩阵，$D<em>{ii} = \sum_j A</em>{ij}$</li><li>$L$ 是<strong>对称半正定矩阵</strong><h3 id="2-特征分解-1"><a href="#2-特征分解-1" class="headerlink" title="2. 特征分解"></a>2. 特征分解</h3>对 $L$ 进行特征分解：<script type="math/tex; mode=display">L = U \Lambda U^T</script>其中：</li><li>$\Lambda = \text{diag}(\lambda_1, \lambda_2, …, \lambda_n)$ 是特征值对角阵 ($0 \leq \lambda_1 \leq … \leq \lambda_n$)</li><li>$U = [\mathbf{u}_1, \mathbf{u}_2, …, \mathbf{u}_n]$ 是酉矩阵，每列是对应特征值的特征向量<h3 id="3-位置编码生成"><a href="#3-位置编码生成" class="headerlink" title="3. 位置编码生成"></a>3. 位置编码生成</h3>节点 $v$ 的位置编码为：<script type="math/tex; mode=display">PE(v) = [\mathbf{u}_2(v), \mathbf{u}_3(v), ..., \mathbf{u}_{d+1}(v)]</script>其中：</li><li>排除第一个特征向量 $\mathbf{u}_1$ (对应特征值 $\lambda_1=0$，所有元素均为常数)</li><li>取 $d$ 个最小非零特征值对应的特征向量分量</li></ul><blockquote><p><strong>为什么工作？</strong>：<br>Fiedler 定理表明第二特征向量 $\mathbf{u}_2$ (Fiedler 向量) 将图分割为两个连通分量的最优解，更高维特征向量提供更细粒度的空间位置信息。</p></blockquote><h2 id="特点分析"><a href="#特点分析" class="headerlink" title="特点分析"></a>特点分析</h2><div class="table-container"><table><thead><tr><th>性质</th><th>说明</th><th>影响</th></tr></thead><tbody><tr><td><strong>结构感知</strong></td><td>编码图的拓扑结构</td><td>区分环状图/网格图的对称节点</td></tr><tr><td><strong>正交性</strong></td><td>$\langle \mathbf{u}<em>i, \mathbf{u}_j \rangle=\delta</em>{ij}$</td><td>不同方向位置特征解耦</td></tr><tr><td><strong>排列不变性</strong></td><td>对节点重标号不变</td><td>满足GNN的置换不变性要求</td></tr><tr><td><strong>多尺度性</strong></td><td>小特征值对应全局结构</td><td>不同特征向量捕获不同尺度的位置关系</td></tr></tbody></table></div><h2 id="完整实现代码-PyTorch-PyG"><a href="#完整实现代码-PyTorch-PyG" class="headerlink" title="完整实现代码 (PyTorch+PyG)"></a>完整实现代码 (PyTorch+PyG)</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> scipy.sparse <span class="keyword">as</span> sp</span><br><span class="line"><span class="keyword">from</span> torch_geometric.data <span class="keyword">import</span> Data</span><br><span class="line"><span class="keyword">from</span> torch_geometric.utils <span class="keyword">import</span> get_laplacian</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">compute_laplace_pe</span>(<span class="params">edge_index, num_nodes, positive=<span class="literal">False</span>, k=<span class="number">8</span></span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    计算图的拉普拉斯位置编码</span></span><br><span class="line"><span class="string">  </span></span><br><span class="line"><span class="string">    参数:</span></span><br><span class="line"><span class="string">        edge_index (Tensor): [2, num_edges] 边索引</span></span><br><span class="line"><span class="string">        num_nodes (int): 节点数量</span></span><br><span class="line"><span class="string">        positive (bool): 是否强制值均为正 (用于正定矩阵)</span></span><br><span class="line"><span class="string">        k (int): 使用的特征向量维度</span></span><br><span class="line"><span class="string">      </span></span><br><span class="line"><span class="string">    返回:</span></span><br><span class="line"><span class="string">        pe (Tensor): [num_nodes, k] 位置编码矩阵</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    <span class="comment"># 计算归一化拉普拉斯矩阵</span></span><br><span class="line">    L = get_laplacian(edge_index, num_nodes=num_nodes, normalization=<span class="string">&#x27;sym&#x27;</span>)</span><br><span class="line">    L_sparse = sp.coo_matrix((L[<span class="number">1</span>].numpy(), L[<span class="number">0</span>].numpy()), shape=(num_nodes, num_nodes))</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># 特征分解 (仅计算k+1个最小特征值/向量)</span></span><br><span class="line">    evals, evecs = sp.linalg.eigsh(L_sparse, k=k+<span class="number">1</span>, which=<span class="string">&#x27;SM&#x27;</span>)</span><br><span class="line">    <span class="comment"># 删除第一个特征向量(对应λ=0)</span></span><br><span class="line">    evecs = evecs[:, evals.argsort()][:, <span class="number">1</span>:<span class="number">1</span>+k] </span><br><span class="line">  </span><br><span class="line">    pe = torch.tensor(evecs).<span class="built_in">float</span>()</span><br><span class="line">    <span class="comment"># 可选：变换为正值(使维度可解释)</span></span><br><span class="line">    <span class="keyword">if</span> positive:</span><br><span class="line">        pe = pe - pe.<span class="built_in">min</span>(<span class="number">0</span>)[<span class="number">0</span>]</span><br><span class="line">        <span class="keyword">return</span> pe / pe.<span class="built_in">max</span>(<span class="number">0</span>)[<span class="number">0</span>]</span><br><span class="line">    <span class="keyword">return</span> pe</span><br><span class="line"></span><br><span class="line"><span class="comment"># 示例：应用到分子图数据</span></span><br><span class="line"><span class="keyword">from</span> torch_geometric.datasets <span class="keyword">import</span> ZINC</span><br><span class="line">dataset = ZINC(root=<span class="string">&#x27;/data/zinc&#x27;</span>, split=<span class="string">&#x27;train&#x27;</span>, transform=LaplacePEAdder(k=<span class="number">8</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LaplacePEAdder</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;PyG数据转换器：自动加入位置编码&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, k=<span class="number">8</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.k = k</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__call__</span>(<span class="params">self, data: Data</span>):</span><br><span class="line">        edge_index, num_nodes = data.edge_index, data.num_nodes</span><br><span class="line">        pe = compute_laplace_pe(edge_index, num_nodes, k=<span class="variable language_">self</span>.k)</span><br><span class="line">        <span class="comment"># 与原始特征拼接</span></span><br><span class="line">        <span class="keyword">if</span> data.x <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            data.x = pe</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            data.x = torch.cat([data.x, pe], dim=-<span class="number">1</span>)</span><br><span class="line">        <span class="keyword">return</span> data</span><br></pre></td></tr></table></figure><h2 id="关键优化技术"><a href="#关键优化技术" class="headerlink" title="关键优化技术"></a>关键优化技术</h2><ol><li><strong>GPU加速特征分解</strong><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用cuSPARSE和cuSOLVER进行加速</span></span><br><span class="line"><span class="keyword">import</span> torch.sparse</span><br><span class="line">L_coo = get_laplacian(edge_index, normalization=<span class="string">&#x27;sym&#x27;</span>)</span><br><span class="line">L_indices = torch.vstack(L_coo)</span><br><span class="line">L_value = torch.ones(L_coo.shape[<span class="number">1</span>])</span><br><span class="line">L_sparse = torch.sparse_coo_tensor(L_indices, L_value, (num_nodes, num_nodes))</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 截断特征分解</span></span><br><span class="line">evals, evecs = torch.lobpcg(L_sparse, k=k+<span class="number">1</span>, largest=<span class="literal">False</span>)</span><br></pre></td></tr></table></figure></li><li><strong>处理大规模图</strong><ul><li>Nystrom 近似法：对部分节点采样加速计算 (ICML 2023)<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> graphgym.efeat.position <span class="keyword">import</span> nystrom_approximation</span><br><span class="line">pe = nystrom_approximation(L, sample_size=<span class="number">500</span>, dim=k)</span><br></pre></td></tr></table></figure></li></ul></li></ol><h2 id="GNN模型集成示例"><a href="#GNN模型集成示例" class="headerlink" title="GNN模型集成示例"></a>GNN模型集成示例</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">from</span> torch_geometric.nn <span class="keyword">import</span> GATConv</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">GTPosModel</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;结合位置编码的图Transformer&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, in_dim, pe_dim</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.pe_proj = nn.Linear(pe_dim, in_dim)  <span class="comment"># 位置编码投影层</span></span><br><span class="line">        <span class="variable language_">self</span>.encoder = GATConv(in_dim, <span class="number">64</span>, heads=<span class="number">4</span>)</span><br><span class="line">        ...</span><br><span class="line">      </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, edge_index, lap_pe</span>):</span><br><span class="line">        <span class="comment"># 融合原始特征和位置编码</span></span><br><span class="line">        fused_feat = x + <span class="variable language_">self</span>.pe_proj(lap_pe)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.encoder(fused_feat, edge_index)</span><br></pre></td></tr></table></figure><h2 id="应用场景比较"><a href="#应用场景比较" class="headerlink" title="应用场景比较"></a>应用场景比较</h2><div class="table-container"><table><thead><tr><th>图类型</th><th>适用性</th><th>解释</th></tr></thead><tbody><tr><td>环形/网格图</td><td>★★★</td><td>完美区分结构等价节点</td></tr><tr><td>小世界网络</td><td>★★☆</td><td>局部特征优于全局位置</td></tr><tr><td>低维点云图</td><td>★☆</td><td>欧式距离编码更有效</td></tr><tr><td>动态图</td><td>☆</td><td>需每次重新计算特征分解</td></tr></tbody></table></div><h2 id="前沿进展"><a href="#前沿进展" class="headerlink" title="前沿进展"></a>前沿进展</h2><ol><li><p><strong>复值编码</strong> (ICLR 2024突破)<br>使用复值特征向量拓展频谱信息：</p><script type="math/tex; mode=display">\mathcal{CR}PE(v) = e^{-i\theta}\mathbf{u}(v) \quad (\theta \sim \text{learnable})</script></li><li><p><strong>方向可区分编码</strong><br>在异质图中给特征向量赋予方向信息：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">directed_lap_pe</span>(<span class="params">edge_index, direction=<span class="string">&#x27;out&#x27;</span></span>):</span><br><span class="line">    L_out = D_out^&#123;-<span class="number">1</span>/<span class="number">2</span>&#125; A D_out^&#123;-<span class="number">1</span>/<span class="number">2</span>&#125;  <span class="comment"># 出度拉普拉斯</span></span><br><span class="line">    L_in = D_in^&#123;-<span class="number">1</span>/<span class="number">2</span>&#125; A^T D_in^&#123;-<span class="number">1</span>/<span class="number">2</span>&#125;   <span class="comment"># 入度拉普拉斯</span></span><br><span class="line">    <span class="keyword">return</span> (compute_pe(L_out), compute_pe(L_in))</span><br></pre></td></tr></table></figure></li><li><p><strong>自适应频谱选择</strong><br>基于learnable gating机制动态选择特征向量：</p><script type="math/tex; mode=display">\text{PE}(v) = \sum_{i=2}^k g_i(\mathcal{G}) \cdot \mathbf{u}_i(v)</script></li></ol><h2 id="参考论文"><a href="#参考论文" class="headerlink" title="参考论文"></a>参考论文</h2><ul><li>Dwivedi et al. Benchmarking GNNs with Positional Encodings (ICLR 2023)</li><li>Kreuzer et al. Rethinking Graph Transformers with Spectral Attention (NeurIPS 2021)</li><li>Lim et al. Sign and Basis Invariant Networks for Spectral Graph Representation Learning (ICML 2023)</li></ul><blockquote><p><strong>最佳实践</strong>：</p><ul><li>对于&lt;50k节点的图直接计算全分解</li><li>大图使用Nyström近似或Lanczos迭代</li><li>与可学习PE结合（如Random Walk PE）效果更佳</li><li>Transformer架构比GCN/GAT更能利用频谱信息</li></ul></blockquote><hr><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ol><li><a href="https://epsilonzyj.github.io/posts/63fed347.html">图神经网络简介 | An Introduction to GNN</a></li><li><a href="https://www.bilibili.com/video/BV1Vw411R7Fj?spm_id_from=333.788.videopod.episodes&amp;vd_source=2e36fae16810615c2d859efc03aef1c4">图卷积神经网络（GCN）的数学原理详解——谱图理论和傅立叶变换初探-Bilibili</a></li></ol>]]></content>
    
    
    <summary type="html">谱域图神经网络不同于常见的消息传递图神经网络，采用图信号的傅立叶变换进行拓展，本文则简要介绍何为谱域图神经网络。</summary>
    
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/categories/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/"/>
    
    <category term="GNN" scheme="https://epsilonzyj.github.io/blog/categories/AI/Graph-ML/GNN/"/>
    
    
    <category term="AI" scheme="https://epsilonzyj.github.io/blog/tags/AI/"/>
    
    <category term="Graph ML" scheme="https://epsilonzyj.github.io/blog/tags/Graph-ML/"/>
    
    <category term="GNN" scheme="https://epsilonzyj.github.io/blog/tags/GNN/"/>
    
  </entry>
  
  <entry>
    <title>使用Mac远程连接Windows WSL</title>
    <link href="https://epsilonzyj.github.io/blog/posts/e4aef2ca.html"/>
    <id>https://epsilonzyj.github.io/blog/posts/e4aef2ca.html</id>
    <published>2025-07-30T16:00:00.000Z</published>
    <updated>2026-06-12T05:48:31.730Z</updated>
    
    <content type="html"><![CDATA[<h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><p>Windows与MacBook，且处于同一局域网下。安装WSL2的过程略。</p><h2 id="WSL中的配置"><a href="#WSL中的配置" class="headerlink" title="WSL中的配置"></a>WSL中的配置</h2><h3 id="安装配置SSH服务"><a href="#安装配置SSH服务" class="headerlink" title="安装配置SSH服务"></a>安装配置SSH服务</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install openssh-server</span><br></pre></td></tr></table></figure><h3 id="修改配置"><a href="#修改配置" class="headerlink" title="修改配置"></a>修改配置</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> vim /etc/ssh/sshd_config</span><br></pre></td></tr></table></figure><p>将注释的内容全部取消注释：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Port 22</span><br><span class="line">AddressFamily any</span><br><span class="line">ListenAddress 0.0.0.0</span><br><span class="line">PasswordAuthentication yes</span><br></pre></td></tr></table></figure><h3 id="启动SSH服务"><a href="#启动SSH服务" class="headerlink" title="启动SSH服务"></a>启动SSH服务</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ssh-keygen -A</span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> /usr/sbin/service ssh start</span><br></pre></td></tr></table></figure><h2 id="Windows的配置"><a href="#Windows的配置" class="headerlink" title="Windows的配置"></a>Windows的配置</h2><p>由于电脑可能安装了杀毒软件，会导致Windows Defender中防火墙设置被篡改而使得部分功能变为灰色，从而不可用，因此使用Power Shell进行配置。注意，一定要使用管理员身份打开，否则会因为权限不足而无法完成操作。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">New-NetFirewallRule -Name sshd -DisplayName <span class="string">&#x27;sshd for WSL&#x27;</span> -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22</span><br></pre></td></tr></table></figure><h2 id="端口转发"><a href="#端口转发" class="headerlink" title="端口转发"></a>端口转发</h2><p>使用管理员身份在Power Shell中运行如下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">​​​​​​​netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=[PORT] connectaddress=[IP] connectport=[PORT]</span><br><span class="line"><span class="comment"># PORT 为你设置的端口，我这里为3333</span></span><br><span class="line"><span class="comment"># IP地址为wls linux子系统的ip地址，可通过ifconfig查看</span></span><br></pre></td></tr></table></figure><h2 id="使用Mac远程连接"><a href="#使用Mac远程连接" class="headerlink" title="使用Mac远程连接"></a>使用Mac远程连接</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh xxx@xxx.xxx.xxx.xxx -p 22</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">Windows与MacBook双持的情况下，远程连接WSL使用Linux环境的方法。</summary>
    
    
    
    <category term="Env" scheme="https://epsilonzyj.github.io/blog/categories/Env/"/>
    
    <category term="WSL" scheme="https://epsilonzyj.github.io/blog/categories/Env/WSL/"/>
    
    
    <category term="WSL" scheme="https://epsilonzyj.github.io/blog/tags/WSL/"/>
    
  </entry>
  
</feed>
