深度学习电影推荐-CNN算法

在这里插入图片描述

文章目录

  • 前言
  • 视频演示效果
  • 1.数据集
    • 环境配置安装教程与资源说明
    • 1.1 ML-1M 数据集概述
      • 1.1.1数据集内容
      • 1.1.2. 数据集规模
      • 1.1.3. 数据特点
      • 1.1.4. 文件格式
      • 1.1.5. 应用场景
  • 2.模型架构
  • 3.推荐实现
    • 3.1 用户数据
    • 3.2 电影数据
    • 3.3 评分数据
    • 3.4 数据预处理
    • 3.5实现数据预处理
    • 3.6 加载数据并保存到本地
    • 3.7从本地读取数据
  • 4 模型设计
    • 4.1 概述
    • 4.2 文本卷积网络
      • 辅助函数
      • 构建神经网络
        • 定义User的嵌入矩阵
        • 将User的嵌入矩阵一起全连接生成User的特征
        • 定义Movie ID的嵌入矩阵
        • 对电影类型的多个嵌入向量做加和
        • Movie Title的文本卷积网络实现
        • 将Movie的各个层一起做全连接
    • 生成Movie特征矩阵
    • 生成User特征矩阵
    • 开始推荐电影
  • 结论


前言

  
随着互联网和流媒体平台的快速发展,用户可以随时访问海量的电影资源。然而,如何帮助用户在繁杂的选择中快速找到符合其兴趣的电影,成为了一个重要且具有挑战性的问题。推荐系统作为解决信息过载的重要工具,在电影行业得到了广泛应用。近年来,深度学习技术的崛起为推荐系统的构建提供了新的方法和更高的精度,其强大的特征提取能力和非线性建模能力使电影推荐系统更加智能化和个性化。

MovieLens 1M(简称 ML-1M)是电影推荐领域最常用的公开数据集之一,包含约6000名用户对3900多部电影的100万条评分记录。该数据集提供了用户的基本信息(如年龄、性别、职业等)、电影的元数据(如标题、类型、年份等)以及用户对电影的评分。这些信息为电影推荐系统的研究提供了丰富的实验数据。基于 ML-1M 数据集,研究者可以开发和验证各种推荐算法,同时通过标准化的数据便于不同方法的横向比较。

传统的推荐方法,如基于协同过滤和矩阵分解的技术,在处理稀疏数据和冷启动问题时表现有限。而深度学习方法以其在高维数据中的强大建模能力,能够挖掘用户和电影之间的复杂非线性关系,并捕捉多模态数据的深层特征。例如,通过神经网络构建用户和电影的嵌入向量,深度学习方法可以对用户行为和电影内容进行联合建模;通过融合用户的评分历史和电影的文本信息、图像特征等多源数据,可以显著提升推荐结果的精准度和多样性。

本研究以 ML-1M 数据集为基础,探索深度学习技术在电影推荐中的应用。研究目标包括:构建高效的深度学习模型,挖掘用户行为模式;融合电影的多模态信息,提升推荐系统的准确性;以及优化推荐策略,为用户提供个性化的观影建议。本研究不仅具有理论意义,也为实际推荐系统的开发提供了宝贵的参考。


视频演示效果

深度学习实战电影推荐系统


觉得不错的小伙伴,感谢点赞、关注加收藏哦!更多干货内容持续更新…


1.数据集

环境配置安装教程与资源说明

在这里插入图片描述

离线安装配置文件说明

1.1 ML-1M 数据集概述

MovieLens 1M(简称 ML-1M)数据集是由明尼苏达大学的 GroupLens 研究团队发布的一个电影推荐系统研究数据集,是推荐算法开发和评估领域的经典数据集之一。该数据集包含 100 万条电影评分记录,为研究电影推荐系统提供了标准化和高质量的数据资源。以下是 ML-1M 数据集的详细概述:

1.1.1数据集内容

ML-1M 数据集包括以下几部分信息:

  • 用户数据
    • 用户唯一 ID。
    • 性别(Male 或 Female)。
    • 年龄段(如 18-24、25-34 等)。
    • 职业编号(对应具体职业类别)。
  • 电影数据
    • 电影唯一 ID。
    • 电影标题及其上映年份。
    • 电影的分类标签(如动作、喜剧、科幻等)。
  • 评分数据
    • 用户对电影的评分,范围为 1 到 5 的整数。
    • 评分的时间戳,用于分析评分的时间分布和用户行为模式。

1.1.2. 数据集规模

  • 用户数量:6,040 名用户。
  • 电影数量:3,900 多部电影。
  • 评分数量:1,000,209 条评分。

