• 基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(四)



    在这里插入图片描述

    前言

    本项目专注于MovieLens数据集,并采用TensorFlow中的2D文本卷积网络模型。它结合了协同过滤算法来计算电影之间的余弦相似度,并通过用户的交互方式,以单击电影的方式,提供两种不同的电影推荐方式。

    首先,项目使用MovieLens数据集,这个数据集包含了大量用户对电影的评分和评论。这些数据用于训练协同过滤算法,以便推荐与用户喜好相似的电影。

    其次,项目使用TensorFlow中的2D文本卷积网络模型,这个模型可以处理电影的文本描述信息。模型通过学习电影的文本特征,能够更好地理解电影的内容和风格。

    当用户与小程序进行交互时,有两种不同的电影推荐方式:

    1. 协同过滤推荐:基于用户的历史评分和协同过滤算法,系统会推荐与用户喜好相似的电影。这是一种传统的推荐方式,通过分析用户和其他用户的行为来推荐电影。

    2. 文本卷积网络推荐:用户可以通过点击电影或输入文本描述,以启动文本卷积网络模型。模型会分析电影的文本信息,并推荐与输入的电影或描述相匹配的其他电影。这种方式更注重电影的内容和情节相似性。

    综合来看,本项目融合了协同过滤和深度学习技术,为用户提供了两种不同但有效的电影推荐方式。这可以提高用户体验,使他们更容易找到符合他们口味的电影。

    总体设计

    本部分包括系统整体结构图和系统流程图。

    系统整体结构图

    系统整体结构如图所示。
    在这里插入图片描述

    系统流程图

    系统流程如图所示。

    在这里插入图片描述

    模型训练流程如图所示。

    在这里插入图片描述

    服务器运行流程如图所示。

    在这里插入图片描述

    运行环境

    本部分包括Python环境、TensorFlow环境、 后端服务器、Django和微信小程序环境

    模块实现

    本项目包括3个模块:模型训练、后端Django、 前端微信小程序模块,下面分别给出各模块的功能介绍及相关代码。

    1. 模型训练

    下载数据集,解压到项目目录下的./ml-1m文件夹下。数据集分用户数据users.dat、电影数据movies.dat和评分数据ratings.dat。

    1)数据集分析

    数据集网站地址为http://files.grouplens.org/datasets/movielens/ml-1m-README.txt对数据的描述。

    相关博客:https://blog.csdn.net/qq_31136513/article/details/133124641#1_44

    2)数据预处理

    通过研究数据集中的字段类型,发现有一些是类别字段,将其转成独热编码,但是UserID、MovieID的字段会变稀疏,输入数据的维度急剧膨胀,所以在预处理数据时将这些字段转成数字。

    相关博客:https://blog.csdn.net/qq_31136513/article/details/133124641#2_123

    3)模型创建

    相关博客:https://blog.csdn.net/qq_31136513/article/details/133125845#3_50

    4)模型训练

    定义超参数,相关代码如下:

    #训练迭代次数
    num_epochs = 5
    #每个Batch大小
    batch_size = 256
    #丢弃率
    dropout_keep = 0.5
    #学习率
    learning_rate = 0.0001
    #每n 个batches 显示信息
    show_every_n_batches = 20
    #保存路径
    save_dir = './save'
    #定义取得batch的函数
    def get_batches(Xs, ys, batch_size):
        for start in range(0, len(Xs), batch_size):
            end = min(start + batch_size, len(Xs))
            yield Xs[start:end], ys[start:end]
    #定义保存参数的函数
    import pickle
    def save_params(params):
        #保存参数到文件中
        pickle.dump(params, open('params.p', 'wb'))
    def load_params():
        #从文件中加载参数
        return pickle.load(open('params.p', mode='rb'))
    #作图
    %matplotlib inline
    %config InlineBackend.figure_format = 'retina'
    import matplotlib.pyplot as plt
    import time
    import datetime
    #记录损失,用于画图
    losses = {'train':[], 'test':[]}
    with tf.Session(graph=train_graph) as sess:
        #搜集数据给TensorBoard使用
        #跟踪渐变值和稀疏度
        grad_summaries = []
        for g, v in gradients:
            if g is not None:
                grad_hist_summary = tf.summary.histogram("{}/grad/hist".format(v.name.replace(':', '_')), g)
                sparsity_summary = tf.summary.scalar("{}/grad/sparsity".format(v.name.replace(':', '_')), tf.nn.zero_fraction(g))
                grad_summaries.append(grad_hist_summary)
                grad_summaries.append(sparsity_summary)
        grad_summaries_merged = tf.summary.merge(grad_summaries)
        #输出文件夹
        timestamp = str(int(time.time()))
        out_dir = os.path.abspath(os.path.join(os.path.curdir, "runs", timestamp))
        print("Writing to {}\n".format(out_dir))
        #损失与精度的总结
        loss_summary = tf.summary.scalar("loss", loss)
        #训练的总结
        train_summary_op = tf.summary.merge([loss_summary, grad_summaries_merged])
        train_summary_dir = os.path.join(out_dir, "summaries", "train")
        train_summary_writer = tf.summary.FileWriter(train_summary_dir, sess.graph)
        #测试总结
        inference_summary_op = tf.summary.merge([loss_summary])
        inference_summary_dir = os.path.join(out_dir,"summaries","inference")
        inference_summary_writer = tf.summary.FileWriter(inference_summary_dir, sess.graph)
        #变量初始化
        sess.run(tf.global_variables_initializer())
        #模型保存
        saver = tf.train.Saver()
        for epoch_i in range(num_epochs):
        #将数据集分成训练集和测试集,随机种子不固定
            train_X,test_X, train_y, test_y = train_test_split(features,  
                                                         targets_values,  
                                                         test_size = 0.2,  
                                                         random_state = 0)  
        #分开batches
            train_batches = get_batches(train_X, train_y, batch_size)
            test_batches = get_batches(test_X, test_y, batch_size)
        #训练的迭代,保存训练损失
            for batch_i in range(len(train_X) // batch_size):
                x, y = next(train_batches)
                categories = np.zeros([batch_size, 18])
                for i in range(batch_size):
                    categories[i] = x.take(6,1)[i]
                titles = np.zeros([batch_size, sentences_size])
                for i in range(batch_size):
                    titles[i] = x.take(5,1)[i]
                #传入数据
                feed = {
                    uid: np.reshape(x.take(0,1), [batch_size, 1]),
                    user_gender: np.reshape(x.take(2,1), [batch_size, 1]),
                    user_age: np.reshape(x.take(3,1), [batch_size, 1]),
                    user_job: np.reshape(x.take(4,1), [batch_size, 1]),
                    movie_id: np.reshape(x.take(1,1), [batch_size, 1]),
                    movie_categories: categories,  #x.take(6,1)
                    movie_titles: titles,  #x.take(5,1)
                    targets: np.reshape(y, [batch_size, 1]),
                    dropout_keep_prob: dropout_keep, #dropout_keep
                    lr: learning_rate}
                #计算结果
                step, train_loss, summaries, _ = sess.run([global_step, loss, train_summary_op, train_op], feed)  #cost
                losses['train'].append(train_loss)
                #保存记录
                train_summary_writer.add_summary(summaries, step)
                #每多少个batches显示一次
                if (epoch_i * (len(train_X) // batch_size) + batch_i) % show_every_n_batches == 0:
             time_str = datetime.datetime.now().isoformat()
           print('{}: Epoch {:>3} Batch {:>4}/{}   train_loss = {:.3f}'.format(
                        time_str,
                        epoch_i,
                        batch_i,
                        (len(train_X) // batch_size),
                        train_loss))
            #使用测试数据的迭代
            for batch_i  in range(len(test_X) // batch_size):
                x, y = next(test_batches)
                categories = np.zeros([batch_size, 18])
                for i in range(batch_size):
                    categories[i] = x.take(6,1)[i]
                titles = np.zeros([batch_size, sentences_size])
                for i in range(batch_size):
                    titles[i] = x.take(5,1)[i]
                #传入数据
                feed = {
                    uid: np.reshape(x.take(0,1), [batch_size, 1]),
                    user_gender: np.reshape(x.take(2,1), [batch_size, 1]),
                    user_age: np.reshape(x.take(3,1), [batch_size, 1]),
                    user_job: np.reshape(x.take(4,1), [batch_size, 1]),
                    movie_id: np.reshape(x.take(1,1), [batch_size, 1]),
                    movie_categories: categories,  #x.take(6,1)
                    movie_titles: titles,  #x.take(5,1)
                    targets: np.reshape(y, [batch_size, 1]),
                    dropout_keep_prob: 1,
                    lr: learning_rate}
                #计算结果
                step, test_loss, summaries = sess.run([global_step, loss, inference_summary_op], feed)  #cost
                #保存测试损失
                losses['test'].append(test_loss)
                inference_summary_writer.add_summary(summaries, step)  
                #每多少个batches显示一次
                time_str = datetime.datetime.now().isoformat()
                if (epoch_i * (len(test_X) // batch_size) + batch_i) % show_every_n_batches == 0:
                    print('{}: Epoch {:>3} Batch {:>4}/{}   test_loss = {:.3f}'.format(
                        time_str,
                        epoch_i,
                        batch_i,
                        (len(test_X) // batch_size),
                        test_loss))
        #保存模型
        saver.save(sess, save_dir)
        print('Model Trained and Saved')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144

    其中,一个batch就是在一次前向/后向传播过程用到的训练样例数量,训练5轮,每轮第一个batch_size 为3125,作为训练集,训练步长为20,第二个batch_ size为781 ,作为测试集,训练步长为20。

    训练集训练结果如图所示。
    在这里插入图片描述

    测试集训练结果如图所示。
    在这里插入图片描述

    通过观察训练集和测试集损失函数的大小来评估模型的训练程度,进行模型训练的进一步决策。一般来说,训练集和测试集的损失函数不变且基本相等为模型训练的较佳状态。可以将训练过程中保存的损失函数以图片的形式表现出来,方便观察。

    相关代码如下:

    #保存参数
    save_params((save_dir))
    load_dir = load_params()
    #作图画出训练损失
    plt.figure(figsize=(8, 6))
    plt.plot(losses['train'], label='Training loss')
    plt.legend()
    plt.xlabel("Batches")
    plt.ylabel("Loss")
    _ = plt.ylim()
    #作图画出测试损失
    plt.figure(figsize=(8,6))
    plt.plot(losses['test'], label='Test loss')
    plt.legend()
    plt.xlabel("Batches")
    plt.ylabel("Loss")
    _ = plt.ylim()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5)获取特征矩阵

    本部分包括定义函数张量、生成电影特征矩阵、生成用户特征矩阵。

    (1)定义函数用于获取保存的张量

    相关代码如下:

    def get_tensors(loaded_graph):
        #使用get_tensor_by_name()函数从loaded_graph模块中获取张量
        uid = loaded_graph.get_tensor_by_name("uid:0")
        user_gender = loaded_graph.get_tensor_by_name("user_gender:0")
        user_age = loaded_graph.get_tensor_by_name("user_age:0")
        user_job = loaded_graph.get_tensor_by_name("user_job:0")
        movie_id = loaded_graph.get_tensor_by_name("movie_id:0")
      movie_categories=loaded_graph.get_tensor_by_name("movie_categories:0")
        movie_titles = loaded_graph.get_tensor_by_name("movie_titles:0")
        targets = loaded_graph.get_tensor_by_name("targets:0")
        dropout_keep_prob = loaded_graph.get_tensor_by_name("dropout_keep_prob:0")
        lr = loaded_graph.get_tensor_by_name("LearningRate:0")
        inference = loaded_graph.get_tensor_by_name("inference/ExpandDims:0")
        movie_combine_layer_flat = loaded_graph.get_tensor_by_name("movie_fc/Reshape:0")
        user_combine_layer_flat = loaded_graph.get_tensor_by_name("user_fc/Reshape:0")
        return uid, user_gender, user_age, user_job, movie_id, movie_categories, movie_titles, targets, lr, dropout_keep_prob, inference, movie_combine_layer_flat, user_combine_layer_flat
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    (2)生成电影特征矩阵

    相关代码如下:

    loaded_graph = tf.Graph()
    movie_matrics = []
    with tf.Session(graph=loaded_graph) as sess: 
        #载入保存好的模型
        loader = tf.train.import_meta_graph(load_dir + '.meta')
        loader.restore(sess, load_dir)
        #调用函数提取tensors
        uid, 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)  
        for 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,
                movie_titles: titles,
                dropout_keep_prob: 1}
            movie_combine_layer_flat_val = sess.run([movie_combine_layer_flat], feed)
            #添加进一个list中
            movie_matrics.append(movie_combine_layer_flat_val)
    #保存成.p文件
    pickle.dump((np.array(movie_matrics).reshape(-1, 200)), open('movie_matrics.p', 'wb'))
    #读取文件
    movie_matrics = pickle.load(open('movie_matrics.p', mode='rb'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    (3)生成用户特征矩阵

    相关代码如下:

    loaded_graph = tf.Graph()
    users_matrics = []
    with tf.Session(graph=loaded_graph) as sess:
        #载入保存好的模型
        loader = tf.train.import_meta_graph(load_dir + '.meta')
        loader.restore(sess, load_dir)
        #调用函数提取张量
        uid, 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_graph
        for 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)  
            #添加进一个list中
            users_matrics.append(user_combine_layer_flat_val)
    #保存成.p文件
    pickle.dump((np.array(users_matrics).reshape(-1, 200)), open('users_matrics.p', 'wb'))
    #读取文件
    users_matrics = pickle.load(open('users_matrics.p', mode='rb'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    完成模型训练生成preprocess.pmovie_matrics.pusers_matrics.p数据文件。这三个文件会放进后端Django框架中,以便调用。

    相关其它博客

    基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(一)

    基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(二)

    基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(三)

    基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(五)

    基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(六)

    基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(七)

    工程源代码下载

    详见本人博客资源下载页


    其它资料下载

    如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载
    这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

  • 相关阅读:
    Apache HTTP服务器配置syslog
    下载、安装Git并拷贝GitHub项目到本地的流程
    EntityManagerFactory和EntityManager的一个用法探究
    【Java 集合】准备知识
    C语言指针详解
    半导体芯片相关知识
    js实现页面元素的拖拽
    Linux:firewalld防火墙-小环境实验(3)
    git总结
    设计模式之迭代器模式
  • 原文地址:https://blog.csdn.net/qq_31136513/article/details/133130704