一个模型搞定多个CTR业务!阿里STAR网络介绍(附代码实现)

今天为大家带来阿里巴巴2021年的一篇文章:《One Model to Serve All: Star Topology Adaptive Recommender for Multi-Domain CTR Prediction》。该文章提出的方法可以只使用一种模型,便可以服务于多种CTR业务场景。这些业务场景中可能会共享一些user和item,也有自己独立的user和item。相比于传统方法中的一个模型对应一种业务,该方法既可以减少多个模型带来的维护成本与计算资源,也可以共享不同业务场景下的数据。我们接下来将详细介绍。

1. 方法动机

针对不同的业务场景,例如图1所示的首页推荐和猜你喜欢,传统方法会针对每个业务场景建立不同的模型。这种方法会带来以下几种问题:

  • 一些业务场景的流量较少,相比于其他相似的业务场景,缺乏训练数据。

  • 维护多个模型会带来大量的成本。

因此,我们提出了一种使用单个模型服务于多种业务场景的任务。我们将其称之为 multi-domain CTR prediction,「即我们的模型需要同时预测在业务场景下的点击率。模型以作为输入,其中为输入特征,为点击标签,为不同业务场景的标识」。其中由不同业务场景下的分布得到。为了充分利用不同业务场景下的数据,该文章提出了以下3种模块:

  1. 「Partitioned Normalization (PN)」: 可以针对不同业务场景下不同的数据分布做定制化归一化。

  2. 「Star topology fully-connected neural network」: 文章提出了Star Topology Adaptive Recommender(STAR) 来解决多领域的CTR预估问题。该网络可以充分利用多个业务中的数据来提升各自业务的指标。

  3. 文章提出了一种「辅助网络」(auxiliary network),直接以业务场景的标识(domain indicator)作为输入,来使得网络更好的感知不同场景下的数据分布。

50164ff23cb807eb9059c5038e068ca1.png图1:首页推荐和猜你喜欢。

2. 方法介绍

方法总览

如图2(a)所示,之前单场景CTR预估的方法将输入经过embedding层后,通过pooling/concat操作得到一维的向量表示后,通过BN层,经过一系列FC层,输出最后的结果。这类方法一个模型对应一种业务,不能充分利用不同业务场景下相似的数据,也提升了多个模型带来的业务成本。本文提出的方法如图2(b)所示:相比于图2(a)所示的模型,该模型有以下几点不同:

  1. 将BN(Batch Normalization)层替换为PN(Partitioned Normalization)层。

  2. 将FCN替换为Star Topology FCN。

  3. 将domain indicator直接输入。

我们接下来将详细介绍这三个不同之处。706d5d1f2c9d3fb0a93da1ee8dea59f2.png

图2:(a)单场景CTR预估模型。(b):Multi-Domain CTR预估模型。
Partitioned Normalization

Batch Normalization (BN)是一个具有代表性的方法,该方法对于深度网络的训练有着关键的作用。具体来说,BN的公式如下:

其中为输出,和 为可学习的缩放系数与bias,和为mini-batch的均值和方差。在测试阶段,BN使用训练中滑动平均得到的均值和方差:

「BN假设所有的样本都是独立同分布(i.i.d),同时所有的训练样本都有着相同的统计规律。」

「然而在multi-domain CTR prediction任务下,样本只在一个domain里遵循i.i.d,不同领域之间并不独立同分布」。因此,文章提出了Partitioned Normalization(PN),具体公式如下:

其中为domain-specific scale 和 domain-specific bias,来捕捉不同domain之间的数据分布。在测试阶段,PN使用训练中每个领域滑动平均得到的均值和方差:

Star Topology FCN

如图2(b)所示,在经过PN层后,输出会作为Star Topology FCN的输入。Star Topology FCN包含一个所有领域共享的FCN和每个领域各自独立的FCN(如图3所示)。因此,所有的FCN数量为, 为domain的数量。对于共享的FCN,我们令为共享FCN的权重,为共享FCN的偏置。对于每个领域各自独立的FCN,我们令其权重为,偏置为。对于第个领域,其最后的权重和偏置表示为:

其中为逐点相乘。我们令为网络第个领域的输入,则输出可表示为:

b5603ef2eb8e158d0a463d0dda4fae48.png图3:Star Topology FCN结构

所以,通俗来说,Star Topology FCN中每个领域网络的权重由共享FCN和其domain-specific FCN的权重共同决定。共享FCN来决定每个领域中数据的共性,而domain-specific FCN习得不同领域数据之间分布的差异性。

为了方便大家理解,我们提供了Star Topology FCN的tensorflow 代码实现,核心步骤实现如代码中注释所示:由于公众号显示代码会有遮挡,欢迎大家点击阅读原文,更方便地查看详细代码。

import tensorflow as tf
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.initializers import Zeros, glorot_normal
from tensorflow.python.keras.layers import Layer
from tensorflow.python.keras.regularizers import l2

def activation_layer(activation):
    if isinstance(activation, str):
        act_layer = tf.keras.layers.Activation(activation)
    elif issubclass(activation, Layer):
        act_layer = activation()
    else:
        raise ValueError(
            "Invalid activation,found %s.You should use a str or a Activation Layer Class." % (activation))
    return act_layer