1.1.3. 数据特点

  • 稀疏性:尽管数据集包含大量评分记录,但与可能的评分总量相比(即用户数 × 电影数),实际评分所占比例较小,表现出典型的稀疏性问题。
  • 时间维度:评分记录带有时间戳信息,可以分析用户行为的时间动态。
  • 多样性:用户和电影的元数据涵盖了性别、年龄、职业、类型等多个维度,为推荐算法提供了丰富的上下文信息。

1.1.4. 文件格式

ML-1M 数据集通常以分隔符文本文件(如 CSV 或 TXT)形式存储,包括以下文件:

  • users.dat:包含用户的基本信息。
  • movies.dat:包含电影的基本信息。
  • ratings.dat:包含用户的评分记录。

1.1.5. 应用场景

ML-1M 数据集广泛应用于以下研究方向:

  • 推荐系统算法开发:用于测试协同过滤、矩阵分解、深度学习等推荐算法的性能。
  • 用户行为建模:分析用户的观影习惯、兴趣动态和评分模式。
  • 冷启动问题研究:通过新用户或新电影的推荐,解决数据稀疏性问题。
  • 多模态融合:结合文本、图像、时间序列等信息,优化推荐效果。

ML-1M 数据集因其数据结构清晰和实验价值高,成为推荐系统研究的重要基准,许多先进的算法和模型均在该数据集上进行了验证。

2.模型架构

在这里插入图片描述

在这里插入图片描述

3.推荐实现

本项目使用的是MovieLens 1M 数据集,包含6000个用户在近4000部电影上的1亿条评论。

数据集分为三个文件:用户数据users.dat,电影数据movies.dat和评分数据ratings.dat。

3.1 用户数据

分别有用户ID、性别、年龄、职业ID和邮编等字段。

数据中的格式:UserID::Gender::Age::Occupation::Zip-code

  • Gender is denoted by a “M” for male and “F” for female

  • Age is chosen from the following ranges:

    • 1: “Under 18”
    • 18: “18-24”
    • 25: “25-34”
    • 35: “35-44”
    • 45: “45-49”
    • 50: “50-55”
    • 56: “56+”
  • Occupation is chosen from the following choices:

    • 0: “other” or not specified
    • 1: “academic/educator”
    • 2: “artist”
    • 3: “clerical/admin”
    • 4: “college/grad student”
    • 5: “customer service”
    • 6: “doctor/health care”
    • 7: “executive/managerial”
    • 8: “farmer”
    • 9: “homemaker”
    • 10: “K-12 student”
    • 11: “lawyer”
    • 12: “programmer”
    • 13: “retired”
    • 14: “sales/marketing”
    • 15: “scientist”
    • 16: “self-employed”
    • 17: “technician/engineer”
    • 18: “tradesman/craftsman”
    • 19: “unemployed”
    • 20: “writer”

users_title = [‘UserID’, ‘Gender’, ‘Age’, ‘OccupationID’, ‘Zip-code’]
users = pd.read_table(‘./ml-1m/users.dat’, sep=‘::’, header=None, names=users_title, engine = ‘python’)
users.head()
可以看出UserID、Gender、Age和Occupation都是类别字段,其中邮编字段是我们不使用的。

3.2 电影数据

分别有电影ID、电影名和电影风格等字段。

数据中的格式:MovieID::Title::Genres

  • Titles are identical to titles provided by the IMDB (including
    year of release)

  • Genres are pipe-separated and are selected from the following genres:

    • Action
    • Adventure
    • Animation
    • Children’s
    • Comedy
    • Crime
    • Documentary
    • Drama
    • Fantasy
    • Film-Noir
    • Horror
    • Musical
    • Mystery
    • Romance
    • Sci-Fi
    • Thriller
    • War
    • Western

movies_title = [‘MovieID’, ‘Title’, ‘Genres’]
movies = pd.read_table(‘./ml-1m/movies.dat’, sep=‘::’, header=None, names=movies_title, engine = ‘python’)
movies.head()
MovieID是类别字段,Title是文本,Genres也是类别字段

3.3 评分数据

分别有用户ID、电影ID、评分和时间戳等字段。

数据中的格式:UserID::MovieID::Rating::Timestamp

  • UserIDs range between 1 and 6040
  • MovieIDs range between 1 and 3952
  • Ratings are made on a 5-star scale (whole-star ratings only)
  • Timestamp is represented in seconds since the epoch as returned by time(2)
  • Each user has at least 20 ratings
    ratings_title = [‘UserID’,‘MovieID’, ‘Rating’, ‘timestamps’]
    ratings = pd.read_table(‘./ml-1m/ratings.dat’, sep=‘::’, header=None, names=ratings_title, engine = ‘python’)
    ratings.head()
    评分字段Rating就是我们要学习的targets,时间戳字段我们不使用。

