构建基于深度学习神经网络协同过滤模型(NCF)的视频推荐系统(Python3.10/Tensorflow2.11)

构建,基于,深度,学习,神经网络,协同,过滤,模型,ncf,视频,推荐,系统,python3,tensorflow2 · 浏览次数 : 264

小编点评

**推荐系统代码** ```python import tensorflow as tf from sklearn.preprocessing import StandardScaler import numpy as np # 准备数据 train = np.load('train.npy') test = np.load('test.npy') # 1. 定义embedding维度 embedding_dim = 64 # 2. 定义数据预处理函数 scaler = StandardScaler() def preprocess(data): return scaler.fit_transform(data['user_id'].values.reshape(-1)) # 3. 训练模型 model = tf.keras.models.Sequential() model.add(tf.keras.layers.Embedding(embedding_dim, 128, input_shape=(None, 1))) model.add(tf.keras.layers.LSTM(128)) model.add(tf.keras.layers.Dense(1, activation='sigmoid')) # 4. 训练模型 model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) model.fit(train['user_id'].values.reshape(-1), train['rating'].values, epochs=100, batch_size=64, verbose=0) # 5. 评估模型 result_df = {} for user_i in range(1, 10): user = f'User{user_i}' result_df[user] = {} for video_i in range(1, 7): video = f'Video {video_i}' pred_user_id = user_encoder.transform([user]).numpy()[0] pred_video_id = user_encoder.transform([video]).numpy()[0] pred_rating = model.predict([np.expand_dims(pred_user_id, axis=0), np.expand_dims(pred_video_id, axis=0)])[0] result_df[user][video] = pred_rating print(result_df) ``` **代码解释** 1. **数据准备**:加载训练和测试数据。 2. **数据预处理**:将用户ID和视频ID转换为数值型并标准化数据。 3. **模型构建**:定义模型架构,包括embedding层、LSTM层和输出层。 4. **训练模型**:定义训练参数和损失函数,并将模型训练。 5. **评估模型**:计算测试集的准确率,并打印预测结果。 6. **反向传播**:使用测试集的预测结果反向传播,以更新模型中的参数。

正文

毋庸讳言,和传统架构(BS开发/CS开发)相比,人工智能技术确实有一定的基础门槛,它注定不是大众化,普适化的东西。但也不能否认,人工智能技术也具备像传统架构一样“套路化”的流程,也就是说,我们大可不必自己手动构建基于神经网络的机器学习系统,直接使用深度学习框架反而更加简单,深度学习可以帮助我们自动地从原始数据中提取特征,不需要手动选择和提取特征。

之前我们手动构建了一个小型的神经网络,解决了机器学习的分类问题,本次我们利用深度学习框架Tensorflow2.11构建一套基于神经网络协同过滤模型(NCF)的视频推荐系统,解决预测问题,完成一个真正可以落地的项目。

推荐系统发展历程

“小伙子,要光盘吗?新的到货了,内容相当精彩!”

大约20年前,在北京中关村的街头,一位抱着婴儿的中年大妈兴奋地拽着笔者的胳臂,手舞足蹈地推荐着她的“产品”,大概这就是最原始的推荐系统雏形了。

事实上,时至今日,依然有类似产品使用这样的套路,不管三七二十一,弄个首页大Banner,直接怼用户脸上,且不论用户感不感兴趣,有没有用户点击和转化,这种强买强卖式的推荐,着实不怎么令人愉快。

所以推荐系统解决的痛点应该是用户的兴趣需求,给用户推荐喜欢的内容,才是推荐系统的核心。

于是乎,启发式推荐算法(Memory-based algorithms)就应运而生了。

启发式推荐算法易于实现,并且推荐结果的可解释性强。启发式推荐算法又可以分为两类:

基于用户的协同过滤(User-based collaborative filtering):主要考虑的是用户和用户之间的相似度,只要找出相似用户喜欢的物品,并预测目标用户对对应物品的评分,就可以找到评分最高的若干个物品推荐给用户。举个例子,李老师和闫老师拥有相似的电影喜好,当新电影上映后,李老师对其表示喜欢,那么就能将这部电影推荐给闫老师。

