百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

推荐模型AutoRec原理介绍与TensorFlow实现

toyiye 2024-06-21 12:31 8 浏览 0 评论

作者:道之有道

出处:https://www.cnblogs.com/sxzhou/p/14489025.html

1. 简介

本篇文章先简单介绍论文思路,然后使用Tensoflow2.0、Keras API复现算法部分。包括:

  • 自定义模型
  • 自定义损失函数
  • 自定义评价指标RMSE

就题目而言 《AutoRec: Autoencoders Meet Collaborative Filtering》,自编码机遇见协同过滤 ,可见是使用自编码机结合协同过滤思想进行的算法。论文经过数据集Movielens和Netfix验证有不错的效果,更重要的是它是对特征交叉引入深度学习的开端,论文两页,简单易懂。

2. 算法模型

令m个用户,n个物品,构成用户-物品矩阵,每个物品对被用户进行评分。根据协同过滤思想,有 基于用户的方式,也有基于物品的方式,取决于输入是物品分表示的用户向量,还是用户评分表示物品向量$r {i},r {u}$ 。自编码机部分将评分向量进行低维压缩,用低维空间表示评分向量,并对向量不同部分进行交叉,然后重构向量。

算法模型图为:

采用的 模型公式 为(基本就是逻辑回归的方式):

其中,中间的神经元数量,即映射低维空间设为k,则k是一个超参数根据效果进行调控。

需要注意的部分是

  1. 每个评分向量(无论物品还是用户向量),都存在稀疏性即没有用户对其进行评分,则在反向传播的过程中不能考虑这部分内容;
  2. 为了防止过拟合,需要在 损失函数 中添加W和V参数矩阵正则化:

前一部分为真实值与预测值的平方误差(仅仅计算有评分的部分),第二部分为正则项,所求为F范数。

预测公式:

若是基于物品的AutoRec(I-AutoRec)则,输入待求的物品向量,到下面预测公式中,得到一个完整的向量,求第几个用户就取第几个维度从而得到此用户对此物品的评分,即

基于用户的AutoRec(U-AutoRec)表示类似。

实验验证

论文的评价方式,使用的RMSE,与其他算法比较得到比较好的参数是k=500,f映射使用线性函数,g映射使用Sigmoid函数。

3. 代码复现

复现包括网络模型,损失函数,以及评价指标三部分,由于部分的改动不能直接使用TF原生的库函数。

首先导入需要使用的工具包:

import numpy as np 
import pandas as pd 
import tensorflow as tf 
from tensorflow import keras
from sklearn.model_selection import train_test_split

定义模型

基于Keras的API的模型定义需要继承 Model 类,重写方法 call (前向传播过程),如果需要加入 dropout 的模型需要将训练和预测分开可以使用参数 training=None 的方式来指定,这里不需要这个参数,因此省略。

class AutoRec(keras.Model):
    def __init__(self, feature_nums, hidden_units, **kwargs):
        super(AutoRec, self).__init__()
        self.feature_nums = feature_nums # 基于物品则为物品特征数-即用户数,基于用户则为物品数量
        self.hidden_units = hidden_units # 论文中的k参数
        self.encoder = keras.layers.Dense(self.hidden_units, input_shape=[self.feature_nums], activation='sigmoid') # g映射
        self.decoder = keras.layers.Dense(self.feature_nums, input_shape=[self.hidden_units]) # f映射

    def call(self, X):
        # 前向传播
        h = self.encoder(X)
        y_hat = self.decoder(h)
        return y_hat

定义损失函数

此损失函数虽然为MSE形式,但是在计算的过程中发现,仅仅计算有评分的部分,无评分部分不进入损失,同时还有正则化,这里一起写出来。

基于Keras API的方式,需要继承 Loss 类,和方法 call 初始化传入 model 参数为了取出W和V参数矩阵。

mask_zero 表示没有评分的部分不进入损失函数,同时要保证数据类型统一 tf.int32,tf.float32 否则会报错。

class  Mse_Reg(keras.losses.Loss):
    def __init__(self, model, reg_factor=None):
        super(Mse_Reg, self).__init__()
        self.model = model
        self.reg_factor = reg_factor
    
    def call(self, y_true, y_pred) :
        y_sub = y_true - y_pred
        mask_zero = y_true != 0
        mask_zero = tf.cast(mask_zero, dtype=y_sub.dtype)
        y_sub *= mask_zero
        mse = tf.math.reduce_sum(tf.math.square(y_sub)) # mse损失部分
        reg = 0.0
        if self.reg_factor is not None:
            weight = self.model.weights
            for w in weight:
                if 'bias' not in w.name:
                    reg += tf.reduce_sum(tf.square(w)) # 求矩阵的Frobenius范数的平方
            return mse + self.reg_factor * 0.5 * reg
        return mse