3.4 数据预处理

  • UserID、Occupation和MovieID不用变。
  • Gender字段:需要将‘F’和‘M’转换成0和1。
  • Age字段:要转成7个连续数字0~6。
  • Genres字段:是分类字段,要转成数字。首先将Genres中的类别转成字符串到数字的字典,然后再将每个电影的Genres字段转成数字列表,因为有些电影是多个Genres的组合。
  • Title字段:处理方式跟Genres字段一样,首先创建文本到数字的字典,然后将Title中的描述转成数字的列表。另外Title中的年份也需要去掉。
  • Genres和Title字段需要将长度统一,这样在神经网络中方便处理。空白部分用‘< PAD >’对应的数字填充。

3.5实现数据预处理

def load_data():"""Load Dataset from File"""#读取User数据users_title = ['UserID', 'Gender', 'Age', 'JobID', 'Zip-code']users = pd.read_table('./ml-1m/users.dat', sep='::', header=None, names=users_title, engine = 'python')# 保留以下特征users = users.filter(regex='UserID|Gender|Age|JobID')users_orig = users.values#改变User数据中性别和年龄gender_map = {'F':0, 'M':1}users['Gender'] = users['Gender'].map(gender_map)age_map = {val:ii for ii,val in enumerate(set(users['Age']))}users['Age'] = users['Age'].map(age_map)#读取Movie数据集movies_title = ['MovieID', 'Title', 'Genres']movies = pd.read_table('./ml-1m/movies.dat', sep='::', header=None, names=movies_title, engine = 'python')movies_orig = movies.values#将Title中的年份去掉pattern = re.compile(r'^(.*)\((\d+)\)$')title_map = {val:pattern.match(val).group(1) for ii,val in enumerate(set(movies['Title']))}movies['Title'] = movies['Title'].map(title_map)#电影类型转数字字典genres_set = set()for val in movies['Genres'].str.split('|'):genres_set.update(val)genres_set.add('<PAD>')# 将类型进行编号genres2int = {val:ii for ii, val in enumerate(genres_set)}#将电影类型转成等长数字列表genres_map = {val:[genres2int[row] for row in val.split('|')] for ii,val in enumerate(set(movies['Genres']))}# 将每个样本的电影类型数字列表处理成相同长度,长度不够用<PAD>填充for key in genres_map:for cnt in range(max(genres2int.values()) - len(genres_map[key])):genres_map[key].insert(len(genres_map[key]) + cnt,genres2int['<PAD>'])movies['Genres'] = movies['Genres'].map(genres_map)#电影Title转数字字典title_set = set()for val in movies['Title'].str.split():title_set.update(val)title_set.add('<PAD>')title2int = {val:ii for ii, val in enumerate(title_set)}#将电影Title转成等长数字列表,长度是15title_count = 15title_map = {val:[title2int[row] for row in val.split()] for ii,val in enumerate(set(movies['Title']))}for key in title_map:for cnt in range(title_count - len(title_map[key])):title_map[key].insert(len(title_map[key]) + cnt,title2int['<PAD>'])movies['Title'] = movies['Title'].map(title_map)#读取评分数据集ratings_title = ['UserID','MovieID', 'ratings', 'timestamps']ratings = pd.read_table('./ml-1m/ratings.dat', sep='::', header=None, names=ratings_title, engine = 'python')ratings = ratings.filter(regex='UserID|MovieID|ratings')#合并三个表data = pd.merge(pd.merge(ratings, users), movies)#将数据分成X和y两张表target_fields = ['ratings']features_pd, targets_pd = data.drop(target_fields, axis=1), data[target_fields]features = features_pd.valuestargets_values = targets_pd.valuesreturn title_count, title_set, genres2int, features, targets_values, ratings, users, movies, data, movies_orig, users_orig

3.6 加载数据并保存到本地

  • title_count:Title字段的长度(15)
  • title_set:Title文本的集合
  • genres2int:电影类型转数字的字典
  • features:是输入X
  • targets_values:是学习目标y
  • ratings:评分数据集的Pandas对象
  • users:用户数据集的Pandas对象
  • movies:电影数据的Pandas对象
  • data:三个数据集组合在一起的Pandas对象
  • movies_orig:没有做数据处理的原始电影数据
  • users_orig:没有做数据处理的原始用户数据