基于物品的协同过滤(Item-based collaborative filtering):主要考虑的是物品和物品之间的相似度,只有找到了目标用户对某些物品的评分,那么就可以对相似度高的类似物品进行预测,将评分最高的若干个相似物品推荐给用户。举个例子,如果用户A、B、C给书籍X,Y的评分都是5分,当用户D想要买Y书籍的时候,系统会为他推荐X书籍,因为基于用户A、B、C的评分,系统会认为喜欢Y书籍的人在很大程度上会喜欢X书籍。

启发式协同过滤算法是一种结合了基于用户的协同过滤和基于项目的协同过滤的算法,它通过启发式规则来预测用户对物品的评分。

然而,启发式协同过滤算法也存在一些缺陷:

难以处理冷启动问题:当一个用户或一个物品没有足够的评分数据时,启发式协同过滤算法无法对其进行有效的预测,因为它需要依赖于已有的评分数据。

对数据稀疏性敏感:如果数据集中存在大量的缺失值,启发式协同过滤算法的预测准确率会受到影响,因为它需要依赖于完整的评分数据来进行预测。

算法的可解释性较差:启发式协同过滤算法的预测结果是通过启发式规则得出的,这些规则可能很难被解释和理解。

受限于启发式规则的质量:启发式协同过滤算法的预测准确率受到启发式规则的质量影响,如果启发式规则得不到有效的优化和更新,算法的性能可能会受到影响。

说白了,这种基于启发式的协同过滤算法,很容易陷入一个小范围的困境,就是如果某个用户特别喜欢体育的视频,那么这种系统就会玩命地推荐体育视频,实际上这个人很有可能也喜欢艺术类的视频,但是囿于冷启动问题,无法进行推荐。

为了解决上面的问题,基于神经网络的协同过滤算法诞生了,神经网络的协同过滤算法可以通过将用户和物品的特征向量作为输入,来预测用户对新物品的评分,从而解决冷启动问题。

对数据稀疏性的鲁棒性:神经网络的协同过滤算法可以自动学习用户和物品的特征向量,并能够通过这些向量来预测评分,因此对于数据稀疏的情况也能进行有效的预测。

更好的预测准确率:神经网络的协同过滤算法可以通过多层非线性变换来学习用户和物品之间的复杂关系,从而能够提高预测准确率。

可解释性和灵活性:神经网络的协同过滤算法可以通过调整网络结构和参数来优化预测准确率,并且可以通过可视化方法来解释预测结果。

所以基于神经网络协同过滤模型是目前推荐系统的主流形态。

基于稀疏矩阵的视频完播数据

首先构造我们的数据矩阵test.csv文件:

User,Video 1,Video 2,Video 3,Video 4,Video 5,Video 6  
User1,10,3,,,,  
User2,,10,,10,5,1  
User3,,,9,,,  
User4,6,1,,8,,9  
User5,1,,1,,10,4  
User6,1,4,1,,10,1  
User7,,2,1,2,,8  
User8,,,,1,,  
User9,1,,10,,3,1

这里横轴是视频数据,纵轴是用户,对应的数据是用户对于视频的完播程度,10代表看完了,1则代表只看了百分之十,留空的代表没有看。

编写ncf.py脚本,将数据读入内存并输出:

import pandas as pd  
# set pandas to show all columns without truncation and line breaks  
pd.set_option('display.max_columns', 1000)  
pd.set_option('display.width', 1000)  
  
# data = np.loadtxt('data/test-data.csv', delimiter=',', dtype=int, skiprows=1,)  
data = pd.read_csv('data/test-data.csv')  
print(data)

程序返回:

