最终幻想灰机wiki_ffm是什么意思

最终幻想灰机wiki_ffm是什么意思相比于FM模型,FFM模型引入了特征域感知(filed-aware)这个概念,使得模型的表达能力更强

一、前言

FFM在FM的基础上进一步改进,在模型中引入类别的概念,即field。将同一个field的特征单独进行one-hot,因此在FFM中,每一维特征都会针对其他特征的每个field,分别学习一个隐变量,该隐变量不仅与特征相关,也与field相关。通过引入field的概念,FFM把相同性质的特征归于同一个field。

二、FFM模型

在说FFM之前,最好先了解下FM模型 

Factorization Machines(FM):发展过程、原理及实现_只想做个咸鱼的博客-CSDN博客

 文章中提到FM的公式:

最终幻想灰机wiki_ffm是什么意思

 红色两项,分别代表用隐向量内积表示权重系数矩阵,特征的交叉组合

FM存在的问题就是模型在进行特征表示时,是与所有的特征进行组合,即它对所有的特征组合时所用的表示都是一样的,至少也得权衡各个类别里面的交互特征学到,意味着不同的特征应该所表示的不同,例如男和北京、男和篮球,而男与另外两个特征组合时所用的表示是一样,这体现不出他们的不同和重要性

引出FFM的数学表达式:

最终幻想灰机wiki_ffm是什么意思

 可以看到蓝色的隐向量部分多了fj和fi这就是添加的域表示,也可以等同额外添加了另一组隐向量,用来表示特征域的概念,用以区分特征与特征之间的区别,用来增强模型的表示。

三、代码实现

class FFM_Node(object):
    '''
    通常x是高维稀疏向量,所以用链表来表示一个x,链表上的每个节点是个3元组(j,f,v)
    '''
    __slots__ = ['j', 'f', 'v']    # 按照元组不是字典的方式存储类的成员属性
    
    def __init__(self, j, f, v):
        """
            j: Feature index (0-n-1)
            f: field index(0-m-1)
            v: value
        """
        self.j = j
        self.f = f
        self.v = v
    
class FFM(object):
    def __init__(self, m, n, k, eta, lambd):
        """
            m: Number of fields
            n: Number of features
            k: Number of latent factors
            eta: learning rate
            lambd: regularization coefficient
        """
        self.m = m
        self.n = n
        self.k = k
        
        #超参数
        self.eta = eta
        self.lambd = lambd
        
        # 初始化三维权重矩阵w~U(0, 1/sqrt(k))
        self.w = np.random.rand(n, m, k) / math.sqrt(k)
        
        # 初始化累积梯度平方和, AdaGrad时要用到
        self.G = np.ones(shape=(n, m, k), dtype=np.float64)
        self.log = Logistic()
    
    # 这个是计算第三项
    def phi(self, node_list):
        """
        特征组合式的线性加权求和
        param node_list: 用链表存储x中的非0值
        """
        z = 0.0
        for a in range(len(node_list)):
            node1 = node_list[a]
            j1 = node1.j
            f1 = node1.f
            v1 = node1.v
            for b in range(a+1, len(node_list)):
                node2 = node_list[b]
                j2 = node2.j
                f2 = node2.f
                v2 = node2.v
                w1 = self.w[j1, f2]
                w2 = self.w[j2, f1]
                z += np.dot(w1, w2) * v1 * v2
        
        return z
    
    
    def predict(self, node_list):
        """
        输入x, 预测y的值
        """
        z = self.phi(node_list)
        y = self.log.decide_by_tanh(z)
        return y

    # 随机梯度下降
    def sgd(self, node_list, y):
        """
        根据一个样本更新模型参数:
        node_list: 链表存储x中的非0值
        y: 正样本1, 负样本-1
        """
        kappa = -y / (1+math.exp(y*self.phi(node_list)))    # 论文里面的那个导数
        for a in range(len(node_list)):
            node1 = node_list[a]
            j1 = node1.j
            f1 = node1.f
            v1 = node1.v
            for b in range(a+1, len(node_list)):
                node2 = node_list[b]
                j2 = node2.j
                f2 = node2.f
                v2 = node2.v
                c = kappa * v1 * v2      # 这是求导数
                
                # self.w[j1,f2]和self.w[j2,f1]是向量,导致g_j1_f2和g_j2_f1也是向量
                g_j1_f2 = self.lambd * self.w[j1, f2] + c * self.w[j2, f1]
                g_j2_f1 = self.lambd * self.w[j2, f1] + c * self.w[j1, f2]
                
                # 计算各个维度上的梯度累积平方和
                self.G[j1, f2] += g_j1_f2 ** 2
                self.G[j2, f1] += g_j2_f1 ** 2
                
                # Adagrad 算法
                self.w[j1, f2] -= self.eta / np.sqrt(self.G[j1, f2]) * g_j1_f2  # sqrt(G)作为分母,所以G必须是大于0的正数
                self.w[j2, f1] -= self.eta / np.sqrt(
                    self.G[j2, f1]) * g_j2_f1  # math.sqrt()只能接收一个数字作为参数,而numpy.sqrt()可以接收一个array作为参数,表示对array中的每个元素分别开方
    
    # 训练
    def train(self, sample_generator, max_echo, max_r2):
        """
        根据一堆样本训练模型
        sample_generator: 样本生成器,每次yield (node_list, y),node_list中存储的是x的非0值。通常x要事先做好归一化,即模长为1,这样精度会略微高一点
        max_echo: 最大迭代次数
        max_r2: 拟合系数r2达到阈值时即可终止学习
        """
        for itr in range(max_echo):
            print("echo: ", itr)
            y_sum = 0.0
            y_sqare_sum = 0.0
            err_square_sum = 0.0    # 误差平方和
            population = 0   # 样本总数
            for node_list, y in sample_generator:
                y = 0.0  if y == -1 else y    # 真实的y取值为{-1,1},而预测的y位于(0,1),计算拟合效果时需要进行统一
                self.sgd(node_list, y)
                y_hat = self.predict(node_list)
                y_sum += y
                y_sqare_sum += y ** 2
                err_square_sum += (y-y_hat) ** 2
                population += 1
            
            var_y = y_sqare_sum - y_sum * y_sum / population  # y的方差
            r2 = 1 - err_square_sum / var_y
            print("r2: ", r2)
            if r2 > max_r2:
                print("r2 have reach", r2)
                break
        
    # 模型保存
    def save_model(self, outfile):
        '''
        序列化模型
        :param outfile:
        :return:
        '''
        np.save(outfile, self.w)

    def load_model(self, infile):
        '''
        加载模型
        :param infile:
        :return:
        '''
        self.w = np.load(infile)

最终幻想灰机wiki_ffm是什么意思数据集很小,只是验证模型能跑否这个就暂时到这了

四、总结

1、FM是FFM的特例
FFM在FM的基础上提出了field的概念,FM模型中每个特征只有一个隐向量,而FFM则有多个隐向量,点乘时根据对应field进行选择
从算复杂度来看,FM通过化简可以将复杂度降到O(kn),而FFM则是O(kn^2)
2、FFM优缺点

FFM优点:
增加field的概念,同一特征针对不同field使用不同隐向量,模型建模更加准确
FFM缺点:
计算复杂度比较高,参数个数为nfk,计算复杂度为O(kn2)

这代码实现部分较为潦草,知道核心思想,添加域的表示即可,

接下来就开始不如深度学习与推荐系统的碰撞了.
 

 

今天的文章最终幻想灰机wiki_ffm是什么意思分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/73878.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注