【机器学习】使用tensorflow 实现协同过滤算法

系列文章目录

第十六章 Python 机器学习 入门之 协同过滤算法


目录

系列文章目录

前言

一、均值归一化

二、利用TensorFlow  来实现协同过滤算法

1 构建代价函数

2 更新参数

三、 寻找相关特征

总结


前言

本文主要讲解如何使用tensorflow 来实现协同过滤算法,以及如何使用均值归一化来优化协同过滤算法和寻找相关特征。


一、均值归一化

均值归一化 mean normalization 有什么用?

在协同过滤算法中加入均值归一化可以使得算法运行的更多,结果更准确。

下面来看看均值归一化的使用

还是以之前的评价电影的例子来说,如果我们添加了一个人Eve, 他并没有对任何电影进行评论。

如果我们在这个数据上训练一个协调过滤算法,通过代价函数我们得到参数的值,对于第五个人Eve ,我们的到的参数可以是 w=[0,0],b(5)=0。

因为他没有给任何电影评分,使用参数w,b 不影响代价函数中的第一项,在这个平方误差代价函数中,我们希望代价函数的值尽可能的小,所以也就是希望参数w 的值尽可能的小,最后参数w 会取到0,参数b 的值我们并没有进行规定,也可以默认它的值为0。

如果我们使用计算出来的参数值来预测评分,那么w*x+b ,最终5部电影的评分都是0,这就是使用均值归一化的原因,使用均值归一化可以避免这种情况。

下面,我们来看看什么是均值归一化

为了描述什么是均值归一化,我们将数据写成矩阵的形式。

在这里,我们计算每一行的均值,然后写成一个列向量μ,表示每部电影的平均收视率,

然后将每个评分减去评分的平均值,随后使用均值归一化后的值进行预测,

为了避免预测结果出现负值,我们就可以在后面加上μ_i

有了这些铺垫,我们再来看均值归一化后的数据对第五个用户Eve,对5部电影的预测,预测结果不是0了,而是评分均值了,很明显这样的评分比0评分是要好的。

事实证明,通过将不同电影评分的均值归一化为0,优化算法推荐的系统也会运行得更快一点。

它对于没有评价电影和评价电影数量很少的用户表现更好,预测结果也更合理。

这里我们使用的是对矩阵的每一行标准化为均值为0,对于不同的问题,我们也可以对矩阵的列进行标准化。

比如对于一部没有人看过的电影,想对其进行预测评分,那么对矩阵的列进行标准化效果是比较好的。

二、利用TensorFlow  来实现协同过滤算法

1 构建代价函数

代码如下:

# 方法一(按公式)
def cost_func(X, W, b, Y, R, lambda_):

    nm, nu = Y.shape
    J = 0
  
    for j in range(nu):
        w = W[j, : ]
        b_j = b[0, j]
        
        for i in range(nm):
            x = X[i, : ]
            y = Y[i, j]
            r = R[i, j]
            J += np.square(r * (np.dot(w,x) + b_j - y))
           
            
    J += lambda_*(np.sum(np.square(W)) + np.sum(np.square(X)))       
    J = J/2

    return J



# 方法二 (使用矢量化)
def cost_func(X, W, b, Y, R, lambda_):

    j = (tf.linalg.matmul(X, tf.transpose(W)) + b - Y)*R
    J = 0.5 * tf.reduce_sum(j**2) + (lambda_/2) * (tf.reduce_sum(X**2) + tf.reduce_sum(W**2))
    return J

2 更新参数

Tensor Flow 不仅可以构建神经网络模型,也可以用它来实现协同过滤算法。

其关键点就在于,使用tensorflow可以自动找到代价函数的导数。这是tensorflow 的一个非常强大的功能,称为AuTo Diff, 它有时也被叫做AuTo Grad ,但是专业的术语还是AuTo Diff,

而AuTo Grad 其实是做自动微分,自动取倒数的专用软件包的名称

下面使用AuTo Diff来实现上面协同过滤算法的简化例子。 

代码如下:

import tensorflow as tf

w = tf.Variable(3.0)  # 告诉tensorflow w 是一个变量,它是我们想要优化的参数

# 设置其他参数
x = 1.0
y = 1.0   # y是目标值
alpha = 0.01

iterations = 30 #迭代次数
for iter in range(iterations):      
    with tf.GradientTape() as tape:   # 使用GradientTape()梯度磁带功能,tensorflow会自动记录步骤顺序,
        fwb = w*x                     # 计算代价J 所需的成本序列,将序列保持在 tape 磁带中
        costJ = (fwb - y)**2
        
[dJdw] = tape.gradient(costJ, [w])   # tensorflow 自动计算w 的倒数

# tensorflow 变量,层变量需要特殊处理,使用assign_add() 函数来更新参数
w.assign_add(-alpha * dJdw)

# 使用tensorflow 的 梯度磁带功能,我们需要做的是告诉它,如何计算代价函数J 

正常情况下使用AuTo Diff来实现协同过滤算法

代码如下:

import tensorflow as tf

# 知指定优化器Adams, 设置学习速率
optimizer = keras.optimizers.Adam(learning_rate = 1e-1)

# 设置其他参数
iterations = 200 #迭代次数
for iter in range(iterations):      
    with tf.GradientTape() as tape:   # 使用GradientTape()梯度磁带功能,tensorflow会自动记录步骤顺序,
                                         # 计算代价J 所需的成本序列将序列保持在 tape 磁带中
        cost_value = cofiCostFuncV(X, W, b, Ynorm, R, num_users, num_movies, lambda)  # 提供代码计算代价函数
        
grads = tape.gradient(cost_valuw, [X, W, b])   # tensorflow 自动计算X, W, b 的倒数

#将优化器与刚刚计算的梯度一起使用
optimizer.apply_gradients(zip(grads, [X, W, b]))

三、 寻找相关特征

我们学习了每个项目I 的特征x^(i),  它很难明确的学习到各个特征,比如说x1学习到这个电影是否是动作片,x2学习到这个电影是否是美国片等,这些是很难的。

我们将学到的特征,统称为 x1、x2…… 等 ,表示关于这部电影的某些特征

虽然学习不到哪些准确的特征,但是找到的这些特征都是与这部电影相关的。

给定项目i的特征x^(i),如果我们想找到其它项目,比如说与电影i相关的其他电影,那么我们可以做的就是尝试找到项目k的x^(k), 类似于x^(i)。

计算x^(k),与 x^(i)的平方距离,如果计算出来的距离值小的话,那就是相关的特征。

如果我们发现不只是一部电影x^(k) 与 x^(i)之间的距离最小,比如说找到了5个相关的项目,那么如果用户在找某个电影Ii时,我们就可以将这几个相似的电影k推荐给他。


总结

使用tensorflow 来实现协同过滤算法还是比较简单的,因为auto diff  功能可以让计算机自己计算代价函数中的导数值,在进行参数更新时,这无疑是为我们省了不少事。除了协同过滤算法,还有一个推荐算法叫基于内容过滤算法,它可以很好的解决本文所指出的协同过滤算法存在的问题,虽然可以使用均值归一化来解决,但是还是会影响精度,而基于内容过滤算法就可以很好的解决这一点,后面我们会学到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓亮.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值