title_count, title_set, genres2int, features, targets_values, \ratings, users, movies, data, movies_orig, users_orig = load_data()with open('./processed_data/preprocess.pkl', 'wb') as f:pickle.dump((title_count, title_set, genres2int, features, targets_values, ratings, users, movies, data, movies_orig, users_orig), f)

3.7从本地读取数据

with open('./processed_data/preprocess.pkl', mode='rb') as f:title_count, title_set, genres2int, features, \targets_values, ratings, users, movies, data, movies_orig, users_orig = pickle.load(f)

4 模型设计

4.1 概述

通过研究数据集中的字段类型,我们发现有一些是类别字段,通常的处理是将这些字段转成one hot编码,但是像UserID、MovieID这样的字段就会变成非常的稀疏,输入的维度急剧膨胀,

所以在预处理数据时将这些字段转成了数字,我们用这个数字当做嵌入矩阵的索引,在网络的第一层使用了嵌入层,维度是(N,32)和(N,16)。
这里的思想其实和 word2vec 比较类似。我们会对用户或者电影的每个属性都指定一个特征维度空间,这就好比我们在自然语言处理中对每个单词指定特征维度空间。从下面的代码中可以看到,我们将用到的属性的特征维度设置为了 32 或者 16.

电影类型的处理要多一步,有时一个电影有多个电影类型,这样从嵌入矩阵索引出来是一个(n,32)的矩阵,因为有多个类型嘛,我们要将这个矩阵求和,变成(1,32)的向量。

电影名的处理比较特殊,没有使用循环神经网络,而是用了文本卷积网络,下文会进行说明。

从嵌入层索引出特征以后,将各特征传入全连接层,将输出再次传入全连接层,最终分别得到(1,200)的用户特征和电影特征两个特征向量。

我们的目的就是要训练出用户特征和电影特征,在实现推荐功能时使用。得到这两个特征以后,就可以选择任意的方式来拟合评分了。我使用了两种方式,一个是上图中画出的将两个特征做向量乘法,将结果与真实评分做回归,采用MSE优化损失。因为本质上这是一个回归问题,另一种方式是,将两个特征作为输入,再次传入全连接层,输出一个值,将输出值回归到真实评分,采用MSE优化损失。

实际上第二个方式的MSE loss在0.8附近,第一个方式在1附近,5次迭代的结果。

4.2 文本卷积网络

将卷积神经网络用于文本,网络的第一层是词嵌入层,由每一个单词的嵌入向量组成的嵌入矩阵。下一层使用多个不同尺寸(窗口大小)的卷积核在嵌入矩阵上做卷积,窗口大小指的是每次卷积覆盖几个单词。这里跟对图像做卷积不太一样,图像的卷积通常用2x2、3x3、5x5之类的尺寸,而文本卷积要覆盖整个单词的嵌入向量,所以尺寸是(单词数,向量维度),比如每次滑动3个,4个或者5个单词。第三层网络是max pooling得到一个长向量,最后使用dropout做正则化,最终得到了电影Title的特征。

辅助函数

import tensorflow as tf
import os
import pickledef save_params(params):"""Save parameters to file"""with open('params.p', 'wb') as f:pickle.dump(params, f)def load_params():"""Load parameters from file"""with open('params.p', mode='rb') as f:return pickle.load(f)

构建神经网络