User  Video 1  Video 2  Video 3  Video 4  Video 5  Video 6  
0  User1     10.0      3.0      NaN      NaN      NaN      NaN  
1  User2      NaN     10.0      NaN     10.0      5.0      1.0  
2  User3      NaN      NaN      9.0      NaN      NaN      NaN  
3  User4      6.0      1.0      NaN      8.0      NaN      9.0  
4  User5      1.0      NaN      1.0      NaN     10.0      4.0  
5  User6      1.0      4.0      1.0      NaN     10.0      1.0  
6  User7      NaN      2.0      1.0      2.0      NaN      8.0  
7  User8      NaN      NaN      NaN      1.0      NaN      NaN  
8  User9      1.0      NaN     10.0      NaN      3.0      1.0

一目了然。

有数据的列代表用户看过,1-10代表看了之后的完播程度,如果没看过就是NAN,现在我们的目的就是“猜”出来这些没看过的视频的完播数据是多少?从而根据完播数据完成视频推荐系统。

矩阵拆解算法

有一种推荐算法是基于矩阵拆解,通过假设的因素去“猜”稀疏矩阵的空缺数据,猜出来之后,再通过反向传播的逆运算来反推稀疏矩阵已存在的数据是否正确,从而判断“猜”出来的数据是否正确:

通俗地讲,跟算命差不多,但是基于数学原理,如果通过反推证明针对一个人的算命策略都是对的,那么就把这套流程应用到其他人身上。

但是这套逻辑过于线性,也就是因素过于单一,比如我喜欢黑色的汽车,那么就会给我推所有黑色的东西,其实可能黑色的因素仅局限于汽车,是多重因素叠加导致的,所以矩阵拆解并不是一个非常好的解决方案。

基于神经网络

使用神经网络计算,必须将数据进行向量化操作:

# reset the column.index to be numeric  
user_index = data[data.columns[0]]  
book_index = data.columns  
data = data.reset_index(drop=True)  
data[data.columns[0]] = data.index.astype('int')  
# print(data)  
# print(data)  
scaler = 10  
  
# data = pd.DataFrame(data.to_numpy(), index=range(0,len(user_index)), columns=range(0,len(book_index)))  
df_long = pd.melt(data, id_vars=[data.columns[0]],   
                  ignore_index=True,   
                  var_name='video_id',   
                  value_name='rate').dropna()  
df_long.columns = ['user_id', 'video_id', 'rating']  
df_long['rating'] = df_long['rating'] / scaler  
# replace the user_id to user by match user_index  
df_long['user_id'] = df_long['user_id'].apply(lambda x: user_index[x])  
# data = df_long.to_numpy()  
  
print(df_long)

程序返回:

user_id video_id  rating  
0    User1  Video 1     1.0  
3    User4  Video 1     0.6  
4    User5  Video 1     0.1  
5    User6  Video 1     0.1  
8    User9  Video 1     0.1  
9    User1  Video 2     0.3  
10   User2  Video 2     1.0  
12   User4  Video 2     0.1  
14   User6  Video 2     0.4  
15   User7  Video 2     0.2  
20   User3  Video 3     0.9  
22   User5  Video 3     0.1  
23   User6  Video 3     0.1  
24   User7  Video 3     0.1  
26   User9  Video 3     1.0  
28   User2  Video 4     1.0  
30   User4  Video 4     0.8  
33   User7  Video 4     0.2  
34   User8  Video 4     0.1  
37   User2  Video 5     0.5  
40   User5  Video 5     1.0  
41   User6  Video 5     1.0  
44   User9  Video 5     0.3  
46   User2  Video 6     0.1  
48   User4  Video 6     0.9  
49   User5  Video 6     0.4  
50   User6  Video 6     0.1  
51   User7  Video 6     0.8  
53   User9  Video 6     0.1

这里scaler=10作为数据范围的阈值,让计算机将完播数据散列成0-1之间的浮点数,便于神经网络进行计算。

随后安装Tensorflow框架:

pip3 install tensorflow

如果是Mac用户,请安装mac版本:

pip3 install tensorflow-macos

接着针对数据进行打标签操作:

import numpy as np  
import pandas as pd  
import tensorflow as tf  
from sklearn.model_selection import train_test_split  
from sklearn.preprocessing import LabelEncoder  
  
