人工智能中文网
  • 主页
  • 线代考研视频
  • 线性代数
  • Python机器学习与算法
  • 大数据与机器学习
  • Python基础入门教程
  • 人工智能中文网
    教程目录
    阅读:

    因子分解机FM算法原理及实现过程(超详细)

    < 上一篇:因子分解机 下一篇:感知机算法 >
    对于FM算法的求解,在前几章中,主要是利用了梯度下降法,在梯度下降法中,在每一个的迭代过程中,利用全部的数据进行模型参数的学习,对于数据量特别大的情况,每次迭代求解所有样本需要花费大量的计算成本。

    随机梯度下降(Stochastic Gradient Descent)

    随机梯度下降算法在每次迭代的过程中,仅根据一个样本对模型中的参数进行调整。

    随机梯度下降法的优化过程为:

    基于随机梯度的方式求解

    假设数据集中有m个训练样本,即 {X(1) ,X(2),…,X(m)},每一个样本 X(i) 有 n 个特征,即:


    对于度为 2 的因子分解机 FM 模型,其主要的参数有一次项和常数项的参数 w0 ,w1 ,…,wn 以及交叉项的系数矩阵 V。在利用随机梯度对模型的参数进行学习的过程中,主要是对损失函数:


    求导数,即:




    为:

    FM算法流程

    利用随机梯度下降法对因子分解机 FM 模型中的参数进行学习的基本步骤如下:

    1) 初始化权重 w0,w1,…,wn 和 V;

    2) 对每一个样本:


    对特征 i∈{1,…,n}:


    对 f ∈{1,…,k}:

    3) 重复步骤 2),直到满足终止条件。

    现在,让我们一起利用 Python 实现上述因子分解机 FM 的更新过程,首先,我们需要导入 numpy:
    import numpy as np
    利用随机梯度下降法训练因子分解机 FM 模型的参数的具体过程如下程序所示。
    def stocGradAscent(dataMatrix, classLabels, k, max_iter, alpha):
        '''利用随机梯度下降法训练FM模型
        input:  dataMatrix(mat)特征
                classLabels(mat)标签
                k(int)v的维数
                max_iter(int)最大迭代次数
                alpha(float)学习率
        output: w0(float),w(mat),v(mat):权重
        '''
        m, n = np.shape(dataMatrix)
        # 1、初始化参数
        w = np.zeros((n, 1))  # 其中n是特征的个数
        w0 = 0  # 偏置项
        v = initialize_v(n, k)  # 初始化V
       
        # 2、训练
        for it in xrange(max_iter):
            for x in xrange(m):  # 随机优化,对每一个样本而言的
                inter_1 = dataMatrix[x] * v
                inter_2 = np.multiply(dataMatrix[x], dataMatrix[x]) *
                 np.multiply(v, v)  # multiply对应元素相乘
                # 完成交叉项
                interaction = np.sum(np.multiply(inter_1, inter_1) - inter_2) / 2.
                p = w0 + dataMatrix[x] * w + interaction  # 计算预测的输出
                loss = sigmoid(classLabels[x] * p[0, 0]) - 1
           
                w0 = w0 - alpha * loss * classLabels[x]
                for i in xrange(n):
                    if dataMatrix[x, i] != 0:
                        w[i, 0] = w[i, 0] - alpha * loss * classLabels[x] * dataMatrix[x, i]
                       
                        for j in xrange(k):
                            v[i, j] = v[i, j] - alpha * loss * classLabels[x] *
                            (dataMatrix[x, i] * inter_1[0, j] -
                              v[i, j] * dataMatrix[x, i] * dataMatrix[x, i])
           
            # 计算损失函数的值
            if it % 1000 == 0:
                print " ------- iter: ", it, " , cost: ",
                getCost(getPrediction(np.mat(dataMatrix), w0, w, v), classLabels)
       
        # 3、返回最终的FM模型的参数
        return w0, w, v
    该程序中的 stocGradAscent 函数实现了对因子分解机 FM 模型的学习,stocGradAscent 函数的输入 dataMatrix 为特征,classLabels 为样本的标签,k 为 FM 模型的度,max_iter 为随机梯度下降法的最大迭代次数,alpha 为随机梯度下降法的学习率。stocGradAscent 函数的输出为模型中的权重,包括一次项和常数项的权重 w0 ,w1 ,…,wn 以及交叉项的系数矩阵 V。

    在程序中的 stocGradAscent 函数中,首先是初始化权重,其中在一次项和常数项的权重 w0 ,w1 ,…,wn 的初始化过程中,使用了比较简单的策略,即全部初始化为 0。对交叉项系数矩阵的初始化过程中,使用的正态分布对其进行初始化,函数 initialize_v 的具体实现如下程序所示。
    def initialize_v(n, k):
        '''初始化交叉项
        input:  n(int)特征的个数
                k(int)FM模型的超参数
        output: v(mat):交叉项的系数权重
        '''
        v = np.mat(np.zeros((n, k)))
       
        for i in xrange(n):
            for j in xrange(k):
                # 利用正态分布生成每一个权重
                v[i, j] = normalvariate(0, 0.2)
        return v
    initialize_v 函数实现了对交叉项的权重进行初始化,initialize_v 函数的输入为特征的个数 n 和 FM 模型的度 k,其输出为交叉项的权重 v。在初始化的过程中,使用了正态分布对权重矩阵 V 中的每一个值生成随机数,为了能够使用正态分布对权重进行初始化,我们需要导入 normalvariate 函数:
    from random import normalvariate #正态分布
    在初始化完所有模型参数后,利用每一个样本对其参数进行学习,并对常数项权重 w0、一次项权重 wi、交叉项的系数矩阵进行修正。sigmoid 函数的具体实现如下所示:
    def sigmoid(inx):
        return 1.0 / (1 + np.exp(-inx))
    在每完成 1000 次迭代后,计算当前的损失函数的值,函数 getCost 的具体实现如下程序所示。
    def getCost(predict, classLabels):
        '''计算预测准确性
        input:  predict(list)预测值
                classLabels(list)标签
        output: error(float)计算损失函数的值
        '''
        m = len(predict)
        error = 0.0
        for i in xrange(m):
            error -=  np.log(sigmoid(predict[i] * classLabels[i] )) 
        return error
    函数 getCost 用于计算当前的损失函数的值,函数的输入是利用当前的 FM 模型对数据集的预测结果 predict 和样本的标签 classLabels,最终得到当前的损失函数值 error。
    < 上一篇:因子分解机 下一篇:感知机算法 >