定义User的嵌入矩阵
def get_user_embedding(uid, user_gender, user_age, user_job):with tf.name_scope("user_embedding"):# 下面的操作和情感分析项目中的单词转换为词向量的操作本质上是一样的# 用户的特征维度设置为 32# 先初始化一个非常大的用户矩阵# tf.random_uniform 的第二个参数是初始化的最小值,这里是-1,第三个参数是初始化的最大值,这里是1uid_embed_matrix = tf.Variable(tf.random_uniform([uid_max, embed_dim], -1, 1), name = "uid_embed_matrix")# 根据指定用户ID找到他对应的嵌入层uid_embed_layer = tf.nn.embedding_lookup(uid_embed_matrix, uid, name = "uid_embed_layer")# 性别的特征维度设置为 16
将User的嵌入矩阵一起全连接生成User的特征
def get_user_feature_layer(uid_embed_layer, gender_embed_layer, age_embed_layer, job_embed_layer):with tf.name_scope("user_fc"):#第一层全连接# tf.layers.dense 的第一个参数是输入,第二个参数是层的单元的数量uid_fc_layer = tf.layers.dense(uid_embed_layer, embed_dim, name = "uid_fc_layer", activation=tf.nn.relu)gender_fc_layer = tf.layers.dense(gender_embed_layer, embed_dim, name = "gender_fc_layer", activation=tf.nn.relu)age_fc_layer = tf.layers.dense(age_embed_layer, embed_dim, name ="age_fc_layer", activation=tf.nn.relu)job_fc_layer = tf.layers.dense(job_embed_layer, embed_dim, name = "job_fc_layer", activation=tf.nn.relu)#第二层全连接# 将上面的每个分段组成一个完整的全连接层user_combine_layer = tf.concat([uid_fc_layer, gender_fc_layer, age_fc_layer, job_fc_layer], 2)  #(?, 1, 128)# 验证上面产生的 tensorflow 是否是 128 维度的print(user_combine_layer.shape)# tf.contrib.layers.fully_connected 的第一个参数是输入,第二个参数是输出# 这里的输入是user_combine_layer,输出是200,是指每个用户有200个特征# 相当于是一个200个分类的问题,每个分类的可能性都会输出,在这里指的就是每个特征的可能性user_combine_layer = tf.contrib.layers.fully_connected(user_combine_layer, 200, tf.tanh)  #(?, 1, 200)user_combine_layer_flat = tf.reshape(user_combine_layer, [-1, 200])return user_combine_layer, user_combine_layer_flat
定义Movie ID的嵌入矩阵
def get_movie_id_embed_layer(movie_id):with tf.name_scope("movie_embedding"):movie_id_embed_matrix = tf.Variable(tf.random_uniform([movie_id_max, embed_dim], -1, 1), name = "movie_id_embed_matrix")movie_id_embed_layer = tf.nn.embedding_lookup(movie_id_embed_matrix, movie_id, name = "movie_id_embed_layer")return movie_id_embed_layer
对电影类型的多个嵌入向量做加和
def get_movie_categories_layers(movie_categories):with tf.name_scope("movie_categories_layers"):movie_categories_embed_matrix = tf.Variable(tf.random_uniform([movie_categories_max, embed_dim], -1, 1), name = "movie_categories_embed_matrix")movie_categories_embed_layer = tf.nn.embedding_lookup(movie_categories_embed_matrix, movie_categories, name = "movie_categories_embed_layer")if combiner == "sum":movie_categories_embed_layer = tf.reduce_sum(movie_categories_embed_layer, axis=1, keep_dims=True)#     elif combiner == "mean":return movie_categories_embed_layer
Movie Title的文本卷积网络实现
def get_movie_cnn_layer(movie_titles):#从嵌入矩阵中得到电影名对应的各个单词的嵌入向量with tf.name_scope("movie_embedding"):movie_title_embed_matrix = tf.Variable(tf.random_uniform([movie_title_max, embed_dim], -1, 1), name = "movie_title_embed_matrix")movie_title_embed_layer = tf.nn.embedding_lookup(movie_title_embed_matrix, movie_titles, name = "movie_title_embed_layer")# 为 movie_title_embed_layer 增加一个维度# 在这里是添加到最后一个维度,最后一个维度是channel# 所以这里的channel数量是1个# 所以这里的处理方式和图片是一样的movie_title_embed_layer_expand = tf.expand_dims(movie_title_embed_layer, -1)#对文本嵌入层使用不同尺寸的卷积核做卷积和最大池化pool_layer_lst = []for window_size in window_sizes:with tf.name_scope("movie_txt_conv_maxpool_{}".format(window_size)):# [window_size, embed_dim, 1, filter_num] 表示输入的 channel 的个数是1,输出的 channel 的个数是 filter_numfilter_weights = tf.Variable(tf.truncated_normal([window_size, embed_dim, 1, filter_num],stddev=0.1),name = "filter_weights")filter_bias = tf.Variable(tf.constant(0.1, shape=[filter_num]), name="filter_bias")# conv2d 是指用到的卷积核的大小是 [filter_height * filter_width * in_channels, output_channels]# 在这里卷积核会向两个维度的方向进行滑动# conv1d 是将卷积核向一个维度的方向进行滑动,这就是 conv1d 和 conv2d 的区别# strides 设置要求第一个和最后一个数字是1,四个数字的顺序要求默认是 NHWC,也就是 [batch, height, width, channels]# padding 设置为 VALID 其实就是不 PAD,设置为 SAME 就是让输入和输出的维度是一样的conv_layer = tf.nn.conv2d(movie_title_embed_layer_expand, filter_weights, [1,1,1,1], padding="VALID", name="conv_layer")# tf.nn.bias_add 将偏差 filter_bias 加到 conv_layer 上# tf.nn.relu 将激活函数设置为 relurelu_layer = tf.nn.relu(tf.nn.bias_add(conv_layer,filter_bias), name ="relu_layer")# tf.nn.max_pool 的第一个参数是输入# 第二个参数是 max_pool 窗口的大小,每个数值表示对每个维度的窗口设置# 第三个参数是 strides,和 conv2d 的设置是一样的# 这边的池化是将上面每个卷积核的卷积结果转换为一个元素# 由于这里的卷积核的数量是 8 个,所以下面生成的是一个具有 8 个元素的向量maxpool_layer = tf.nn.max_pool(relu_layer, [1,sentences_size - window_size + 1 ,1,1], [1,1,1,1], padding="VALID", name="maxpool_layer")pool_layer_lst.append(maxpool_layer)#Dropout层with tf.name_scope("pool_dropout"):# 这里最终的结果是这样的,# 假设卷积核的窗口是 2,卷积核的数量是 8# 那么通过上面的池化操作之后,生成的池化的结果是一个具有 8 个元素的向量# 每种窗口大小的卷积核经过池化后都会生成这样一个具有 8 个元素的向量# 所以最终生成的是一个 8 维的二维矩阵,它的另一个维度就是不同的窗口的数量# 在这里就是 2,3,4,5,那么最终就是一个 8*4 的矩阵,pool_layer = tf.concat(pool_layer_lst, 3, name ="pool_layer")max_num = len(window_sizes) * filter_num# 将这个 8*4 的二维矩阵平铺成一个具有 32 个元素的一维矩阵pool_layer_flat = tf.reshape(pool_layer , [-1, 1, max_num], name = "pool_layer_flat")dropout_layer = tf.nn.dropout(pool_layer_flat, dropout_keep_prob, name = "dropout_layer")return pool_layer_flat, dropout_layer
将Movie的各个层一起做全连接
def get_movie_feature_layer(movie_id_embed_layer, movie_categories_embed_layer, dropout_layer):with tf.name_scope("movie_fc"):#第一层全连接movie_id_fc_layer = tf.layers.dense(movie_id_embed_layer, embed_dim, name = "movie_id_fc_layer", activation=tf.nn.relu)movie_categories_fc_layer = tf.layers.dense(movie_categories_embed_layer, embed_dim, name = "movie_categories_fc_layer", activation=tf.nn.relu)#第二层全连接movie_combine_layer = tf.concat([movie_id_fc_layer, movie_categories_fc_layer, dropout_layer], 2)  #(?, 1, 96)movie_combine_layer = tf.contrib.layers.fully_connected(movie_combine_layer, 200, tf.tanh)  #(?, 1, 200)movie_combine_layer_flat = tf.reshape(movie_combine_layer, [-1, 200])return movie_combine_layer, movie_combine_layer_flat