class STAR(Layer):

    def __init__(self, hidden_units, num_domains, activation='relu', l2_reg=0, dropout_rate=0, use_bn=False, output_activation=None,
                 seed=1024, **kwargs):
        self.hidden_units = hidden_units
        self.num_domains = num_domains
        self.activation = activation
        self.l2_reg = l2_reg
        self.dropout_rate = dropout_rate
        self.use_bn = use_bn
        self.output_activation = output_activation
        self.seed = seed

        super(STAR, self).__init__(**kwargs)

    def build(self, input_shape):
        input_size = input_shape[-1]
        hidden_units = [int(input_size)] + list(self.hidden_units)
        ## 共享FCN权重
        self.shared_kernels = [self.add_weight(name='shared_kernel_' + str(i),
                                        shape=(
                                            hidden_units[i], hidden_units[i + 1]),
                                        initializer=glorot_normal(
                                            seed=self.seed),
                                        regularizer=l2(self.l2_reg),
                                        trainable=True) for i in range(len(self.hidden_units))]

        self.shared_bias = [self.add_weight(name='shared_bias_' + str(i),
                                     shape=(self.hidden_units[i],),
                                     initializer=Zeros(),
                                     trainable=True) for i in range(len(self.hidden_units))]
        ## domain-specific 权重
        self.domain_kernels = [[self.add_weight(name='domain_kernel_' + str(index) + str(i),
                                        shape=(
                                            hidden_units[i], hidden_units[i + 1]),
                                        initializer=glorot_normal(
                                            seed=self.seed),
                                        regularizer=l2(self.l2_reg),
                                        trainable=True) for i in range(len(self.hidden_units))] for index in range(self.num_domains)]

        self.domain_bias = [[self.add_weight(name='domain_bias_' + str(index) + str(i),
                                     shape=(self.hidden_units[i],),
                                     initializer=Zeros(),
                                     trainable=True) for i in range(len(self.hidden_units))] for index in range(self.num_domains)]

        self.activation_layers = [activation_layer(self.activation) for _ in range(len(self.hidden_units))]

        if self.output_activation:
            self.activation_layers[-1] = activation_layer(self.output_activation)

        super(STAR, self).build(input_shape)  # Be sure to call this somewhere!

    def call(self, inputs, domain_indicator, training=None, **kwargs):
        deep_input = inputs
        output_list = [inputs] * self.num_domains 
        for i in range(len(self.hidden_units)):
            for j in range(self.num_domains):
                # 网络的权重由共享FCN和其domain-specific FCN的权重共同决定
                output_list[j] = tf.nn.bias_add(tf.tensordot(
                    output_list[j], self.shared_kernels[i] * self.domain_kernels[j][i], axes=(-1, 0)), self.shared_bias[i] + self.domain_bias[j][i])

                try:
                    output_list[j] = self.activation_layers[i](output_list[j], training=training)
                except TypeError as e:  # TypeError: call() got an unexpected keyword argument 'training'
                    print("make sure the activation function use training flag properly", e)
                    output_list[j] = self.activation_layers[i](output_list[j])
        output = tf.reduce_sum(tf.stack(output_list, axis=1) * tf.expand_dims(domain_indicator,axis=-1), axis=1)

        return output

    def compute_output_shape(self, input_shape):
        if len(self.hidden_units) > 0:
            shape = input_shape[:-1] + (self.hidden_units[-1],)
        else:
            shape = input_shape

        return tuple(shape)

    def get_config(self, ):
        config = {'activation': self.activation, 'hidden_units': self.hidden_units,
                  'l2_reg': self.l2_reg, 'use_bn': self.use_bn, 'dropout_rate': self.dropout_rate,
                  'output_activation': self.output_activation, 'seed': self.seed}
        base_config = super(STAR, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))
Auxiliary Network

文章还提出了一个辅助网络来学习不同领域之间数据分布的差别。该网络和主干网络相比,参数量很小,仅为几层layer。该辅助网络以domain indicator 的embedding作为输入,同时连接了其他的特征。输出为,我们令主干网络的输出为。最终的CTR预测结果如下所示:

由此可见,domain indicator会直接影响到输出分数的变化,增强了网络捕捉不同领域数据分布的能力。

总结

本文首先提出了不同业务场景下,数据互相共享互补提升的思路,提出了一种新的任务:multi-domain CTR prediction。并针对这类任务设计了PN,Star Topology FCN,辅助网络等结构。笔者认为,该文章具有很好的借鉴价值,大家可以在自己的任务上或者业务中进行尝试,欢迎大家交流。

一起交流

想和你一起学习进步!『NewBeeNLP』目前已经建立了多个不同方向交流群(机器学习 / 深度学习 / 自然语言处理 / 搜索推荐 / 图网络 / 面试交流 / 等),名额有限,赶紧添加下方微信加入一起讨论交流吧!(注意一定要备注信息才能通过)

d31f4299edde5572e8add4c974f5d765.png

参考文献:

Sheng XR, Zhao L, Zhou G, Ding X, Luo Q, Yang S, Lv J, Zhang C, Zhu X. One Model to Serve All: Star Topology Adaptive Recommender for Multi-Domain CTR Prediction. arXiv preprint arXiv:2101.11427. 2021 Jan 27.

END -

fe870d059645ff48d75619552988b5a1.png

deb3c2a56ba828da699547d265156cfc.png

从Google Scholar看各大科技公司科研水平

2021-10-30

318c7d89b7c870427028cf808d25da2f.png

广义多目标算法探索实践

2021-10-29

533edb5bc6d6509fee9df3c9aee07795.png

升级换代!Facebook全新电商搜索系统Que2Search

2021-10-28

7320a07912eff7a7579f72feb701b986.png

字节AI LAB NLP算法二面凉+被捞后通过

2021-10-27

6b8c11c41211c48a8b79d474cace7684.png

ef3c917636f7d0e1e74f381d47c165a3.gif

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值