推荐模型之DCN
本文介绍了推荐系统的经典模型——深度交叉网络DCN,并给出去原理和python实现。
一、概念
DCN(Deep & Cross Network)模型是一种常用于推荐系统的深度学习模型,出自谷歌的论文《Deep & Cross Network for Ad Click Predictions》,旨在有效地捕捉特征之间的交叉关系。DCN模型结合了深度网络和交叉网络两种结构,能够同时学习特征的高阶交叉和非线性组合,常用于推荐系统的精排阶段。
DCN模型的核心优势在于其能够显式地学习特征之间的交互关系,同时结合深度网络的强大表达能力,适用于需要处理复杂特征交互的场景。无论是推荐系统(个性化推荐)、广告系统(CTR)、搜索排序(相关度)还是用户行为预测,DCN都能够通过高效的特征交互学习,显著提升模型的预测性能。
二、原理
DCN模型由两个主要部分组成:
- Cross Network(交叉网络):交叉网络通过逐层交叉操作来捕捉特征之间的交叉关系。每一层的输出是当前层输入与原始输入的交叉组合,能够有效地学习特征的高阶交叉。
- Deep Network(深度网络):深度网络是一个典型的MLP,负责学习特征的非线性组合。
目前,DCN已经发展出了两个版本:
1、DCN-v1
在这一版的DCN模型中,每个交叉层的公式为:
其中,是底部交叉层的输入,由各种类别特征的嵌入和稠密特征拼接而成;
分别是第
个交叉层的输入和输出;
是第
个交叉层的权重和偏置,都是d维的可学习参数。对于一个包含L个交叉层的交叉网络,其最终结果包含了原始输入
中所有元素之间小于或者等于 L+1 阶的交叉。
2、DCN-v2
在DCN-v1中,每层要学习的参数只有,参数数量有限,限制了模型的表达能力。因此,DCN-v2用一个d*d的矩阵
代替了DCN-v1中的d维向量
:
其中,是原始输入,
是第
层的输入,长度都为d。而在实际的应用场景中,原始输入的维度d一般都很大,可以是上千维,这时候
作为一个d*d的矩阵,会给模型造成巨大的计算压力。因此,DCN-v2的作者提出了使用两个小矩阵对
进行分解的策略,即
,这两个小矩阵的维度都为d*r(r<<d),从而将参数量从d²减少为2*d*r,实际上就是低秩矩阵分解。
3、融入DNN
为了进一步提升DCN网络的性能,一般来说我们会显式地融合DCN和DNN,通常有两种形式:一种是原始特征先过DCN,再过DNN,最后输出;另一种是原始特征分别经过DCN和DNN,然后合并两者的输出,再使用一个全连接层计算最终的预测结果。
三、python实现
以下是一个结合电商领域的知识构建数据集并实现DCN(Deep & Cross Network)模型的完整代码示例。我们构建一个模拟的电商数据集,包含以下字段:
- 用户特征:年龄、性别、用户等级
- 商品特征:商品类别、价格区间
- 行为特征:用户点击、购买记录
模型同时预测用户的点击和购买行为。
import torch
import torch.nn as nn
import torch.optim as optim
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
# 构建模拟电商数据集
def create_dataset(num_samples=1000):
np.random.seed(42)
data = {
"user_age": np.random.randint(18, 60, num_samples),
"user_gender": np.random.choice(["M", "F"], num_samples),
"user_level": np.random.choice(["low", "medium", "high"], num_samples),
"item_category": np.random.choice(["electronics", "clothing", "home"], num_samples),
"item_price": np.random.uniform(10, 1000, num_samples),
"clicked": np.random.choice([0, 1], num_samples),
"purchased": np.random.choice([0, 1], num_samples),
}
return pd.DataFrame(data)
# 数据预处理
def preprocess_data(df):
# 编码分类特征
label_encoders = {}
for col in ["user_gender", "user_level", "item_category"]:
le = LabelEncoder()
df[col] = le.fit_transform(df[col])
label_encoders[col] = le
# 标准化数值特征
scaler = StandardScaler()
df["user_age"] = scaler.fit_transform(df[["user_age"]])
df["item_price"] = scaler.fit_transform(df[["item_price"]])
# 特征和标签
features = df[["user_age", "user_gender", "user_level", "item_category", "item_price"]].values
labels = df[["clicked", "purchased"]].values
return features, labels
# 构建DCN模型
class DCN(nn.Module):
def __init__(self, input_dim, cross_layers, deep_layers):
super(DCN, self).__init__()
self.input_dim = input_dim
# Cross Network
self.cross_layers = nn.ModuleList([nn.Linear(input_dim, input_dim) for _ in range(cross_layers)])
# Deep Network
deep_modules = []
for i in range(len(deep_layers) - 1):
deep_modules.append(nn.Linear(deep_layers[i], deep_layers[i+1]))
deep_modules.append(nn.ReLU())
self.deep_network = nn.Sequential(*deep_modules)
# Final output layer
self.output_layer = nn.Linear(deep_layers[-1] + input_dim, 2) # 2个输出:点击和购买
def forward(self, x):
# Cross Network
cross_out = x
for layer in self.cross_layers:
cross_out = layer(cross_out) + cross_out * x
# Deep Network
deep_out = self.deep_network(x)
# Concatenate Cross and Deep outputs
combined_out = torch.cat([cross_out, deep_out], dim=1)
# Final output
return self.output_layer(combined_out)
# 主程序
if __name__ == "__main__":
# 构建数据集
df = create_dataset()
features, labels = preprocess_data(df)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)
# 转换为Tensor
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32)
y_test = torch.tensor(y_test, dtype=torch.float32)
# 模型参数
input_dim = X_train.shape[1]
cross_layers = 3
deep_layers = [input_dim, 64, 32]
# 初始化模型
model = DCN(input_dim, cross_layers, deep_layers)
criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
epochs = 20
for epoch in range(epochs):
model.train()
optimizer.zero_grad()
outputs = model(X_train)
loss = criterion(outputs, y_train)
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item():.4f}")
# 测试模型
model.eval()
with torch.no_grad():
test_outputs = model(X_test)
test_loss = criterion(test_outputs, y_test)
print(f"Test Loss: {test_loss.item():.4f}")

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)