# dataset = pd.read_csv(url, compression='zip', usecols=['userId', 'movieId', 'rating'])  
dataset = df_long  
# Encode the user and video IDs  
user_encoder = LabelEncoder()  
video_encoder = LabelEncoder()  
dataset['user_id'] = user_encoder.fit_transform(dataset['user_id'])  
dataset['video_id'] = video_encoder.fit_transform(dataset['video_id'])  
  
# Split the dataset into train and test sets  
# train, test = train_test_split(dataset, test_size=0.2, random_state=42)  
train = dataset  
  
# Model hyperparameters  
num_users = len(dataset['user_id'].unique())  
num_countries = len(dataset['video_id'].unique())

随后定义64个维度针对向量进行处理:



embedding_dim = 64  
  
# Create the NCF model  
inputs_user = tf.keras.layers.Input(shape=(1,))  
inputs_video = tf.keras.layers.Input(shape=(1,))  
embedding_user = tf.keras.layers.Embedding(num_users, embedding_dim)(inputs_user)  
embedding_video = tf.keras.layers.Embedding(num_countries, embedding_dim)(inputs_video)  
  
# Merge the embeddings using concatenation, you can also try other merging methods like dot product or multiplication  
merged = tf.keras.layers.Concatenate()([embedding_user, embedding_video])  
merged = tf.keras.layers.Flatten()(merged)  
  
# Add fully connected layers  
dense = tf.keras.layers.Dense(64, activation='relu')(merged)  
dense = tf.keras.layers.Dense(32, activation='relu')(dense)  
output = tf.keras.layers.Dense(1, activation='sigmoid')(dense)  
  
# Compile the model  
model = tf.keras.Model(inputs=[inputs_user, inputs_video], outputs=output)  
model.compile(optimizer='adam', loss='mse', metrics=['mae'])


这里定义了一个64维度的 embedding 类用来对向量进行处理。相当于就是把属于数据当中的所有特征都设定成一个可以用一个64维向量标识的东西,然后通过降维处理之后使得机器能以一个低维的数据流形来“理解”高维的原始数据的方式来“理解”数据的“含义”,

从而实现机器学习的目的。而为了检验机器学习的成果(即机器是否有真正理解特征的含义),则使用mask(遮罩)的方式,将原始数据当中的一部分无关核心的内容“遮掉”,然后再尝试进行输入输出操作,如果输入输出操作的结果与没有遮罩的结果进行比较后足够相近,或者完全相同,则判定机器有成功学习理解到向量的含义。

这里需要注意的是,因为embedding 这个词其实是有一定程度的误用的关系,所以不要尝试用原来的语义去理解这个词,通俗地讲,可以把它理解为“特征(feature)”,即从原始数据中提取出来的一系列的特征属性,至于具体是什么特征,不重要。

这里有64个维度,那就可以认为是从输入的原始数据当中提取64个“特征”,然后用这个特征模型去套用所有的输入的原始数据,然后再将这些数据通过降维转换,最终把每一个输入的向量转换成一个1维的特殊字符串,然后让机器实现“理解复杂的输入”的目的,而那个所谓的训练过程,其实也就是不断地用遮罩mask去遮掉非核心的数据,然后对比输出结果,来看机器是否成功实现了学习的目的。

说白了,和矩阵拆解差不多,只不过矩阵拆解是线性单维度,而神经网络是非线性多维度。

最后进行训练和输出:

model.fit(  
    [train['user_id'].values, train['video_id'].values],  
    train['rating'].values,  
    batch_size=64,  
    epochs=100,  
    verbose=0,  
    # validation_split=0.1,  
)  
  
result_df = {}  
for user_i in range(1, 10):  
  user = f'User{user_i}'  
  result_df[user] = {}  
  for video_i in range(1, 7):      
    video = f'Video {video_i}'  
    pred_user_id = user_encoder.transform([user])  
    pred_video_id = video_encoder.transform([video])  
    result = model.predict(x=[pred_user_id, pred_video_id], verbose=0)  
    result_df[user][video] = result[0][0]  
