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

本文涉及的产品
模型训练 PAI-DLC,100CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
简介: 毋庸讳言,和传统架构(BS开发/CS开发)相比,人工智能技术确实有一定的基础门槛,它注定不是大众化,普适化的东西。但也不能否认,人工智能技术也具备像传统架构一样“套路化”的流程,也就是说,我们大可不必自己手动构建基于神经网络的机器学习系统,直接使用深度学习框架反而更加简单,深度学习可以帮助我们自动地从原始数据中提取特征,不需要手动选择和提取特征。

毋庸讳言,和传统架构(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

相关文章
|
11天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
眼疾识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了4种常见的眼疾图像数据集(白内障、糖尿病性视网膜病变、青光眼和正常眼睛) 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Django框架搭建了一个Web网页平台可视化操作界面,实现用户上传一张眼疾图片识别其名称。
44 4
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
|
1月前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
281 55
|
2天前
|
机器学习/深度学习 监控 算法
基于yolov4深度学习网络的排队人数统计系统matlab仿真,带GUI界面
本项目基于YOLOv4深度学习网络,利用MATLAB 2022a实现排队人数统计的算法仿真。通过先进的计算机视觉技术,系统能自动、准确地检测和统计监控画面中的人数,适用于银行、车站等场景,优化资源分配和服务管理。核心程序包含多个回调函数,用于处理用户输入及界面交互,确保系统的高效运行。仿真结果无水印,操作步骤详见配套视频。
34 18
|
30天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于yolov4深度学习网络的公共场所人流密度检测系统matlab仿真,带GUI界面
本项目使用 MATLAB 2022a 进行 YOLOv4 算法仿真,实现公共场所人流密度检测。通过卷积神经网络提取图像特征,将图像划分为多个网格进行目标检测和识别,最终计算人流密度。核心程序包括图像和视频读取、处理和显示功能。仿真结果展示了算法的有效性和准确性。
65 31
|
25天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
94 1
|
30天前
|
监控 安全 BI
什么是零信任模型?如何实施以保证网络安全?
随着数字化转型,网络边界不断变化,组织需采用新的安全方法。零信任基于“永不信任,永远验证”原则,强调无论内外部,任何用户、设备或网络都不可信任。该模型包括微分段、多因素身份验证、单点登录、最小特权原则、持续监控和审核用户活动、监控设备等核心准则,以实现强大的网络安全态势。
127 2
|
1月前
|
机器学习/深度学习 算法 信息无障碍
基于GoogleNet深度学习网络的手语识别算法matlab仿真
本项目展示了基于GoogleNet的深度学习手语识别算法,使用Matlab2022a实现。通过卷积神经网络(CNN)识别手语手势,如"How are you"、"I am fine"、"I love you"等。核心在于Inception模块,通过多尺度处理和1x1卷积减少计算量,提高效率。项目附带完整代码及操作视频。
|
1月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于深度学习网络的宝石类型识别算法matlab仿真
本项目利用GoogLeNet深度学习网络进行宝石类型识别,实验包括收集多类宝石图像数据集并按7:1:2比例划分。使用Matlab2022a实现算法,提供含中文注释的完整代码及操作视频。GoogLeNet通过其独特的Inception模块,结合数据增强、学习率调整和正则化等优化手段,有效提升了宝石识别的准确性和效率。
|
7月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch代码实现神经网络
这段代码示例展示了如何在PyTorch中构建一个基础的卷积神经网络(CNN)。该网络包括两个卷积层,分别用于提取图像特征,每个卷积层后跟一个池化层以降低空间维度;之后是三个全连接层,用于分类输出。此结构适用于图像识别任务,并可根据具体应用调整参数与层数。

热门文章

最新文章