定义RMSE评价指标

定义评价指标需要继承类 Metric ,方法 update_state和result以及reset ,reset方法感觉使用较少,主要是更新状态和得到结果。

class RMSE(keras.metrics.Metric):
    def __init__(self):
        super(RMSE, self).__init__()
        self.res = self.add_weight(name='res', dtype=tf.float32, initializer=tf.zeros_initializer())   

    def update_state(self, y_true, y_pred, sample_weight=None):
        y_sub = y_true - y_pred
        mask_zero = y_true != 0
        mask_zero = tf.cast(mask_zero, dtype=y_sub.dtype)
        y_sub *= mask_zero
        values = tf.math.sqrt(tf.reduce_mean(tf.square(y_sub)))
        self.res.assign_add(values)

    def result(self):
        return self.res

定义数据集

定义好各个部分之后,就可以构造训练集然后训练模型了。

get_data 表示从path中加载数据,然后加数据通过pandas的透视表功能构造一个行为物品,列为用户的矩阵;

data_iter 表示通过 tf.data 构造数据集。

# 定义数据
def get_data(path, base_items=True):
    data = pd.read_csv(path)
    rate_matrix = pd.pivot_table(data, values='rating', index='movieId', columns='userId',fill_value=0.0)
    if base_items:
        return rate_matrix
    else :
        return rate_matrix.T
 
def data_iter(df, shuffle=True, batch_szie=32, training=False) :
    df = df.copy()
    X = df.values.astype(np.float32)
    ds = tf.data.Dataset.from_tensor_slices((X, X)).batch(batch_szie)
    if training:
        ds = ds.repeat()
    return ds

训练模型

万事俱备,就准备数据放给模型就好了。

要说明的是,如果fit的时候不设置 steps_per_epoch 会在数据量和batch大小不能整除的时候报迭代器的超出范围的错误。设置了此参数当然也要加上 validation_steps=2 ,不然还是会报错,不信可以试试看。

path = 'ratings.csv' # 我这里用的是10w数据,不是原始的movielens-1m
# I-AutoRec,num_users为特征维度
rate_matrix = get_data(path)
num_items, num_users = rate_matrix.shape

# 划分训练测试集
BARCH = 128
train, test = train_test_split(rate_matrix, test_size=0.1)
train, val = train_test_split(train, test_size=0.1)
train_ds = data_iter(train, batch_szie=BARCH, training=True)
val_ds = data_iter(val, shuffle=False)
test_ds = data_iter(test, shuffle=False)

# 定义模型
net = AutoRec(feature_nums=num_users, hidden_units=500) # I-AutoRec, k=500
net.compile(loss=Mse_Reg(net), #keras.losses.MeanSquaredError(),
            optimizer=keras.optimizers.Adam(),
            metrics=[RMSE()])
