Merlin是NVIDIA针对推荐系统场景推出的端到端框架,它把数据加载、特征工程、模型训练与推理部署集中在同一套工具链中。在推荐流程里,原始日志通常包含大量用户行为、物品属性和上下文信息,这些数据需要经过特征变换才能输入排序模型。本文围绕特征变换和排序模型训练两个环节,说明如何借助Merlin中的NVTabular和Merlin Models完成一条可落地的训练流水线。

理解Merlin工具链中的特征变换基础
Merlin的核心组件之一是NVTabular,它专门为表格数据的大规模特征工程而设计。NVTabular引入了算子(Operator)的概念,每个算子负责一种特征变换逻辑,比如将类别值映射为连续ID、对数值特征做归一化、根据目标变量计算统计编码等。这些算子可以像搭积木一样串联成一个工作流(Workflow),并且工作流会被自动编译为GPU执行图,在训练数据和推理数据上保持一致的处理逻辑。
常用的特征变换算子包括Categorify、Normalize和TargetEncoding。Categorify用于处理用户ID、物品ID、类目等高基数类别特征,它会把字符串或原始ID映射为从0开始的整数,并支持频率阈值过滤,避免长尾类别占用过多词汇表。Normalize对连续特征做标准化或归一化,让不同量纲的数值特征处于相近的分布范围。TargetEncoding则利用目标变量的平均值对类别进行编码,特别适合处理那些与点击率、转化率强相关的类别特征。
NVTabular的另一个优势是GPU加速。它基于RAPIDS cuDF实现数据框操作,单张V100或A100显卡就能在分钟级完成几亿行日志的特征变换。相比传统基于Pandas或Spark的流程,NVTabular在处理大规模推荐数据时能节省大量时间,而且内存占用也更可控。
用NVTabular构建特征变换工作流
在实际项目中,原始数据通常以Parquet文件形式存放在对象存储或本地磁盘。第一步是定义哪些列属于类别特征,哪些列属于连续特征。NVTabular的Workflow接收列名列表,并允许通过add_cat_feature和add_cont_feature方法为不同列绑定对应的算子。下面是一个典型的特征变换代码示例。
import nvtabular as nvt from nvtabular import ops # 定义特征列 cat_cols = ['user_id', 'item_id', 'category'] cont_cols = ['price', 'age', 'click_count'] # 创建Workflow,输出列包含原始列和变换后的列 workflow = nvt.Workflow(cat_cols + cont_cols) # 对类别特征执行Categorify,将字符串ID映射为连续整数 workflow.add_cat_feature([ops.Categorify(columns=cat_cols)]) # 对连续特征执行Normalize,将数值标准化到零均值单位方差 workflow.add_cont_feature([ops.Normalize(columns=cont_cols)])
上面的代码中,Categorify会扫描整个数据集,统计每个类别出现的频次,然后生成映射表。Normalize则计算每个连续特征的均值和标准差,并保存为统计信息。这些统计信息会持久化到工作流内部,后续对验证集、测试集或线上推理数据做变换时,可以直接复用已经拟合好的参数,避免数据泄露。
工作流构建完成后,需要调用fit方法在训练数据上进行拟合并保存。保存工作流的代码很简单,通常只需要指定输出目录。之后可以通过load方法重新加载,并调用transform方法对新的数据集做特征变换。例如先把训练数据变换为Parquet文件,再加载到模型训练阶段。一个关键点是,类别映射表需要在训练阶段固定下来,推理时遇到未知类别时可以使用预先设置的填充值。
排序模型训练实践
Merlin Models提供了多种常用的排序模型结构,包括DLRM、DCN、MMOE等。DLRM擅长处理大规模稀疏特征与连续特征的交互,DCN通过交叉网络捕捉高阶特征交叉,MMOE则适合多目标排序场景。对于点击率预估任务,可以选择DCN模型,它结构清晰、训练速度快,并且能够通过堆叠隐藏层提升表达能力。
训练排序模型之前需要准备Merlin Dataset,它可以直接读取Workflow输出目录中的Parquet文件。Merlin Models会根据Dataset的schema自动推断输入特征的类型和维度,省去了手动定义输入层的过程。下面是一个训练DCN模型的完整示例。
import merlin.models.tf as mm
from merlin.io import Dataset
# 加载经过NVTabular变换后的训练集和验证集
train = Dataset('/path/to/train_processed')
valid = Dataset('/path/to/valid_processed')
# 构建DCN排序模型
model = mm.DCNModel(
schema=train.schema,
depth=2,
hidden_units=[512, 256, 128],
prediction_tasks=mm.BinaryClassificationTask('click')
)
# 编译模型并训练
model.compile(optimizer='adam', run_eagerly=False)
model.fit(train, validation_data=valid, batch_size=4096, epochs=3)DCNModel的参数中,depth控制交叉网络的层数,hidden_units定义了深度神经网络部分的每一层宽度。prediction_tasks指定了输出任务,这里使用BinaryClassificationTask表示点击率预测的二分类任务。训练过程中可以设置batch_size和epochs,也可以加入早停回调避免过拟合。Merlin Models基于TensorFlow或PyTorch后端,因此可以很方便地使用TensorBoard、模型检查点等生态工具。
训练完成后,通过model.evaluate方法在测试集上查看AUC、LogLoss等指标。如果效果不理想,可以尝试调整交叉层深度、隐藏层宽度或者更换为DLRM模型。另外,Merlin Models支持将模型导出为TensorFlow SavedModel格式,方便后续部署到Triton Inference Server进行在线推理。在线推理时同样需要加载NVTabular的Workflow,确保特征变换与训练时完全一致。
如果推荐场景包含用户行为序列特征,还可以引入Transformers4Rec组件,将用户最近的交互序列作为输入构建序列化排序模型。不过对于大多数以特征变换和排序模型训练为起点的项目,先用NVTabular完成数据预处理,再用Merlin Models训练DCN或DLRM已经能够覆盖大部分需求。随着数据规模和模型复杂度的提升,可以逐步加入更多高级算子与多目标训练策略。