result_df = pd.DataFrame(result_df).T  
result_df *= scaler  
  
print(result_df)

程序返回:

Video 1   Video 2   Video 3   Video 4   Video 5   Video 6  
User1  9.143433  3.122697  5.831852  8.930688  9.223139  9.148163  
User2  2.379406  9.317654  9.280337  9.586231  5.115635  0.710877  
User3  6.046935  8.950342  9.335093  9.546472  8.487216  5.069511  
User4  6.202362  1.341177  2.609368  7.755390  9.160558  8.974072  
User5  1.134012  1.772043  0.634183  3.741076  9.297663  3.924277  
User6  0.488006  4.060344  1.116192  4.625140  9.264144  1.199519  
User7  2.820735  0.898690  0.560579  2.215827  8.604731  7.889819  
User8  0.244587  1.062029  0.360087  1.069786  7.698551  1.286932  
User9  1.337930  8.537857  9.329366  9.123328  3.074733  0.774436

我们可以看到,机器通过神经网络的“学习”,直接“猜出来”所有用户未播放视频的完播程度。那么,我们只需要给这些用户推荐他未看的,但是机器“猜”他完播高的视频即可。

总结

我们可以看到,整个流程简单的令人发指,深度学习框架Tensorflow帮我们做了大部分的工作,我们其实只是简单的提供了基础数据而已。

首先定义一个embedding (多维空间) 用来理解需要学习的原始数据 :

一个用户对象(含一个属性userId)

一个视频对象(含三个属性:videoId, userId, rating (完播向量))

这里需要进行学习的具体就是让机器理解那个“完播向量:rating”的含义)这里定义的embedding 维度为64, 本质就是让机器把完播向量rating 的值当作成一个64维度的空间来进行理解(其实就是从这个rating值当中提取出64个特征来重新定义这个rating)

随后对embedding 进行降维处理:

具体的操作与使用的降维函数曲线有关,这里采用的是先降为32维再降为1维的两道操作方式,原来的代表rating 的embedding 空间从64维降低到了1维。而此时的输出output 对象就是机器对rating完播向量所做出来的“自己的理解”。

最后通过对学习完的输出项output 进行mask(遮罩)测试,通过变换不同的mask(遮罩)来测试结果是否与原始数据相近,或一致,从而来证实机器学习的效果,也就是上文提到的反向传播方式的逆运算。

结语

可能依然有朋友对这套系统的底层不太了解,那么,如果我们用“白话文”的形式进行解释:比如有一幅油画,油画相比完播量,肯定是多维度的,因为画里面有颜色、风格、解析度、对比度、饱和度等等特征参数,此时我们让机器先看完整的这幅画,然后用机器学习的方式让它学习(即embedding方式),接着把这幅画遮掉一部分与主题无关的部分,然后再测试机器让它用学习到的数据(即embedding完成降维处理之后的数据)去尝试复原整幅画,随后对比复原的整幅画和原始油画有多大差别,如果差别没有或者很小,则证明机器学习成功了,机器确实学会了这副画,然后就让机器按照这套逻辑去画类似的画,最后把这一“类”的画推荐给没有鉴赏过的用户,从而完成推荐系统,就这么简单。

最后,奉上视频推荐系统项目代码,与众乡亲同飨:github.com/zcxey2911/NeuralCollaborativeFiltering_NCF_Tensorflow

与构建基于深度学习神经网络协同过滤模型(NCF)的视频推荐系统(Python3.10/Tensorflow2.11)相似的内容:

构建基于深度学习神经网络协同过滤模型(NCF)的视频推荐系统(Python3.10/Tensorflow2.11)

毋庸讳言,和传统架构(BS开发/CS开发)相比,人工智能技术确实有一定的基础门槛,它注定不是大众化,普适化的东西。但也不能否认,人工智能技术也具备像传统架构一样“套路化”的流程,也就是说,我们大可不必自己手动构建基于神经网络的机器学习系统,直接使用深度学习框架反而更加简单,深度学习可以帮助我们自动地从原始数据中提取特征,不需要手动选择和提取特征。