生成Movie特征矩阵

loaded_graph = tf.Graph()  #
movie_matrics = []
with tf.Session(graph=loaded_graph) as sess:  ## Load saved modelloader = tf.train.import_meta_graph(load_dir + '.meta')loader.restore(sess, load_dir)# Get Tensors from loaded modeluid, user_gender, user_age, user_job, movie_id, movie_categories, movie_titles, targets, lr, dropout_keep_prob, _, movie_combine_layer_flat, __ = get_tensors(loaded_graph)  #loaded_graphfor item in movies.values:categories = np.zeros([1, 18])categories[0] = item.take(2)titles = np.zeros([1, sentences_size])titles[0] = item.take(1)feed = {movie_id: np.reshape(item.take(0), [1, 1]),movie_categories: categories,  #x.take(6,1)movie_titles: titles,  #x.take(5,1)dropout_keep_prob: 1}movie_combine_layer_flat_val = sess.run([movie_combine_layer_flat], feed)  movie_matrics.append(movie_combine_layer_flat_val)pickle.dump((np.array(movie_matrics).reshape(-1, 200)), open('movie_matrics.p', 'wb'))
movie_matrics = pickle.load(open('movie_matrics.p', mode='rb'))

生成User特征矩阵

将训练好的用户特征组合成用户特征矩阵并保存到本地
loaded_graph = tf.Graph()  #
users_matrics = []
with tf.Session(graph=loaded_graph) as sess:  ## Load saved modelloader = tf.train.import_meta_graph(load_dir + '.meta')loader.restore(sess, load_dir)# Get Tensors from loaded modeluid, user_gender, user_age, user_job, movie_id, movie_categories, movie_titles, targets, lr, dropout_keep_prob, _, __,user_combine_layer_flat = get_tensors(loaded_graph)  #loaded_graphfor item in users.values:feed = {uid: np.reshape(item.take(0), [1, 1]),user_gender: np.reshape(item.take(1), [1, 1]),user_age: np.reshape(item.take(2), [1, 1]),user_job: np.reshape(item.take(3), [1, 1]),dropout_keep_prob: 1}user_combine_layer_flat_val = sess.run([user_combine_layer_flat], feed)  users_matrics.append(user_combine_layer_flat_val)pickle.dump((np.array(users_matrics).reshape(-1, 200)), open('users_matrics.p', 'wb'))
users_matrics = pickle.load(open('users_matrics.p', mode='rb'))

