LightGCN:简化图卷积用于协同过滤推荐

FreeGuideOnline 最新 2026-06-23

LightGCN:简化图卷积用于协同过滤推荐

1. 什么是协同过滤与图推荐

协同过滤(Collaborative Filtering,CF)是推荐系统的经典范式,其核心假设是:用户过去喜欢过的物品,与相似用户喜欢的物品也值得推荐。传统方法如矩阵分解(MF)学习用户和物品的隐向量,通过向量内积预测评分。然而,MF 只考虑用户与物品之间的直接交互,忽略了高阶连通性。

随着图神经网络(GNN)的兴起,基于图的协同过滤将用户-物品交互建模为二分图。图中的节点为用户和物品,边代表交互(如点击、购买)。通过图卷积操作,节点的表示能聚合其多跳邻居的信息,从而捕捉用户-物品-用户等协同信号。

2. 图卷积网络(GCN)的回顾

GCN 的核心是层间传播规则:

[ H^{(k+1)} = \sigma\left( \tilde{D}^{-\frac{1}{2}} \tilde{A} \tilde{D}^{-\frac{1}{2}} H^{(k)} W^{(k)} \right) ]

  • (\tilde{A} = A + I):添加自环的邻接矩阵
  • (\tilde{D}):(\tilde{A}) 的度矩阵
  • (H^{(k)}):第 (k) 层节点特征
  • (W^{(k)}):可学习的特征变换矩阵
  • (\sigma):非线性激活函数(如 ReLU)

在协同过滤中,(A) 就是用户-物品交互矩阵构成的二分图邻接矩阵。早期工作 NGCF(Neural Graph Collaborative Filtering)直接套用这样的 GCN 结构来做推荐,取得了不错的提升。

3. LightGCN 的诞生:为什么需要简化?

3.1 NGCF 的“冗余”操作

NGCF 虽然有效,但通过大量消融实验发现,其中特征变换矩阵 (W) 和非线性激活 (\sigma) 对协同过滤任务并无明显增益,反而会增加训练难度。这是因为:

  • 用户和物品的初始嵌入已经是可训练的参数向量(即 ID 嵌入),不需要像视觉任务那样进行复杂的特征提取和变换。
  • 协同过滤的核心在于邻居信息的聚合与平滑,非线性反而可能破坏这种平滑性。
  • 过度的参数化还容易导致过拟合,尤其在数据稀疏的场景下。

3.2 LightGCN 的设计哲学

LightGCN 大胆地去除了 GCN 中的特征变换和非线性激活,只保留最本质的邻居聚合。这让模型极大简化,更容易训练,效果却超越了 NGCF 和诸多多模态模型。其层定义如下:

[ e_u^{(k+1)} = \sum_{i \in \mathcal{N}_u} \frac{1}{\sqrt{|\mathcal{N}_u|}\sqrt{|\mathcal{N}i|}} e_i^{(k)} ] [ e_i^{(k+1)} = \sum{u \in \mathcal{N}_i} \frac{1}{\sqrt{|\mathcal{N}_i|}\sqrt{|\mathcal{N}_u|}} e_u^{(k)} ]

其中,(e_u^{(k)}) 和 (e_i^{(k)}) 分别是用户 (u) 和物品 (i) 在第 (k) 层的嵌入,(\mathcal{N}_u) 是用户 (u) 交互过的物品集合,(\mathcal{N}_i) 是物品 (i) 被哪些用户交互的集合。对称归一化系数 (\frac{1}{\sqrt{|\mathcal{N}_u||\mathcal{N}_i|}}) 遵循标准 GCN 设计,防止度数大的节点使嵌入尺度膨胀。

4. LightGCN 模型架构详解

4.1 初始嵌入层

每个用户和物品都分配一个可学习的嵌入向量 (e_u^{(0)} \in \mathbb{R}^d) 和 (e_i^{(0)} \in \mathbb{R}^d),其中 (d) 是嵌入维度。这些向量随机初始化。

4.2 多层线性传播

对于 (K) 层 LightGCN,嵌入递归地按照第 3 节的公式传播。因为没有可训练权重和激活函数,整个过程完全线性,可以通过矩阵形式高效实现。

令用户-物品交互矩阵为 (R \in \mathbb{R}^{M \times N}),其中 (M) 为用户数,(N) 为物品数。则二分图邻接矩阵可以表示为:

[ A = \begin{pmatrix} 0 & R \ R^T & 0 \end{pmatrix} ]

归一化邻接矩阵为 (\tilde{A} = D^{-\frac{1}{2}} A D^{-\frac{1}{2}}),其中 (D) 是度矩阵。那么第 (k) 层的传播等价于:

[ E^{(k+1)} = \tilde{A} E^{(k)} ]

这里的 (E^{(k)} \in \mathbb{R}^{(M+N) \times d}) 是所有节点在第 (k) 层的嵌入堆叠。

4.3 层组合

经过 (K) 层传播,我们得到每一层的嵌入 (E^{(0)}, E^{(1)}, \dots, E^{(K)})。LightGCN 组合它们以形成最终的节点表示:

[ E = \alpha_0 E^{(0)} + \alpha_1 E^{(1)} + \alpha_2 E^{(2)} + \dots + \alpha_K E^{(K)} ]

最常见也最简单的组合方式是求和(所有 (\alpha_k = 1) 或采用加权求和)。论文中采用 (\alpha_k = \frac{1}{K+1}) 的简单平均值,效果就已经很好。

组合的原因:

  • 避免深层出现过度平滑问题。
  • 保留了不同阶(1阶、2阶、高阶)的邻域信息,像一个携带了自连接的多尺度特征。

4.4 预测层

最终预测用户 (u) 对物品 (i) 的得分采用简单的内积:

[ \hat{y}_{ui} = e_u^T e_i ]

其中 (e_u) 和 (e_i) 是层组合后的最终嵌入。整个模型只用到了内积作为预测函数,没有复杂的 MLP 预测头。

5. 模型训练

5.1 损失函数

LightGCN 采用贝叶斯个性化排序(BPR)损失进行优化,这个损失鼓励观测到的交互得分高于未观测到的交互:

[ L = -\sum_{u=1}^M \sum_{i \in \mathcal{N}u} \sum{j \notin \mathcal{N}u} \ln \sigma(\hat{y}{ui} - \hat{y}_{uj}) + \lambda ||E^{(0)}||^2 ]

  • (\sigma) 是 sigmoid 函数。
  • 负样本 (j) 从用户未交互的物品中均匀采样。
  • 正则化项仅施加在第0层嵌入上(因为其他层嵌入由传播产生),系数 (\lambda) 控制强度。

5.2 训练流程

  1. 构造邻接矩阵并归一化。
  2. 初始化所有用户和物品的第0层嵌入。
  3. 对于每个训练批次,采样一批用户及其交互物品和负样本。
  4. 通过多层传播得到用户的最终嵌入(可以提前缓存整个图所有节点的嵌入,因为邻域聚合不依赖批次)。
  5. 计算 BPR 损失并反向传播,只更新第0层嵌入参数。
  6. 达到预设的迭代轮数后停止。

6. 与其它模型的关系

LightGCN 可以被视为对以下模型的抽象:

  • 矩阵分解(MF):仅使用第0层嵌入和内积,即 (K=0) 的特例。
  • SVD++FISM:可以看作手工设计的1阶邻居加权和,LightGCN 将其推广到任意阶并自动学习权重。
  • PinSage 等工业图推荐模型:使用带权重的邻居聚合,LightGCN 证明去掉变换和非线性依然强大。

7. 代码实现示例(PyTorch 伪代码)

为了方便理解,下面给出核心传播部分的代码结构。

import torch
import torch.nn as nn

class LightGCN(nn.Module):
    def __init__(self, num_users, num_items, embed_dim, n_layers):
        super().__init__()
        self.num_users = num_users
        self.num_items = num_items
        self.embed_dim = embed_dim
        self.n_layers = n_layers

        # 第0层嵌入
        self.user_embeddings = nn.Embedding(num_users, embed_dim)
        self.item_embeddings = nn.Embedding(num_items, embed_dim)
        # 初始化
        nn.init.xavier_uniform_(self.user_embeddings.weight)
        nn.init.xavier_uniform_(self.item_embeddings.weight)

        # 归一化邻接矩阵将作为外部数据传入
        self.norm_adj = None

    def forward(self, users, items, neg_items):
        # 获取所有0层嵌入
        all_embeddings = torch.cat([self.user_embeddings.weight, self.item_embeddings.weight], dim=0)
        embeddings_list = [all_embeddings]

        # 多层传播
        for layer in range(self.n_layers):
            all_embeddings = torch.sparse.mm(self.norm_adj, all_embeddings)
            embeddings_list.append(all_embeddings)

        # 层组合(平均)
        final_embeddings = torch.stack(embeddings_list, dim=1).mean(dim=1)

        # 拆分用户和物品嵌入
        user_final, item_final = torch.split(final_embeddings, [self.num_users, self.num_items])

        # 获取批次嵌入
        user_emb = user_final[users]
        pos_item_emb = item_final[items]
        neg_item_emb = item_final[neg_items]

        # 预测得分
        pos_scores = (user_emb * pos_item_emb).sum(dim=1)
        neg_scores = (user_emb * neg_item_emb).sum(dim=1)

        return pos_scores, neg_scores

    def bpr_loss(self, pos_scores, neg_scores):
        loss = -torch.log(torch.sigmoid(pos_scores - neg_scores) + 1e-10).mean()
        # L2 正则化仅施加于第0层
        reg_loss = (self.user_embeddings.weight.norm(2) + self.item_embeddings.weight.norm(2)) / 2
        return loss + reg_loss * 1e-4

请注意,实际实现需要提前计算 norm_adj 并将其转换为稀疏张量(如 torch.sparse.FloatTensor)以支持高效矩阵乘法。

8. 效果与优势

LightGCN 在多个公开数据集(Gowalla、Yelp2018、Amazon-Book)上,对比 NGCF、Mult-VAE 等强基线,在 Recall@20 和 NDCG@20 上均有显著提升。其优势可归纳为:

  1. 极简结构:只有初始嵌入是可训练参数,模型体积极小。
  2. 训练高效:去掉了非线性与权重变换,前向传播速度大幅加快,内存占用更低。
  3. 泛化更强:简化带来的正则化效果使其在稀疏数据下不容易过拟合。
  4. 理论清晰:直接揭示了基于图的协同过滤的核心——邻域平滑与多层组合。

9. 总结与进阶方向

LightGCN 是对基于图的协同过滤的一次优雅简化。它告诉我们,在像推荐这样的 ID 场景中,图神经网络的效能主要来源于图结构上的相邻节点信息平滑,而非特征变换和非线性激活。

后续拓展方向

  • 社会关系与知识图谱:纳入社交网络或物品属性图,构造异构图进行 LightGCN 风格的传播。
  • 自监督学习:结合对比学习,利用数据增强生成更鲁棒的节点表示(如 SGL 模型)。
  • 超图结构:用超图建模多用户共同点击行为,进一步捕捉高阶协同模式。
  • 实时更新:针对新交互动态更新图结构及节点嵌入,实现在线服务。

LightGCN 不仅是学术上的经典基线,也是工业界落地的优选模型。建议你从复现论文开始,将上述伪代码改造为可运行的完整项目,深入感受图推荐的核心思想。