动手造轮子自己实现人工智能神经网络(ANN),解决鸢尾花分类问题Golang1.18实现

人工智能神经网络( Artificial Neural Network,又称为ANN)是一种由人工神经元组成的网络结构,神经网络结构是所有机器学习的基本结构,换句话说,无论是深度学习还是强化学习都是基于神经网络结构进行构建。关于人工神经元,请参见:人工智能机器学习底层原理剖析,人造神经元,您一定能看

基于深度学习的鸟类声音识别系统

鸟叫声识别在鸟类保护中具有重要意义。通过适当的声音分类,研究可以自动预测该地区的生活质量。如今,深度学习模型被用于对鸟类声音数据进行高精度的分类。然而,现有的大多数鸟类声音识别模型的泛化能力较差,并且采用复杂的算法来提取鸟类声音特征。为了解决这些问题,本文构建了一个包含264种鸟类的大数据集,以增强

基于 JuiceFS 构建高校 AI 存储方案:高并发、系统稳定、运维简单

中山大学的 iSEE 实验室(Intelligence Science and System) Lab)在进行深度学习任务时,需要处理大量小文件读取。在高并发读写场景下,原先使用的 NFS 性能较低,常在高峰期导致数据节点卡死。此外,NFS 系统的单点故障问题也导致一旦数据节点宕机,该机器上的数据将

动手学Avalonia:基于硅基流动构建一个文生图应用(一)

文生图 文生图,全称“文字生成图像”(Text-to-Image),是一种AI技术,能够根据给定的文本描述生成相应的图像。这种技术利用深度学习模型,如生成对抗网络(GANs)或变换器(Transformers),来理解和解析文本中的语义信息,并将其转化为视觉表现。文生图可以用于创意设计、图像编辑、虚

深度学习框架火焰图pprof和CUDA Nsys配置指南

注:如下是在做深度学习框架开发时,用到的火焰图pprof和 CUDA Nsys 配置指南,可能对大家有一些帮助,就此分享。一些是基于飞桨的Docker镜像配置的。 一、环境 & 工具配置 0. 开发机配置 # 1.构建镜像, 记得映射端口,可以多映射几个;记得挂载ssd目录,因为数据都在ssd盘上

入侵检测系统综述文献研读

什么是入侵检测系统? 入侵检测就是从大量行为中找出异常部分,如果将其转化为深度学习知识,就是构建一个二分类器来识别异常和正常两种类别,但是因为网络入侵检测还需要相应的类别,因此二分类器不可以满足,所以要扩展到多分类器。 入侵检测系统的分类 现在有关入侵检测系统主要研究基于网络的入侵检测或基于异常的入

对DenseTensor进行Transpose

`ML.NET` 是微软推出的为. NET 平台设计的深度学习库,通过这个东西(`ModelBuilder`)可以自己构建模型,并用于后来的推理与数据处理。虽然设计是很好的,但是由于现在的 AI 发展基本上都以 `python` 实现作为基础,未来这个东西的发展不好说,特别是模型构建部分。我个人认为

探索Semantic Kernel内置插件:深入了解ConversationSummaryPlugin的应用

前言 经过前几章的学习我们已经熟悉了Semantic Kernel 插件的概念,以及基于Prompts构造的Semantic Plugins和基于本地方法构建的Native Plugins。本章我们来讲解一下在Semantic Kernel 中内置的一些插件,让我们避免重复造轮子。 内置插件 Sem

Cursor是什么?基于ChatGPT代码编辑器的cursor如何使用?VS Code如何迁移到Cursor的步骤

Cursor 是一个基于 Visual Studio Code(VS Code)技术构建的高级代码编辑器,专为提高编程效率并更深度地整合 AI 功能而设计。它不仅继承了 VS Code 的强大功能和用户界面,还增加了专门针对 AI 支持的特色功能。Cursor 是 VS Code 的一个分支,这意味...