开始推荐电影

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论

以上就是实现的常用的推荐功能,将网络模型作为回归问题进行训练,得到训练好的用户特征矩阵和电影特征矩阵进行推荐。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2603.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代理模式实现

一、概念&#xff1a;代理模式属于结构型设计模式。客户端不能直接访问一个对象&#xff0c;可以通过代理的第三者来间接访问该对象&#xff0c;代理对象控制着对于原对象的访问&#xff0c;并允许在客户端访问对象的前后进行一些扩展和处理&#xff1b;这种设置模式称为代理模…

2024年11月架构设计师综合知识真题回顾,附参考答案、解析及所涉知识点(一)

软考高级系统架构设计师考试包含三个科目&#xff1a;信息系统综合知识、系统架构设计案例分析和系统架构设计论文。考试形式为机考。本文主要回顾2024年下半年(2024-11-10)系统架构设计师考试上午综合知识科目的选择题&#xff0c;同时附带参考答案、解析和所涉知识点。 由于机…

【Kafka】Linux+KRaft集群部署指南

【Kafka】LinuxKRaft集群部署指南 摘要本地环境说明官网准备工作快速开始修改config/kraft/server.properties初始化数据存储目录 新节点加入集群启动停止测试创建topic创建生产者创建消费者 摘要 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在…

【GIS操作】使用ArcGIS Pro进行海图的地理配准(附:墨卡托投影对比解析)

文章目录 一、应用场景二、墨卡托投影1、知识点2、Arcgis中的坐标系选择 三、操作步骤1、数据转换2、数据加载3、栅格投影4、地理配准 一、应用场景 地理配准是数字化之前必须进行的一项工作。扫描得到的地图数据通常不包含空间参考信息&#xff0c;需要通过具有较高位置精度的…

计算机网络 (45)动态主机配置协议DHCP

前言 计算机网络中的动态主机配置协议&#xff08;DHCP&#xff0c;Dynamic Host Configuration Protocol&#xff09;是一种网络管理协议&#xff0c;主要用于自动分配IP地址和其他网络配置参数给连接到网络的设备。 一、基本概念 定义&#xff1a;DHCP是一种网络协议&#xf…

自动驾驶3D目标检测综述(八)

在介绍完前九章的内容后&#xff0c;咱们已经基本完成了综述主题内容的解读。剩下只有第十章分析和展望以及第十一章总结的部分。本篇为自动驾驶3D目标检测综述的第八篇也将是最后一篇。 目录 1、研究趋势 1.1 数据选择的趋势 1.2 推理时间的趋势 1.3 基于激光雷达方法的趋…

Web3 时代,区块链与物联网的融合创新前景

随着Web3时代的到来&#xff0c;区块链技术和物联网&#xff08;IoT&#xff09;的融合成为科技领域的一个热点话题。Web3以去中心化为核心理念&#xff0c;而区块链正是这一理念的技术支撑。物联网则通过智能设备和传感器将现实世界的数据数字化&#xff0c;连接成一个庞大的网…

【JavaEE进阶】SpringMVC 响应

目录 &#x1f38d;前言 &#x1f333; 返回静态页面 &#x1f332;RestController 与 Controller 的关联和区别 &#x1f334;返回数据 ResponseBody &#x1f38b;返回HTML代码片段 &#x1f343;返回JSON &#x1f340;设置状态码 &#x1f384;设置Header &#x…

RV1126+FFMPEG推流项目(7)AI音频模块编码流程

一、AI 模块和外设麦克风的关系 AI 模块是 RV1126 芯片的一个重要组成部分。它的主要功能是将外部接入的麦克风采集到的模拟信号通过内置的驱动程序转换为数字信号。这意味着麦克风作为外设&#xff0c;提供音频输入信号&#xff0c;AI 模块通过其硬件和软件的结合&#xff0c…

