译者 | 陈峻
审校 | 重楼
你知道什么是推荐引擎吗?它是每一笔互联网交易背后的算法,无论是亚马逊、Netflix、YouTube、TikTok,甚至是 LinkedIn、Facebook、X(Twitter)、以及Snapchat,所有这些网站、以及互联网上几乎所有的内容策划、或产品市场应用,都从推荐算法中获利颇丰。
简单来说,推荐算法会建立一套模型,包括你的喜好、憎恶、收藏的物品、类型和项目等。当你在网上进行一笔交易时,它们几乎会读懂你的想法,并预测你最有可能购买的下一个产品。目前,YouTube 和 TikTok 上所使用的推荐算法已非常准确,以至于它们可以让用户沉迷数小时。下面展示了YouTube、TikTok、Instagram 和 Facebook 的月访问量足以证明这一点。
- Facebook:29亿
- YouTube:22 亿
- Instagram:14亿
- TikTok:10亿
显然,此类算法会带来更好的客户参与度、更好的客户体验、以及平台收入的提升。可以说,成瘾就建立在这些超优化算法的准确性和令人生畏的性能之上,而它们成功的秘诀就依赖于出色的推荐算法。
一、推荐算法的类型
1.协作筛选(基于用户)
基于用户的协作筛选是一种推荐技术,它假设具有相似偏好的用户将具有相似的品味。它利用用户-项目(user-item)的交互数据,来识别用户之间的相似性,且通常采用余弦相似性或Pearson 相关性等来度量。该方法根据类似用户给出的评级,来预测其他用户的评级或偏好。
但是,此方法可能会面临一些挑战,例如:尚未与系统交互的新用户,会出现“冷启动问题”,并且在处理大量用户时,也可能会出现可扩展性问题。
Python
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def user_based_cf(ratings_matrix, user_id, k=5):
similarities = cosine_similarity(ratings_matrix)
user_similarities = similarities[user_id]
similar_users = np.argsort(user_similarities)[::-1][1:k+1]
recommendations = np.zeros(ratings_matrix.shape[1])
for similar_user in similar_users:
recommendations += ratings_matrix[similar_user]
return recommendations / k
上述代码展示了:
- 使用余弦相似度来计算用户的相似度
- 查找与目标用户最相似的用户k
- 汇总类似用户的评分以生成推荐
- 返回类似用户对每个项目的平均评分而且,它实现起来非常简单,易于修改或扩展。
2.协作筛选(基于项目)
基于项目的协作筛选假定用户会更喜欢与他们过去喜欢的项目相类似的项目。它根据用户评分或交互来计算项目之间的相似性。这种方法通常比基于用户的协作筛选更具可扩展性,尤其是在用户众多而项目较少的情况下。它允许通过预先计算项目的相似性,以更快地进行实时推荐。
虽然此方法能比基于用户的方法更好地处理新用户,但它对缺乏足够评级的新项目不一定奏效。随着时间的推移,它受到用户偏好变化的影响也较小。
Python
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def item_based_cf(ratings_matrix, item_id, k=5):
similarities = cosine_similarity(ratings_matrix.T)
item_similarities = similarities[item_id]
similar_items = np.argsort(item_similarities)[::-1][1:k+1]
recommendations = np.zeros(ratings_matrix.shape[0])
for similar_item in similar_items:
recommendations += ratings_matrix[:, similar_item]
return recommendations / k
上述代码展示了:
- 通过转置评级矩阵以计算项目之间的相似性
- 查找与目标项目最相似的k
- 汇总类似商品的用户评分
- 返回基于相似项目的每个用户的平均评分而且,它对于用户多于项目的系统非常有效。
3.矩阵分解
矩阵分解会将用户-项目交互矩阵分解为低维度矩阵,并假设用户偏好和项目特征可以由潜在的因素所表示。奇异值分解 (Singular Value Decomposition,SVD) 或交替最小二乘法 (Alternating Least Squares,ALS) 等技术通常被用于此目的。
与基于上述记忆的协作筛选方法相比,这种方法可以有效地处理大型稀疏数据集,而且通常能够提供更高的准确性。此外,它还可以结合正则化技术,来防止过度拟合,从而增强模型对不可见的数据的泛化。
Python
import numpy as np
def matrix_factorization(R, P, Q, K, steps=5000, alpha=0.0002, beta=0.02):
Q = Q.T
for step in range(steps):
for i in range(len(R)):
for j in range(len(R[i])):
if R[i][j] > 0:
eij = R[i][j] - np.dot(P[i,:], Q[:,j])
for k in range(K):
P[i][k] += alpha * (2 * eij * Q[k][j] - beta * P[i][k])
Q[k][j] += alpha * (2 * eij * P[i][k] - beta * Q[k][j])
e = 0
for i in range(len(R)):
for j in range(len(R[i])):
if R[i][j] > 0:
e += pow(R[i][j] - np.dot(P[i,:], Q[:,j]), 2)
for k in range(K):
e += (beta/2) * (pow(P[i][k], 2) + pow(Q[k][j], 2))
if e < 0.001:
break
return P, Q.T
上述代码展示了:
- 实现基本的矩阵分解算法
- 使用梯度下降,来最小化预测评级和实际评级之间的误差
- 结合正则化以防止过拟合
- 迭代更新用户和项目的潜在因素
- 当误差低于阈值或达到最大步长时停止
4.基于内容的筛选
基于内容的筛选根据项目的功能和用户的偏好来推荐项目。它根据每个用户和项目的特征,为每个用户和项目构建一个配置文件。
通常此方法采用诸如 TF-IDF(术语频率-逆文档频率)和余弦相似度等技术,进行文本分析和余弦相似度进行匹配。由于该方法并不依赖于先前的用户交互,因此有效地解决了新项目的问题。
然而,它也可能受到过度专业化(overspecialization)的影响,并导致给出的建议缺乏多样性。此外,其有效的实施往往需要良好的特征工程,以确保能准确地捕获项目的相关特征。
Python
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
def content_based_filtering(item_descriptions, user_profile, k=5):
vectorizer = TfidfVectorizer()
item_vectors = vectorizer.fit_transform(item_descriptions)
user_vector = vectorizer.transform([user_profile])
similarities = cosine_similarity(user_vector, item_vectors)
top_items = np.argsort(similarities[0])[::-1][:k]
return top_items
上述代码展示了:
- 使用 TF-IDF 将文本描述转换为数值向量
- 计算用户配置文件和项目描述之间的余弦相似度
- 返回与用户配置文件最相似的项目k此方法不但对于具有明确定义的物料特征的系统非常高效,而且可以通过轻松的扩展,来包含多种功能类型。
5.混合推荐系统
混合推荐系统结合了两种或多种推荐技术,以利用它们各自的优势。通过集成多种方法,混合系统可以减轻例如:冷启动问题等,单一方法的弱点。常见的方法组合包括协作筛选和基于内容的筛选。其涉及到的技术包括:加权、切换、混合或meta-level方法。
与单一方法系统相比,混合系统通常可以提供更强大、更准确的建议。当然,有效的实施也离不开仔细的调整,以平衡不同的组件,并确保其最佳性能。
Python
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def hybrid_recommender(ratings_matrix, content_matrix, user_id, alpha=0.5, k=5):
cf_similarities = cosine_similarity(ratings_matrix)
content_similarities = cosine_similarity(content_matrix)
hybrid_similarities = alpha * cf_similarities + (1 - alpha) * content_similarities
user_similarities = hybrid_similarities[user_id]
similar_users = np.argsort(user_similarities)[::-1][1:k+1]
recommendations = np.zeros(ratings_matrix.shape[1])
for similar_user in similar_users:
recommendations += ratings_matrix[similar_user]
return recommendations / k
上述代码展示了:
- 将协作筛选和基于内容的相似性相结合
- 使用带有参数 alpha 的加权求和方法
- 根据混合相似度查找相似用户
- 根据类似用户的评分生成推荐而且,它还允许轻松调整 CF 和基于内容的方法之间的平衡
6.奇异值分解 (SVD)
奇异值分解是一种矩阵分解技术,它将矩阵分解为三个分量:U、Σ 和 V^T。在此分解中,U 和 V 分别表示左奇异向量和右奇异向量,而 Σ 包含了奇异值。SVD 通过仅保留顶部的奇异值k来降低维度。这有助于揭示用户与项目交互中的潜在因素。
此方法对于处理推荐系统中常见的大型稀疏矩阵非常有效。此外,SVD 在准确性和计算效率之间提供了良好的平衡,使其成为生成推荐的热门选择。
Python
import numpy as np
from scipy.sparse.linalg import svds
def svd_recommender(ratings_matrix, k=5):
U, s, Vt = svds(ratings_matrix, k=k)
sigma = np.diag(s)
predicted_ratings = np.dot(np.dot(U, sigma), Vt)
return predicted_ratings
上述代码展示了:
- 使用 scipy 的svd函数来执行截短了的 SVD
- 仅使用顶部奇异值k重建评级矩阵
- 返回所有“用户-项目”对的预测评级的密集矩阵由于适用于大型稀疏评级矩阵,它还可以很容易地集成到一个更大的推荐系统中。
7.张量分解
张量分解技术会将传统的矩阵分解扩展为多维数据,并允许将时间和位置等上下文信息合并到推荐中。它利用 CP 分解等方法,将张量分解为各个分量张量之和,以捕获多个因素之间的复杂交互。与二维方法相比,由于处理的是更高维的数组,因此该方法需要更多的数据和计算资源。
同时,此方法可以通过利用数据的其他维度,来提供高度个性化和上下文感知的建议。数据结构复杂性的增加,会使得在各种上下文中,对用户偏好的理解更加细致入微,整体推荐的准确性也就相应提高了。
Python
import numpy as np
import tensorly as tl
from tensorly.decomposition import parafac
def tensor_factorization_recommender(tensor, rank=10):
factors = parafac(tensor, rank=rank)
reconstructed_tensor = tl.kruskal_to_tensor(factors)
return reconstructed_tensor
上述代码展示了:
- 使用 TensorLy 库进行张量运算和分解
- 将 PARAFAC 分解应用于输入张量
- 从分解因子中重建张量
- 将重建的张量作为建议返回而且,它还可以处理多维数据(例如,用户-项目-上下文)。
8.神经协作筛选
基于深度学习的推荐系统会将协作筛选技术与神经网络相结合。这种方法能够学到非线性用户-项目的交互,而传统的矩阵分解方法则可能难以解决。深度学习推荐器通常使用嵌入层,来表示密集的低维空间中的用户和项目。据此,它可以轻松地集成各种附加功能或附带信息,包括用户人口统计或项目描述等,从而提高推荐的效果。
在大型数据集上进行训练时,基于深度学习的系统在准确性方面,通常会优于传统的矩阵分解方法。当然,这一优势是以计算复杂性的增加和对大数据的需求为代价的。
此外,深度学习推荐器还需要仔细的超参数调优,才能获得最佳结果。与更简单的协作筛选方法相比,深度学习推荐器的实施和维护更具挑战性。
Python
import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, Flatten, Dense, Concatenate
from tensorflow.keras.models import Model
def neural_collaborative_filtering(num_users, num_items, embedding_size=100):
user_input = Input(shape=(1,), dtype='int32', name='user_input')
item_input = Input(shape=(1,), dtype='int32', name='item_input')
user_embedding = Embedding(num_users, embedding_size, name='user_embedding')(user_input)
item_embedding = Embedding(num_items, embedding_size, name='item_embedding')(item_input)
user_vecs = Flatten()(user_embedding)
item_vecs = Flatten()(item_embedding)
concat = Concatenate()([user_vecs, item_vecs])
dense1 = Dense(128, activation='relu')(concat)
dense2 = Dense(64, activation='relu')(dense1)
output = Dense(1, activation='sigmoid')(dense2)
model = Model(inputs=[user_input, item_input], outputs=output)
model.compile(optimizer='adam', loss='binary_crossentropy')
上述代码展示了:
- 使用 TensorFlow 和 Keras 构建神经网络模型
- 为用户和项目创建嵌入层
- 连接用户和项目嵌入
- 添加密集层以学习非线性交互
- 返回一个已编译的模型,以便进行训练
二、Netflix 案例研究
作为一种协作筛选算法,Netflix 的推荐系统源于 2000 年的 CineMatch。它使用会员评分来估计用户对于电影的喜爱程度。2006 年,Netflix 发起了 100 万美元的奖金池,旨在创建一个能够胜过 CineMatch 10% 的模型,进而让获胜的算法被应用到Netflix的内部数据中。
Netflix很快以此开始积累用户,并在2007年转向流媒体数据,让观众接触到了实时生成建议的强化学习算法和聚类算法。随着推荐算法在有效性上的改进,越来越多的用户开始转用Netflix。他们在Netflix上观看的内容中,几乎有80%是由推荐算法所建议的。
说到Netflix 先进的机器学习技术和聚类技术,该系统是基于用户观看的电影相关元数据,由 1300 多个聚类组成。这使得他们能够向用户提供高度优化的建议。不过,Netflix很快就遇到了一个新的问题--用户规模。随着月用户数达到数亿级,Netflix需要全力投入云计算。
简而言之,Netflix从 2008 年开始将所有数据迁移到 Amazon Web Services (AWS)上。 他们充分利用了AWS 内置的对于机器学习的支持。据报道,Netflix 早在 2022 年就为其全球观众使用了超过 100,000 台 AWS 服务器和 1,000 个 Kinesis 分片。而且,Netflix的推荐器算法是高度自动化的,每天都能为用户执行数千次 A/B 测试。截止去年,Netflix已获得了高达310亿美元的收入。
目前,Netflix推荐系统的主要部分包括:
- 强化学习:根据用户行为,Netflix 会实时更改屏幕上的内容。系统处于不断变化的状态,会根据用户的交互而变化。
- 深度神经网络:鉴于数据规模相当庞大(超过 15,000 个节目和近 3 亿用户),深度学习和NVIDIA技术(请参阅下文,以了解使用 NVIDIA 最新的 Merlin 深度学习技术)得到了广泛的使用。
- 矩阵分解:通过在高度稀疏和庞大的矩阵上有效地执行奇异值分解 (SVD),Netflix 可以估计某些类型的节目对于用户的重要性和吸引力。
- 集成学习:上面列出的算法的组合可以动态调整推荐,实现了没有两个用户会看到相同的屏幕。这种个性化是获取大笔资金,并使得 Netflix 在所有 OTT 平台上处于领先地位的根本原因。Netflix的上述所有这些模型和优化,每天都会为数十万用户运行数十万次。
三、现代化深度学习技术
针对大规模用户,任何一台计算机都无法单独地运行机器学习模型。这就是 AWS 在数千台机器上,以分布式方式运行 ML 算法的原因。
现代化推荐系统已广泛地使用到了深度学习。作为深度学习的一部分,GPU/TPU 计算系统被广泛用于加速计算。例如,NVIDIA 的 GPU 集群在 ML 算法的执行中,发挥着重要的作用。其新近发布的Merlin,就是一种高性能推荐算法。经过优化,它可以在数千台机器上运行,并提供卓越的计算结果。
1.NVIDIA 推荐系统
NVIDIA Merlin官宣的深度推荐系统应用框架包括:
NVTabular(https://github.com/NVIDIA/nvTabular)
NVTabular 是一个特征工程和预处理库,旨在快速便捷地操作 TB 级数据集。它特别适用于推荐系统,这些系统需要一种可扩展的方式,来处理诸如用户-项目元数据、以及上下文信息等。它提供了一种高级抽象来简化代码,并使用 RAPIDS cuDF 库来加速 GPU 上的计算。使用 NVTabular,你只需 10-20 行高级 API 代码,就可以设置好数据工程管道。与基于 CPU 的优化方法相比,NVTabular 实现了高达 10 倍的加速,而且无论 GPU/CPU 及内存的配置如何,都不会受到数据集大小的限制。
HugeCTR(https://github.com/NVIDIA/HugeCTR)
HugeCTR 是一个高效的 GPU 框架,专为推荐模型训练而设计,旨在实现高性能和易用性。它既支持简单的深度模型,也支持最先进的混合模型,如W&D、Deep Cross Network和DeepFM。而HugeCTR 的 DLRM模型的详细信息和超参数,则可以很容易地以JSON格式被指定,并允许开发者从一系列常见的模型中进行快速选择。
TensorRT (https://developer.nvidia.com/tensorrt)和Triton 推理服务器(https://developer.nvidia.com/nvidia-triton-inference-server)
NVIDIA TensorRT 是一个用于高性能深度学习推理的 SDK 。它包括了一个深度学习推理优化器和运行时,可以为推理应用程序提供低延迟和高吞吐量的服务。TensorRT 可以使用通用接口,即开放神经网络交换格式ONNX,接入来自所有深度学习框架的训练神经网络。
而NVIDIA Triton 推理服务器提供了针对 NVIDIA GPU 优化的云推理解决方案。该服务器通过 HTTP 或 gRPC 端点提供推理服务,允许远程客户端请求对服务器管理的任何模型进行推理。目前,Triton Server 可以使用包括 TensorFlow、PyTorch (TorchScript)、ONNX 运行时和 TensorRT 运行时等多个后端,来提供深度学习推荐器模型。
代码示例
以下代码示例展示了转换 1 TB Criteo Ads 数据集所需的实际预处理工作流。该工作流仅使用 NVTabular 通过十几行代码指定的数值列和分类列。据此,我们可以定义一个 NVTabular 工作流,并提供一组训练和验证文件。然后,我们再将预处理操作添加到工作流中,并将数据保存到磁盘上。相比之下,那些自定义构建的处理代码,例如:由Facebook 的 DLRM 实现的基于 NumPy 的数据工具,对于同一管道,则需要 500-1000 行代码才能实现。
Python
import nvtabular as nvt
import glob
cont_names = ["I"+str(x) for x in range(1, 14)] # specify continuous feature names
cat_names = ["C"+str(x) for x in range(1, 27)] # specify categorical feature names
label_names = ["label"] # specify target feature
columns = label_names + cat_names + cont_names # all feature names
# initialize Workflow
proc = nvt.Worfklow(cat_names=cat_names, cont_names=cont_names, label_name=label_names)
# create datsets from input files
train_files = glob.glob("./dataset/train/*.parquet")
valid_files = glob.glob("./dataset/valid/*.parquet")
train_dataset = nvt.dataset(train_files, gpu_memory_frac=0.1)
valid_dataset = nvt.dataset(valid_files, gpu_memory_frac=0.1)
# add feature engineering and preprocessing ops to Workflow
proc.add_cont_feature([nvt.ops.ZeroFill(), nvt.ops.LogOp()])
proc.add_cont_preprocess(nvt.ops.Normalize())
proc.add_cat_preprocess(nvt.ops.Categorify(use_frequency=True, freq_threshold=15))
# compute statistics, transform data, export to disk
proc.apply(train_dataset, shuffle=True, output_path="./processed_data/train", num_out_files=len(train_files))
proc.apply(valid_dataset, shuffle=False, output_path="./processed_data/valid", num_out_files=len(valid_files))
你可以通过链接--https://github.com/NVIDIA-Merlin,在GitHub 存储库中找到整个技术栈。
小结
综上所述,推荐系统已从简单的统计建模、基于内容的筛选和协作筛选,发展到了我们现在常见的深度学习神经网络、HPC 节点、矩阵分解,并正在向更大维度的扩展。推荐系统可谓无处不在,从Google到Microsoft,从Amazon到Flipkart。它已是现代企业的重要组成部分。希望如下参考能够帮助你对推荐系统有进一步的了解。
- 推荐系统 - 维基百科
- 什么是推荐系统?- GeeksforGeeks
- 推荐系统的类型:它们的工作原理和用例 - almabetter.com
- 推荐系统和机器学习 - itransition.com
- Python 101 中的推荐系统 - kaggle.com
- 推荐系统算法:概述 - KDnuggets
译者介绍
陈峻(Julian Chen),51CTO社区编辑,具有十多年的IT项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验。
原文标题:A Deep Dive Into Recommendation Algorithms With Netflix Case Study and NVIDIA Deep Learning Technology,作者:Sagar Sidana