NewsTorch:基于PyTorch的模块化新闻推荐工具包,整合GNN与LLM前沿技术

发布时间:2026/6/21 12:41:23

NewsTorch:基于PyTorch的模块化新闻推荐工具包,整合GNN与LLM前沿技术 1. 项目概述为什么我们需要NewsTorch如果你正在做新闻推荐系统或者想入门这个领域大概率会面临一个尴尬的局面网上能找到的教程和代码要么是好几年前的“古董”还在用协同过滤或者简单的矩阵分解要么就是一些大厂的论文开源代码动辄几万行依赖复杂环境都配不起来更别提跑通了。你想试试最新的图神经网络GNN来挖掘用户和新闻之间复杂的交互关系或者想用大语言模型LLM来理解新闻的深层语义做更精准的匹配光是数据预处理、模型搭建、训练流程这些基础工作就足以劝退大部分人了。这就是NewsTorch诞生的背景。它不是一个全新的、颠覆性的算法而是一个基于PyTorch的、高度模块化的新闻推荐学习工具包。你可以把它理解为一个“脚手架”或者“乐高积木箱”。它的核心目标是让研究者和开发者能快速搭建、实验和比较不同的新闻推荐模型特别是那些前沿的GNN和LLM模型而不用从零开始重复造轮子。我最初接触这个项目是因为团队需要快速验证一个结合用户行为图和新闻语义的推荐想法。当时我们评估了RecBole、DeepCTR等几个不错的推荐库但它们要么对图神经网络的支持不够友好要么很难无缝集成我们微调过的LLM来做文本特征提取。从头写一个时间成本太高。NewsTorch恰好填补了这个空白——它用PyTorch作为统一的底层框架把新闻推荐中那些脏活累活数据加载、负采样、评估指标都封装好了同时把模型定义、特征工程这些核心部分设计得足够灵活让你可以像搭积木一样把GNN模块、LLM编码器、传统的深度模型组合在一起。简单来说NewsTorch解决了三个痛点一是降低了前沿技术GNN/LLM在新闻推荐场景的应用门槛二是提供了一套标准化的数据处理和评估流程确保实验的可复现性和公平比较三是其模块化设计极大地提升了研发迭代的速度。无论你是想复现顶会论文还是探索自己的新模型它都能提供一个坚实且高效的起点。2. 核心架构与设计哲学NewsTorch的设计遵循着“约定大于配置”和“高内聚、低耦合”的原则。它不是一个大而全的、把所有算法都硬编码进去的黑盒系统而是提供了一系列基础组件和接口。你的主要工作就是像厨师选用食材一样组合这些组件来烹饪你的“模型大餐”。2.1 整体架构拆解整个工具包可以清晰地分为四层数据层 (Data Layer)这是所有机器学习项目的基石。NewsTorch定义了新闻推荐场景下的标准数据格式通常包含用户ID、新闻ID、点击/未点击行为、时间戳以及新闻的文本内容标题、摘要、正文等。它内置了NewsDataset和UserBehaviorDataset这样的类负责从原始日志文件或数据库中加载数据并进行必要的预处理比如构建用户-新闻交互图、对新闻文本进行分词和建立词表。这一层的输出是规整的、可以被模型直接消费的DataLoader。特征层 (Feature Layer)这一层负责将原始数据转化为模型可用的特征。这是NewsTorch灵活性的关键体现。它可能包含ID类特征处理用户ID、新闻ID的嵌入层Embedding Layer。数值特征处理归一化、分桶等。文本特征处理这是集成LLM的核心。这里不直接内置某个特定的LLM而是提供了一个TextEncoder接口。你可以轻松地将Hugging Face Transformers库中的BERT、RoBERTa甚至是GPT、Qwen等模型的输出接入进来作为新闻的语义表征。工具包会帮你处理好文本的tokenization、padding以及GPU内存的管理例如使用梯度检查点。模型层 (Model Layer)这是工具包的核心价值所在。NewsTorch预置或提供了构建多种推荐模型的框架基础深度模型如DeepFM、DIN等用于学习用户和新闻的特征交叉。图神经网络模型这是重头戏。工具包可能基于PyTorch Geometric (PyG) 或 DGL库提供了诸如LightGCN、NGCF等经典GNN推荐模型的实现。更重要的是它提供了构建“用户-新闻”二部图Bipartite Graph的便捷方法并封装了消息传递、邻居采样等图操作让你能专注于设计图上的聚合函数。LLM增强模型这里展示了如何将第2层提取的LLM语义特征与传统的ID特征、GNN学习到的结构特征进行融合。例如一个典型的模型可能是“GNN LLM MLP”的多塔结构。训练与评估层 (Training Evaluation Layer)提供了标准的训练循环、损失函数如BPR Loss、Cross-Entropy Loss和一系列新闻推荐场景的评估指标如AUC、MRR、NDCGK、RecallK等。它确保了不同模型是在完全相同的训练/验证/测试集划分、相同的负采样策略、相同的评估标准下进行比较的这对于科研的严谨性至关重要。2.2 模块化设计的好处这种设计带来的最大好处是可扩展性和可实验性。假设你读到了一篇新论文提出了一种新颖的图注意力机制用于新闻推荐。在NewsTorch中你通常不需要改动数据加载和训练流程只需要在模型层新增一个继承自BaseGNNModel的类实现其中的消息传递和更新函数即可。同样如果你想换一个更强的LLM作为文本编码器也只需要更换特征层中TextEncoder的具体实现。注意NewsTorch作为一个学习工具包其预置的模型更多是作为示例和基线Baseline。它的强大之处在于提供了一个优秀的框架让你能快速将自己的想法实现并与之进行对比。不要期望它开箱即用就能达到SOTAState-of-the-Art效果SOTA效果需要你在模型结构和特征工程上做大量的调优和创新。3. 关键技术点深度解析要真正用好NewsTorch必须理解其背后的几个关键技术点。这些点也是新闻推荐系统乃至现代推荐系统的核心难题。3.1 图神经网络在新闻推荐中的应用新闻推荐中用户和新闻构成了一个天然的动态二部图。用户点击新闻的行为就是图中的边。GNN的魅力在于它可以通过多层消息传递让一个用户节点“感知”到他邻居点击过的新闻的邻居其他点击过相同新闻的用户的信息。这能有效挖掘隐藏在群体行为中的高阶兴趣关联。在NewsTorch中实现一个GNN模型通常会涉及以下步骤图构建将用户和新闻的交互记录user_id, item_id, timestamp转换为图数据对象。这里的关键是处理新闻的时效性——昨天的热门新闻和一年前的新闻重要性显然不同。因此构建图时可能需要引入时间衰减权重或者使用基于时间滑动的动态图。邻居采样对于大规模图无法一次性加载所有邻居。NewsTorch会集成邻居采样算法如随机游走、分层采样只为每个中心节点采样固定数量的邻居以控制计算和内存开销。消息传递与聚合这是GNN的核心。以LightGCN为例其消息传递规则异常简单每一层节点的嵌入是其所有邻居节点上一层的嵌入的平均值。在PyTorch中这可以通过稀疏矩阵乘法高效实现。NewsTorch会封装这些操作。层组合与预测经过多层传播后将每一层学习到的节点嵌入加起来或平均起来得到最终的节点表征。最后通过用户嵌入和新闻嵌入的内积或经过一个MLP来预测点击概率。实操心得GNN模型对超参数非常敏感特别是层数。层数太少无法捕获高阶信息层数太多超过3层很容易导致“过度平滑”即所有节点的嵌入变得相似反而损害推荐性能。在NewsTorch中实验时建议从2层或3层开始调优。3.2 大语言模型作为特征提取器LLM的引入是为了解决传统推荐模型难以理解新闻文本深层语义和隐含话题的问题。例如一篇标题为“某科技公司发布全新AI芯片”的新闻传统词袋模型或Word2Vec可能只能捕捉到“科技”、“公司”、“AI”、“芯片”这些词但LLM能理解这是一条关于“人工智能硬件进展”、“半导体行业动态”的新闻甚至能推断出其可能对“高性能计算”、“自动驾驶”等领域产生影响。在NewsTorch中集成LLM通常有两种模式冻结模式Feature Extraction将预训练好的LLM如BERT作为一个静态的特征提取器。输入新闻标题和摘要取[CLS]位置的输出向量或最后一层隐藏状态的平均值作为该新闻的语义特征向量。这个向量随后会与ID嵌入、GNN嵌入等拼接输入到下游的推荐模型中进行训练。这种模式计算开销小但LLM的知识无法根据推荐任务进行微调。微调模式Fine-tuning将LLM作为整个推荐模型的一部分进行端到端训练。这能让LLM学习到与推荐任务相关的特定文本表示。例如它可能会学会更关注新闻中的情感词、实体名等对点击率预测更有用的信号。这种模式效果通常更好但对计算资源GPU显存要求极高且需要小心防止过拟合。注意事项直接使用原始LLM如完整的BERT-base处理海量新闻文本即使是冻结模式计算成本也非常可观。实践中可以采用以下技巧知识蒸馏用一个大LLM教师模型标注数据训练一个轻量级的小模型学生模型如TinyBERT用于线上推理。向量化预处理离线用LLM将所有新闻文本编码成向量存入数据库线上推荐时直接查询。这要求新闻库相对稳定对新新闻需要有一套近实时的向量化流水线。使用更高效的架构考虑使用ALBERT、DistilBERT等参数更少、速度更快的模型变体。3.3 多模态特征融合策略当同时拥有GNN学习到的结构特征用户-物品交互图和LLM提取的语义特征时如何将它们有效融合是一个关键问题。NewsTorch的模型层通常会提供几种融合策略早期融合Early Fusion将GNN输出的用户/新闻嵌入与LLM提取的新闻语义嵌入直接拼接Concatenate然后输入到一个多层感知机MLP中进行最终预测。这是最简单直接的方式。晚期融合Late Fusion让GNN分支和LLM分支分别做出预测如分别输出一个点击概率分数最后将两个分数通过加权求和或另一个小型神经网络门控网络进行融合。这种方式给了两个模态更大的独立性。交叉注意力融合Cross-Attention Fusion这是更精细的方法。例如可以让用户嵌入来自GNN作为Query新闻的语义特征来自LLM作为Key和Value通过注意力机制来动态决定哪些语义信息对该用户更重要。反之亦然。选择哪种融合策略没有定论需要在你的具体数据集上进行实验。NewsTorch的模块化设计使得切换融合策略就像更换一个模块一样简单。4. 从零开始基于NewsTorch的实践指南理论说了这么多我们来点实际的。假设我们有一个标准的新闻点击日志数据集例如MIND数据集现在想用NewsTorch搭建一个结合LightGCN和BERT的推荐模型。4.1 环境准备与数据预处理首先你需要一个Python环境3.8并安装核心依赖pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 根据你的CUDA版本选择 pip install torch-geometric # 如果使用PyG作为GNN后端 pip install transformers datasets # 用于LLM和数据处理 pip install scikit-learn pandas tqdm # 常用工具库假设NewsTorch工具包已经下载到你的项目目录中。数据预处理是第一步也是最繁琐的一步。通常原始数据是CSV或JSON格式的日志。你需要编写一个脚本将其转换为NewsTorch定义的NewsDataset所需的格式。这个过程一般包括数据清洗过滤掉点击次数过少的用户和新闻冷启动问题另论处理缺失值。构建映射为每个用户和新闻生成唯一的连续整数ID这是高效嵌入查找所必需的。划分数据集按时间顺序划分训练集、验证集和测试集。绝对不能随机划分必须模拟真实的时间流用历史数据预测未来行为。构建交互图使用训练集数据构建用户-新闻二部图。图的边可以带有时间戳权重。文本预处理对新闻的标题、摘要进行清洗、分词并构建词表或直接准备好供BERT使用的tokenizer。NewsTorch可能会提供一个标准的数据处理脚本模板你需要根据自己数据的格式进行适配。4.2 模型定义与组合接下来是核心部分——定义你的混合模型。在NewsTorch的框架下你可能会创建一个新的模型文件my_gnn_llm_model.pyimport torch import torch.nn as nn import torch.nn.functional as F from newstorch.models.base import BaseRecommender from newstorch.layers.gnn import LightGCNConv from transformers import AutoModel, AutoTokenizer class GNNLLMNewsRecommender(BaseRecommender): def __init__(self, num_users, num_items, embedding_dim, gnn_layers, llm_model_namebert-base-uncased): super().__init__() self.user_embedding nn.Embedding(num_users, embedding_dim) self.item_embedding nn.Embedding(num_items, embedding_dim) # GNN部分LightGCN层 self.gnn_convs nn.ModuleList([LightGCNConv() for _ in range(gnn_layers)]) # LLM部分冻结的BERT编码器 self.llm_tokenizer AutoTokenizer.from_pretrained(llm_model_name) self.llm_model AutoModel.from_pretrained(llm_model_name) # 冻结LLM参数仅作为特征提取器 for param in self.llm_model.parameters(): param.requires_grad False self.llm_projection nn.Linear(768, embedding_dim) # BERT输出768维投影到embedding_dim # 融合与预测层 self.fusion_mlp nn.Sequential( nn.Linear(embedding_dim * 3, embedding_dim * 2), # 用户GNN嵌入 新闻GNN嵌入 新闻LLM嵌入 nn.ReLU(), nn.Dropout(0.2), nn.Linear(embedding_dim * 2, 1) ) def encode_text(self, news_texts): 使用LLM编码一批新闻文本 inputs self.llm_tokenizer(news_texts, paddingTrue, truncationTrue, max_length128, return_tensorspt) inputs {k: v.to(self.device) for k, v in inputs.items()} with torch.no_grad(): # 不计算梯度 outputs self.llm_model(**inputs) # 取[CLS] token的表示作为句子向量 text_embeddings outputs.last_hidden_state[:, 0, :] return self.llm_projection(text_embeddings) def forward(self, user_ids, item_ids, item_texts, graph_data): user_ids: 用户ID [batch_size] item_ids: 新闻ID [batch_size] item_texts: 新闻文本列表 [batch_size] graph_data: 包含邻接矩阵等信息的图对象 # 1. 获取初始嵌入 u_emb self.user_embedding(user_ids) i_emb_gnn self.item_embedding(item_ids) # 2. 通过GNN传播 (简化示例实际需在全体节点上传播后索引) # 这里假设 self.gnn_forward 是一个方法能返回所有节点经过GNN传播后的嵌入 all_user_emb, all_item_emb self.gnn_forward(graph_data) u_emb_gnn all_user_emb[user_ids] i_emb_gnn all_item_emb[item_ids] # 3. 获取新闻的LLM语义嵌入 i_emb_llm self.encode_text(item_texts) # 4. 特征融合与预测 combined torch.cat([u_emb_gnn, i_emb_gnn, i_emb_llm], dim-1) prediction self.fusion_mlp(combined).squeeze() return torch.sigmoid(prediction) # 输出点击概率 def gnn_forward(self, graph): 执行多层GNN传播 # 获取所有节点的初始嵌入 all_embeddings torch.cat([self.user_embedding.weight, self.item_embedding.weight], dim0) embeddings_list [all_embeddings] for conv in self.gnn_convs: all_embeddings conv(all_embeddings, graph.adjacency_matrix) # 简化的传播接口 embeddings_list.append(all_embeddings) # 如LightGCN将各层嵌入相加 all_embeddings torch.stack(embeddings_list, dim0).mean(dim0) num_users self.user_embedding.num_embeddings final_user_emb all_embeddings[:num_users] final_item_emb all_embeddings[num_users:] return final_user_emb, final_item_emb这个模型示例展示了如何将ID嵌入、GNN和LLM特征在一个前向传播过程中结合起来。在实际的NewsTorch中LightGCNConv和graph_data的处理会被封装得更完善。4.3 训练循环与负采样新闻推荐通常被建模为点击率CTR预测任务使用二元交叉熵损失。一个关键环节是负采样。对于每一个正样本用户点击的新闻我们需要采样一个或多个负样本用户未点击的新闻来构建训练对。NewsTorch的训练器Trainer会帮你封装好这个循环# 伪代码展示逻辑 for epoch in range(num_epochs): for batch in train_dataloader: # batch包含 user_ids, pos_item_ids, pos_item_texts # 负采样为每个用户采样一个未点击的新闻 neg_item_ids, neg_item_texts sample_negative_items(batch[user_ids]) # 拼接正负样本 all_user_ids torch.cat([batch[user_ids], batch[user_ids]]) all_item_ids torch.cat([batch[pos_item_ids], neg_item_ids]) all_item_texts batch[pos_item_texts] neg_item_texts labels torch.cat([torch.ones_like(batch[user_ids]), torch.zeros_like(batch[user_ids])]).float() # 前向传播 predictions model(all_user_ids, all_item_ids, all_item_texts, graph_data) # 计算损失 loss F.binary_cross_entropy(predictions, labels) # 反向传播与优化 optimizer.zero_grad() loss.backward() optimizer.step()负采样策略直接影响模型效果。最简单的随机采样可能不够好因为用户未点击的新闻中有些是真正不感兴趣的硬负例有些只是没曝光过未观测到。高级的采样策略如“基于流行度的采样”或“对抗性负采样”可以提升模型区分度这些策略也可能在NewsTorch中提供选项。4.4 评估与调优训练完成后在验证集上进行评估。NewsTorch会提供标准的评估函数计算AUC、NDCG10等指标。调优经验嵌入维度通常设置在64到256之间。维度太低表达能力不足太高容易过拟合且增加计算量。可以从128开始尝试。GNN层数如前所述2或3层是常见的起点。可以通过观察验证集指标随层数的变化来选择。学习率使用Adam优化器时学习率1e-3或3e-4是常见的初始选择。可以配合学习率预热Warmup和衰减Decay。Dropout在融合MLP中加入Dropout如0.2-0.5是防止过拟合的有效手段。LLM特征尝试不同的LLM如RoBERTa、DeBERTa或者尝试对LLM的最后几层进行微调看看是否能带来提升。负采样数量增加负采样数量如从1个到4个通常会稳定训练并提升效果但也会增加计算成本。5. 常见问题与实战排坑记录在实际使用NewsTorch或类似工具包进行开发时你会遇到各种各样的问题。下面是我和团队在项目中踩过的一些坑和解决方案。5.1 内存溢出与性能优化问题当用户和新闻数量达到百万级图结构非常大即使使用稀疏矩阵全图训练也会导致GPU内存溢出。解决方案邻居采样这是处理大规模图的标准做法。不要在全图上进行卷积而是为每个批次batch的目标节点采样一个固定大小的子图进行训练。NewsTorch应集成类似NeighborSampler的组件。梯度累积当GPU内存只能容纳很小的批次大小时可以使用梯度累积。多次前向传播的梯度累加后再更新一次参数等效于增大了批次大小。混合精度训练使用torch.cuda.amp进行自动混合精度训练可以显著减少显存占用并加快训练速度。LLM编码离线化如果使用冻结的LLM最耗时的部分是将新闻文本编码为向量。可以预先将所有新闻用LLM编码好存储为向量文件。训练和推理时直接加载这些向量而不是实时调用LLM。5.2 冷启动问题问题对于新用户或新新闻由于没有历史交互数据GNN无法为其学习到有效的嵌入导致推荐质量差。解决方案对于新用户更多地依赖LLM提供的新闻语义特征采用基于内容的推荐作为补充。例如可以询问新用户的兴趣标签或者用其首次点击的少数新闻的语义特征来初步表征其兴趣。对于新新闻同样依赖LLM的语义特征。在NewsTorch的框架下一个新新闻入库时可以立即通过LLM得到其语义向量。在模型中可以将这个LLM向量与一个随机初始化的ID嵌入相加或拼接作为该新闻的初始表征参与图的传播和预测。随着该新闻被不断点击其GNN学习到的结构嵌入会逐渐占据主导。5.3 线上线下效果不一致问题模型在离线测试集上指标很好如NDCG很高但上线A/B测试后点击率提升不明显甚至下降。排查方向数据分布不一致离线训练测试数据与线上实时数据分布存在差异。确保你的训练数据时间窗口和线上环境匹配并且包含了足够近期的数据以反映用户兴趣的变化。评估指标有偏离线评估通常基于“曝光且点击”的数据但线上存在“曝光未点击”和“未曝光”的大量样本。考虑引入更接近线上业务的评估指标如线上AUC。特征穿越这是最常见也是最致命的问题。确保在构建每个训练样本时只使用了该样本发生时间点之前的信息。例如不能用用户未来的点击行为来构建当前时刻的用户兴趣图。在NewsTorch的数据预处理阶段必须严格按照时间戳划分和构建图确保数据的时序纯洁性。服务延迟如果模型尤其是LLM部分推理速度太慢无法满足线上服务的响应时间要求如百毫秒级就需要进行模型压缩、蒸馏或使用更轻量的架构。5.4 模型融合策略失效问题费了很大劲加入了LLM特征但模型效果相比纯GNN模型提升甚微甚至下降。可能原因与对策特征冗余GNN从交互中学到的信息可能已经隐含了文本语义因为相似语义的新闻会被相似的用户点击。可以尝试对GNN嵌入和LLM嵌入做相关性分析。融合方式不当简单的拼接可能不够。尝试更复杂的融合方式如注意力机制让模型自己决定更相信哪种特征或者设计一个门控网络Gating Network。LLM特征质量你用的预训练LLM可能与你新闻领域的语言风格不符。尝试在领域相关的文本如历史新闻库上对LLM进行继续预训练Continual Pre-training或微调。梯度冲突在端到端微调LLM时来自推荐任务的梯度可能会破坏LLM本身预训练好的语言知识。可以尝试采用渐进式解冻Gradual Unfreezing或不同的学习率为LLM部分设置更小的学习率。最后我想分享一点个人体会NewsTorch这类工具包最大的价值是它把工程上的复杂性封装起来让你能更专注于模型和算法本身的创新。但在使用它时切忌把它当成一个“自动炼丹机”。你必须深入理解数据流动的每一个环节从原始日志到最终预测。每一个设计选择负采样策略、图构建方法、融合方式背后都有其考量需要根据你的具体业务场景和数据特点进行反复实验和验证。推荐系统没有银弹NewsTorch给了你一把好枪但瞄准哪里、何时扣动扳机还需要你这个“狙击手”凭借对业务和数据的深刻理解来决定。在实际项目中我建议先用一个简单的模型如纯LightGCN跑通NewsTorch的全流程建立一个稳定的基线然后再逐步引入LLM等复杂模块这样能更清晰地评估每个模块带来的收益也更容易定位问题所在。

相关新闻