net.fit(train_ds, validation_data=val_ds, epochs=10, validation_steps=2, steps_per_epoch=train.shape[0]//BARCH)

loss, rmse = net.evaluate(test_ds)
print('loss: ', loss, ' rmse: ', rmse)

预测

df = test.copy()
X = df.values.astype(np.float32)
ds = tf.data.Dataset.from_tensor_slices(X) # 这里没有第二个X了
ds = ds.batch(32)
pred = net.predict(ds)
# 随便提出来一个测试集中有的评分看看预测的分数是否正常,pred包含原始为0.0的分数现在已经预测出来分数的。
print('valid: pred user1 for item1: ', pred[1][X[1].argmax()], 'real: ', X[1][X[1].argmax()])

得到结果(没有达到论文的精度,可能是数据量不足,而valid部分可以看到预测的精度还是凑合的):

4. 小结

本篇文章主要是针对AutoRec论文的主要部分进行了介绍,然后使用TensorFlow2.0的Keras接口实现了自定义的模型,损失,以及指标,并训练了I-AutoRec模型。

关于AutoRec要说的是,

编码器部分如果使用深层网络比如三层会增加预测的准确性;

自编码器部分的输出向量经过了编码过程的泛化相当于对缺失部分有了预测能力,这是自编码机用于推荐的原因;

I-AutoRec推荐过程,需要输入物品的矩阵然后得到每个用户对物品的预测评分,然后取用户自己评分的Top可以进行推荐,U-AutoRec只需要输入一次目标用户的向量就可以重建用户对所有物品的评分,然后得到推荐列表,但是用户向量可能稀疏性比较大影响最终的推荐效果。

AutoRec使用了单层网络,存在表达能力不足的问题,但对于基于机器学习的矩阵分解,协同过滤来说,由于这层网络的加入特征的表达能力得到提高。

作者:道之有道

出处:https://www.cnblogs.com/sxzhou/p/14489025.html

相关推荐

如何用 coco 数据集训练 Detectron2 模型?

随着最新的Pythorc1.3版本的发布,下一代完全重写了它以前的目标检测框架,新的目标检测框架被称为Detectron2。本教程将通过使用自定义coco数据集训练实例分割模型,帮助你开始使...

CICD联动阿里云容器服务Kubernetes实践之Bamboo篇

本文档以构建一个Java软件项目并部署到阿里云容器服务的Kubernetes集群为例说明如何使用Bamboo在阿里云Kubernetes服务上运行RemoteAgents并在agents上...

Open3D-ML点云语义分割实验【RandLA-Net】

作为点云Open3D-ML实验的一部分,我撰写了文章解释如何使用Tensorflow和PyTorch支持安装此库。为了测试安装,我解释了如何运行一个简单的Python脚本来可视化名为...

清理系统不用第三方工具(系统自带清理软件效果好不?)

清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...

【信创】联想开先终端开机不显示grub界面的修改方法

原文链接:【信创】联想开先终端开机不显示grub界面的修改方法...

如意玲珑成熟度再提升,三大发行版支持教程来啦!

前期,我们已分别发布如意玲珑在deepinV23与UOSV20、openEuler24.03发行版的操作指南,本文,我们将为大家详细介绍Ubuntu24.04、Debian12、op...

118种常见的多媒体文件格式(英文简写)

MP4[?mpi?f??]-MPEG-4Part14(MPEG-4第14部分)AVI[e?vi??a?]-AudioVideoInterleave(音视频交错)MOV[m...

密码丢了急上火?码住7种console密码紧急恢复方式!

身为攻城狮的你,...

CSGO丨CS2的cfg指令代码分享(csgo自己的cfg在哪里?config文件位置在哪?)

?...

使用open SSL生成局域网IP地址证书

某些特殊情况下,用户内网访问多可文档管理系统时需要启用SSL传输加密功能,但只有IP,没有域名和证书。这种情况下多可提供了一种免费可行的方式,通过openSSL生成免费证书。此方法生成证书浏览器会提示...

Python中加载配置文件(python怎么加载程序包)

我们在做开发的时候经常要使用配置文件,那么配置文件的加载就需要我们提前考虑,再不使用任何框架的情况下,我们通常会有两种解决办法:完整加载将所有配置信息一次性写入单一配置文件.部分加载将常用配置信息写...

python开发项目,不得不了解的.cfg配置文件

安装软件时,经常会见到后缀为.cfg、.ini的文件,一般我们不用管,只要不删就行。因为这些是程序安装、运行时需要用到的配置文件。但对开发者来说,这种文件是怎么回事就必须搞清了。本文从.cfg文件的创...

瑞芯微RK3568鸿蒙开发板OpenHarmony系统修改cfg文件权限方法

本文适用OpenHarmony开源鸿蒙系统,本次使用的是开源鸿蒙主板,搭载瑞芯微RK3568芯片。深圳触觉智能专注研发生产OpenHarmony开源鸿蒙硬件,包括核心板、开发板、嵌入式主板,工控整机等...

Python9:图像风格迁移-使用阿里的接口

先不多说,直接上结果图。#!/usr/bin/envpython#coding=utf-8importosfromaliyunsdkcore.clientimportAcsClient...

Python带你打造个性化的图片文字识别

我们的目标:从CSV文件读取用户的文件信息,并将文件名称修改为姓名格式的中文名称,进行规范资料整理,从而实现快速对多个文件进行重命名。最终效果:将原来无规律的文件名重命名为以姓名为名称的文件。技术点:...

取消回复欢迎 发表评论:

请填写验证码