4.Proto 3 语法详解

目录 proto 3 语法详解字段规则消息类型的定义与使用创建通讯录2.0版本enum类型升级通讯录至2.1版本Any类型升级通讯录至2.2版本oneof类型升级通讯录至2.3版本map类型升级通讯录至2.4版本默认值更新消息保留字段reserved创建通讯录3.0版本未知字段升级通讯录3.1版本前后兼容性选…

告别 Excel,拥抱 R 语言:开启数据分析新时代

在这个数据驱动的时代&#xff0c;数据分析已然成为每个行业的核心竞争力。从市场营销到金融领域&#xff0c;从医疗健康到教育行业&#xff0c;数据无处不在&#xff0c;深刻影响着每一个决策。然而&#xff0c;面对日益复杂的数据集&#xff0c;单纯依靠 Excel 进行分析&…

SDK调用文心一言如何接入,文心一言API接入教程

一、前期准备 注册百度智能云账号&#xff1a; 前往百度智能云官网注册一个账号。这是接入文心一言API的基础。 了解API接口&#xff1a; 在百度智能云开放平台中&#xff0c;找到文心一言API的详情页&#xff0c;了解提供的API接口类型&#xff08;如云端API、移动端API、离线…

linux之进程信号(初识信号,信号的产生)

目录 引入一、初识信号(信号预备知识)1.生活中的信号2.Linux中的信号3.信号进程得出的初步结论 二、信号的产生1.通过终端输入产生信号拓展: 硬件中断2.调用系统函数向进程发信号3.硬件异常产生信号4.软件条件产生信号拓展: 核心转储技术总结一下&#xff1a; 引入 一、初识信…

​​​​​​​​​​​​​​★3.3 事件处理

★3.3.1 ※MouseArea Item <-- MouseArea 属性 acceptedButtons : Qt::MouseButtons containsMouse : bool 【书】只读属性。表明当前鼠标光标是否在MouseArea上&#xff0c;默认只有鼠标的一个按钮处于按下状态时才可以被检测到。 containsPress : bool curs…

从前端视角看设计模式之创建型模式篇

设计模式简介 "设计模式"源于GOF&#xff08;四人帮&#xff09;合著出版的《设计模式&#xff1a;可复用的面向对象软件元素》&#xff0c;该书第一次完整科普了软件开发中设计模式的概念&#xff0c;他们提出的设计模式主要是基于以下的面向对象设计原则&#xff…

DAMA CDGA 备考笔记(二)

1. 考点分布 2. 第二章 数据处理伦理知识点总结 伦理是建立在是非观念上的行为准则。伦理准则通常侧重于公平、尊重、责任、诚信、质量、可靠性、透明度和信任等方面。数据伦理是一项社会责任问题不是法律问题。 度量指标&#xff1a;培训员工人数、合规/不合规事件、企业高管…

ros2笔记-6.2 使用urdf创建机器人模型

本节主要跟着小鱼老师的视频操作&#xff0c;不同的仿真平台有不同的建模语言&#xff0c;但是几乎都支持URDF。 本节使用URDF创建一个机器人模型。 6.2.1 帮机器人创建一个身体 URDF使用XML来描述机器人的结构和传感器、执行器等信息。 在chapt6/chap6_ws/src创建功能包:r…

MLX90640自制热像仪(四) LVGL UI界面设计 移植 SquareLine Studio

SquareLine Studio 1.5.0是一款LVGL图形化的软件&#xff0c;LVGL官方的软件&#xff0c;针对这个软件我们主要做的除了开发&#xff0c;就是移植到自己的板端&#xff0c;过程中会遇到各种各样的问题。 下面附上源代码&#xff1a; // This file was generated by SquareLine…

hadoop3.3和hive4.0安装——单节点

hadoop3.3x和hive4.0安装部署 为什么我要安装hive4.0&#xff0c;因为阿里云镜像只有hive4.0 软件相互兼容性版本 系统centos7 uname -a如果内核3.0以上可以用 安装jdk1.8以上的版本&#xff08;配置好环境变量&#xff09; hadoop3.3.x与hive4.0.x 创建目录 mkdir -p /us…

09.VSCODE:安装 Git for Windows

在 Windows 下安装著名的源代码管理工具&#xff1a;git。 git 工具两大作用&#xff1a; 管理我们自己的源代码获取他人&#xff08;开源的&#xff09;源代码 当前我们更需要第2点。 为什么要安装 git 一、 得到更多库 之前课程中我们安装了 msys2&#xff0c;从而可以通…