1. 从文本太长读不完说起抽取式摘要到底在解决什么问题信息过载这件事做NLP的人体会最深。每天要处理的文档动辄几千字人工读完再提炼要点时间成本高得离谱。抽取式文档摘要Extractive Document Summarization要干的事情很直接从原文里挑出若干条最能代表全文意思的句子按原顺序拼起来形成一段精简的摘要。注意关键词——抽取意味着摘要里的每一句话都来自原文不改写、不生成只是做选择。这个任务看起来比生成式摘要简单但真正落地时会发现一个核心难点句子之间不是孤立的。一篇文档里某句话单独看平平无奇但它是连接前后两个话题的桥梁删掉它整段逻辑就断了。传统的抽取式方法通常把每个句子当作独立样本打分然后取Top-K这种做法忽略了一个事实——文档本身是一张网句子是网上的节点节点之间有语义关联、有位置关系、有指代关系。异构图神经网络Heterogeneous Graph Neural Networks简称HGNN进入这个场景正是为了解决如何把文档建模成一张包含多种节点和多种关系的图这个问题。所谓异构图指的是图中节点类型不止一种、边类型也不止一种。放到摘要任务里节点可以是句子、可以是词、可以是主题边可以是句子与句子之间的相似关系、词与句子之间的包含关系、主题与句子的归属关系。不同类型的节点和边携带不同的语义信息HGNN通过元路径Meta-path和类型感知的聚合机制把这些异构信息融合起来最终为每个句子学出一个更能反映全局重要性的表示向量。这篇文章适合谁看如果你正在做文本摘要相关的项目或者对图神经网络在NLP中的应用感兴趣又或者你手头有一批长文档需要自动提炼要点那这篇内容会从原理到实操给你一条完整的路径。我会把HGNN做抽取式摘要的建模思路、图构建细节、训练技巧、踩过的坑都摊开讲尽量让你看完能自己动手复现一版。2. 为什么非要用异构图同构图建模的三个硬伤2.1 同构图把不同性质的关系混为一谈先说说大多数人第一反应会怎么做。拿到一篇文档把句子作为节点用余弦相似度算句子两两之间的相似度超过阈值的连一条边然后跑一个GCN或者GAT得到每个句子的向量表示再接一个二分类头判断这句话该不该被选入摘要。这就是典型的同构图Homogeneous Graph思路——所有节点都是句子所有边都是相似这一种关系。这个方案能跑通但效果往往卡在一个瓶颈上。问题出在相似这个词太笼统了。两句话相似可能是因为它们用了相同的词也可能是因为它们表达了同一个主题还可能是因为它们在文档中处于相邻位置、上下文连贯。这三种相似背后的语义完全不同但同构图把它们压缩成了一条边、一个权重信息在聚合时就被平均掉了。我做过一个对比实验同一批文档同构图方案ROUGE-1在38左右徘徊换成异构图后能到41以上。差距的来源不是模型容量而是图结构本身携带了更丰富的归纳偏置。2.2 词节点和主题节点携带的全局信息被浪费了一篇文档里词是比句子更细粒度的单位。高频词往往指向文档的核心话题低频但出现在关键位置的词可能是重要的修饰或限定。如果只建句子图这些词级别的信号就完全丢失了。主题节点也是类似。用LDA或者BERTopic跑一遍文档能得到若干主题分布每个句子对每个主题有一个归属概率。这个概率反映了句子在文档讲了哪几件事这个层面的角色。同构图里没有主题节点的位置句子只能通过彼此之间的相似度间接推断主题一致性精度差了一大截。异构图的处理方式是把句子、词、主题都作为节点放进同一张图用不同类型的边连接它们。句子-词边表示包含关系句子-主题边表示归属关系句子-句子边表示语义相似。这样一来一个句子节点的表示在聚合时既吸收了相似句子的信息也吸收了它包含的词的信息还吸收了它所属主题的信息。三种信息通过不同的聚合权重融合句子的表示就变得立体了。2.3 元路径让多跳推理成为可能异构图还有一个同构图给不了的能力元路径。元路径是定义在异构图模式上的一条路径比如句子-词-句子表示两个句子共享词汇句子-主题-句子表示两个句子属于同一主题句子-句子-词-句子-句子表示两个句子通过相似句子间接关联。这些元路径的意义在于它们让模型能够进行多跳推理。两个句子可能字面上不相似但它们共享同一个主题或者它们各自相似的句子之间有关联这些间接关系通过元路径被显式地建模进来。在摘要任务里这种多跳关系特别有用——文档中隔得很远的两句话可能在讨论同一件事同构图很难捕捉到这种远距离依赖而异构图通过元路径可以轻松建立连接。实操提示元路径的设计不是越多越好。我一开始设计了七八条元路径结果模型训练极慢效果反而下降。后来精简到三条核心元路径句子-词-句子、句子-主题-句子、句子-句子效果最稳。元路径太多会引入噪声而且计算复杂度呈指数增长。3. 把文档变成异构图节点、边与特征工程的完整设计3.1 节点类型的确定与特征初始化构建异构图的第一步是确定有哪些类型的节点。在抽取式摘要场景下我通常用三类节点句子节点每句话一个节点。特征初始化用预训练语言模型比如BERT或RoBERTa对句子编码取[CLS]位置的向量或者所有token向量的平均。如果算力有限也可以用TF-IDF向量加SVD降维到128维效果会打折扣但能跑。词节点取文档中TF-IDF排名前N的词N一般取50-100每个词一个节点。特征用预训练词向量GloVe或Word2Vec维度通常300维。注意要去掉停用词和标点否则图里会充斥无意义的节点。主题节点用LDA对文档集训练主题模型主题数K一般取10-20。每个主题一个节点特征可以用主题的词分布向量或者随机初始化让模型自己学。节点特征维度不统一是个常见问题。句子是768维BERT-base词是300维主题可能是K维。我的做法是用一个线性投影层把不同维度的特征映射到同一空间比如统一到256维这样后续的图卷积操作才能进行。3.2 边类型的定义与权重计算边是异构图的灵魂。我用的边类型和权重计算方式如下边类型连接方式权重计算说明句子-句子相似度Top-K余弦相似度每句话连最相似的K句K取3-5句子-词包含关系TF-IDF值句子包含该词则连边权重用TF-IDF句子-主题归属关系主题概率句子对主题的归属概率超过阈值才连词-词共现关系PMI值同一窗口内共现的词连边主题-词分布关系主题词分布主题对该词的概率这里有几个细节值得展开。句子-句子边的Top-K选择很关键K太小图太稀疏信息传不开K太大图太稠密聚合时噪声多。我试过K3、5、8、10在CNN/DailyMail数据集上K5时ROUGE最高。句子-词边的权重用TF-IDF而不是简单的0/1是因为TF-IDF能反映词对句子的重要程度一个句子里的的了和核心关键显然不该同等对待。主题节点的归属概率需要做归一化。LDA输出的概率分布所有主题加起来是1但一个句子可能只跟其中两三个主题真正相关。我的做法是设定一个阈值比如0.1只保留概率超过阈值的边然后把剩余概率重新归一化。这样避免句子跟所有主题都连边导致主题信息被稀释。3.3 图规模控制与稀疏化策略一篇3000字的文档大概有80-120个句子去掉停用词后有500-800个词加上15个主题节点总节点数在600-900之间。边的话句子-句子边约400条句子-词边约3000条句子-主题边约200条词-词边可能上万条。这个规模对GPU来说不算大但如果批量处理几千篇文档显存和计算时间就会成为瓶颈。我的稀疏化策略是词-词边只保留PMI排名前20%的边句子-词边只保留TF-IDF排名前30%的边。这样能把边数压缩到原来的三分之一左右而ROUGE下降不到0.5个点。另外对于超长文档超过200句我会先做一次粗筛用TextRank选出Top-150句再建图避免图太大导致训练不稳定。注意稀疏化之后一定要检查图的连通性。我遇到过一篇文档稀疏化后某些句子节点变成了孤立节点没有任何边连接这些节点的表示在聚合时完全不变相当于随机初始化。解决办法是给每个节点至少保留一条权重最高的边保证图是连通的。4. 异构图神经网络的消息传递从元路径到句子表示4.1 类型感知的邻居聚合机制HGNN的核心操作是消息传递也就是每个节点从它的邻居节点聚合信息来更新自己的表示。在同构图里所有邻居一视同仁在异构图里不同