自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

基于PaddlePaddle的點(diǎn)擊率的深度學(xué)習(xí)方法嘗試

人工智能 深度學(xué)習(xí)
DeemFM是17年深度學(xué)習(xí)在點(diǎn)擊率預(yù)估、推薦這塊的新的方法,有點(diǎn)類似于deep and wide的思想,將傳統(tǒng)的fm來(lái)nn化,利用神經(jīng)網(wǎng)絡(luò)強(qiáng)大的建模能力來(lái)挖掘數(shù)據(jù)中的有效信息,paddlepaddle在這塊有現(xiàn)成的deepfm模型,單機(jī)部署起來(lái)比較容易....

前言

前面在團(tuán)隊(duì)內(nèi)部分享點(diǎn)擊率相關(guān)的一些文章時(shí),輸出了一篇常見(jiàn)計(jì)算廣告點(diǎn)擊率預(yù)估算法總結(jié),看了一些廣告點(diǎn)擊率的文章,從最經(jīng)典的Logistic Regression到Factorization Machined,F(xiàn)FM,F(xiàn)NN,PNN到今年的DeepFM,還有文章里面沒(méi)有講的gbdt+lr這類,一直想找時(shí)間實(shí)踐下,正好這次在學(xué)習(xí)paddle的時(shí)候在它的models目錄下看到了DeepFM的實(shí)現(xiàn),因?yàn)橹皩?duì)DeepFM有過(guò)比較詳細(xì)的描述,這里稍微復(fù)習(xí)一下:

DeepFM更有意思的地方是WDL和FM結(jié)合了,其實(shí)就是把PNN和WDL結(jié)合了,PNN即將FM用神經(jīng)網(wǎng)絡(luò)的方式構(gòu)造了一遍,作為wide的補(bǔ)充,原始的Wide and Deep,Wide的部分只是LR,構(gòu)造線性關(guān)系,Deep部分建模更高階的關(guān)系,所以在Wide and Deep中還需要做一些特征的東西,如Cross Column的工作,而我們知道FM是可以建模二階關(guān)系達(dá)到Cross column的效果,DeepFM就是把FM和NN結(jié)合,無(wú)需再對(duì)特征做諸如Cross Column的工作了,這個(gè)是我感覺(jué)最吸引人的地方,其實(shí)FM的部分感覺(jué)就是PNN的一次描述,這里只描述下結(jié)構(gòu)圖,PNN的部分前面都描述, FM部分:

 

 

Deep部分:

 

 

DeepFM相對(duì)于FNN、PNN,能夠利用其Deep部分建模更高階信息(二階以上),而相對(duì)于Wide and Deep能夠減少特征工程的部分工作,wide部分類似FM建模一、二階特征間關(guān)系, 算是NN和FM的一個(gè)更***的結(jié)合方向,另外不同的是如下圖,DeepFM的wide和deep部分共享embedding向量空間,wide和deep均可以更新embedding部分,雖說(shuō)wide部分純是PNN的工作,但感覺(jué)還是蠻有意思的。

 

 

本文相關(guān)代碼部分都是來(lái)自于paddlepaddle/model, 我這里走一遍流程,學(xué)習(xí)下,另外想要了解算法原理的可以仔細(xì)再看看上面的文章,今天我們來(lái)paddlepaddle上做下實(shí)驗(yàn),來(lái)從代碼程度學(xué)習(xí)下DeepFM怎么實(shí)現(xiàn)的:

數(shù)據(jù)集說(shuō)明

criteo Display Advertising Challenge,數(shù)據(jù)主要來(lái)criteolab一周的業(yè)務(wù)數(shù)據(jù),用來(lái)預(yù)測(cè)用戶在訪問(wèn)頁(yè)面時(shí),是否會(huì)點(diǎn)擊某廣告。

wget --no-check-certificate https://s3-eu-west-1.amazonaws.com/criteo-labs/dac.tar.gz
tar zxf dac.tar.gz
rm -f dac.tar.gz

mkdir raw
mv ./*.txt raw/

數(shù)據(jù)有點(diǎn)大, 大概4.26G,慢慢等吧,數(shù)據(jù)下載完成之后,解壓出train.csv,test.csv,其中訓(xùn)練集45840617條樣本數(shù),測(cè)試集45840617條樣本,數(shù)據(jù)量還是蠻大的。 數(shù)據(jù)主要有三部分組成:

  • label: 廣告是否被點(diǎn)擊;
  • 連續(xù)性特征: 1-13,為各維度下的統(tǒng)計(jì)信息,連續(xù)性特征;
  • 離散型特征:一些被脫敏處理的類目特征

Overview

整個(gè)項(xiàng)目主要由幾個(gè)部分組成:

 

 

數(shù)據(jù)處理

這里數(shù)據(jù)處理主要包括兩個(gè)部分:

  1. 連續(xù)值特征值處理:
  • 濾除統(tǒng)計(jì)次數(shù)95%以上的數(shù)據(jù),這樣可以濾除大部分異值數(shù)據(jù),這里的處理方式和以前我在1號(hào)店做相關(guān)工作時(shí)一致,代碼里面已經(jīng)做了這部分工作,直接給出了這部分的特征閾值;
  • 歸一化處理,這里andnew ng的課程有張圖很明顯,表明不同的特征的值域范圍,會(huì)使得模型尋優(yōu)走『之』字形,這樣會(huì)增加收斂的計(jì)算和時(shí)間;

 

  1. 離散特征值處理:
  • one-hot: 對(duì)應(yīng)特征值映射到指定維度的只有一個(gè)值為1的稀疏變量;
  • embedding: 對(duì)應(yīng)特征值映射到指定的特征維度上;

具體我們來(lái)研究下代碼:

class ContinuousFeatureGenerator:
    """
    Normalize the integer features to [0, 1] by min-max normalization
    """

    def __init__(self, num_feature):
        self.num_feature = num_feature
        self.min = [sys.maxint] * num_feature
        self.max = [-sys.maxint] * num_feature

    def build(self, datafile, continous_features):
        with open(datafile, 'r') as f:
            for line in f:
                features = line.rstrip('\n').split('\t')
                for i in range(0, self.num_feature):
                    val = features[continous_features[i]]
                    if val != '':
                        val = int(val)
                        if val > continous_clip[i]:
                            val = continous_clip[i]
                        self.min[i] = min(self.min[i], val)
                        self.max[i] = max(self.max[i], val)

    def gen(self, idx, val):
        if val == '':
            return 0.0
        val = float(val)
        return (val - self.min[idx]) / (self.max[idx] - self.min[idx])

 

連續(xù)特征是在1-13的位置,讀取文件,如果值大于對(duì)應(yīng)維度的特征值的95%閾值,則該特征值置為該閾值,并計(jì)算特征維度的***、最小值,在gen時(shí)歸一化處理。

class CategoryDictGenerator:
    """
    Generate dictionary for each of the categorical features
    """

    def __init__(self, num_feature):
        self.dicts = []
        self.num_feature = num_feature
        for i in range(0, num_feature):
            self.dicts.append(collections.defaultdict(int))

    def build(self, datafile, categorial_features, cutoff=0):
        with open(datafile, 'r') as f:
            for line in f:
                features = line.rstrip('\n').split('\t')
                for i in range(0, self.num_feature):
                    if features[categorial_features[i]] != '':
                        self.dicts[i][features[categorial_features[i]]] += 1
        for i in range(0, self.num_feature):
            self.dicts[i] = filter(lambda x: x[1] >= cutoff,
                                self.dicts[i].items())
            self.dicts[i] = sorted(self.dicts[i], key=lambda x: (-x[1], x[0]))
            vocabs, _ = list(zip(*self.dicts[i]))
            self.dicts[i] = dict(zip(vocabs, range(1, len(vocabs) + 1)))
            self.dicts[i]['<unk>'] = 0

    def gen(self, idx, key):
        if key not in self.dicts[idx]:
            res = self.dicts[idx]['<unk>']
        else:
            res = self.dicts[idx][key]
        return res

    def dicts_sizes(self):
        return map(len, self.dicts)

類目特征的處理相對(duì)比較麻煩,需要遍歷,然后得到對(duì)應(yīng)維度上所有出現(xiàn)值的所有情況,對(duì)打上對(duì)應(yīng)id,為后續(xù)類目特征賦予id。這部分耗時(shí)好大,慢慢等吧,另外強(qiáng)烈希望paddlepaddle的小伙伴能在輸出處理期間打印下提示信息,算了,我之后有時(shí)間看看能不能提提pr。

經(jīng)過(guò)上面的特征處理之后,訓(xùn)練集的值變?yōu)椋?/p>

 

 

reader

paddle里面reader的文件,自由度很高,自己可以寫(xiě)生成器,然后使用batch的api,完成向網(wǎng)絡(luò)傳入batchsize大小的數(shù)據(jù):

class Dataset:
    def _reader_creator(self, path, is_infer):
        def reader():
            with open(path, 'r') as f:
                for line in f:
                    features = line.rstrip('\n').split('\t')
                    dense_feature = map(float, features[0].split(','))
                    sparse_feature = map(int, features[1].split(','))
                    if not is_infer:
                        label = [float(features[2])]
                        yield [dense_feature, sparse_feature
                            ] + sparse_feature + [label]
                    else:
                        yield [dense_feature, sparse_feature] + sparse_feature

        return reader

    def train(self, path):
        return self._reader_creator(path, False)

    def test(self, path):
        return self._reader_creator(path, False)

    def infer(self, path):
        return self._reader_creator(path, True)

主要邏輯在兌入文件,然后yield對(duì)應(yīng)的網(wǎng)絡(luò)數(shù)據(jù)的輸入格式

模型構(gòu)造

模型構(gòu)造,DeepFM在paddlepaddle里面比較簡(jiǎn)單,因?yàn)橛袑iT(mén)的fm層,這個(gè)據(jù)我所知在TensorFlow或MXNet里面沒(méi)有專門(mén)的fm層,但是值得注意的是,在paddlepaddle里面的fm層,只建模二階關(guān)系,需要再加入fc才是完整的fm,實(shí)現(xiàn)代碼如下:

def fm_layer(input, factor_size, fm_param_attr):
    first_order = paddle.layer.fc(
        input=input, size=1, act=paddle.activation.Linear())
    second_order = paddle.layer.factorization_machine(
        input=input,
        factor_size=factor_size,
        act=paddle.activation.Linear(),
        param_attr=fm_param_attr)
    out = paddle.layer.addto(
        input=[first_order, second_order],
        act=paddle.activation.Linear(),
        bias_attr=False)
    return out

然后就是構(gòu)造DeepFM,這里根據(jù)下面的代碼畫(huà)出前面的圖,除去數(shù)據(jù)處理的部分,就是DeepFM的網(wǎng)絡(luò)結(jié)構(gòu):

def DeepFM(factor_size, infer=False):
    dense_input = paddle.layer.data(
        name="dense_input",
        type=paddle.data_type.dense_vector(dense_feature_dim))
    sparse_input = paddle.layer.data(
        name="sparse_input",
        type=paddle.data_type.sparse_binary_vector(sparse_feature_dim))
    sparse_input_ids = [
        paddle.layer.data(
            name="C" + str(i),
            type=s(sparse_feature_dim))
        for i in range(1, 27)
    ]
    dense_fm = fm_layer(
        dense_input,
        factor_size,
        fm_param_attr=paddle.attr.Param(name="DenseFeatFactors"))
    sparse_fm = fm_layer(
        sparse_input,
        factor_size,
        fm_param_attr=paddle.attr.Param(name="SparseFeatFactors"))
    def embedding_layer(input):
        return paddle.layer.embedding(
            input=input,
            size=factor_size,
            param_attr=paddle.attr.Param(name="SparseFeatFactors"))
    sparse_embed_seq = map(embedding_layer, sparse_input_ids)
    sparse_embed = paddle.layer.concat(sparse_embed_seq)

    fc1 = paddle.layer.fc(
        input=[sparse_embed, dense_input],
        size=400,
        act=paddle.activation.Relu())
    fc2 = paddle.layer.fc(input=fc1, size=400, act=paddle.activation.Relu())
    fc3 = paddle.layer.fc(input=fc2, size=400,            act=paddle.activation.Relu())

    predict = paddle.layer.fc(
        input=[dense_fm, sparse_fm, fc3],
        size=1,
        act=paddle.activation.Sigmoid())

    if not infer:
        label = paddle.layer.data(
            name="label", type=paddle.data_type.dense_vector(1))
        cost = paddle.layer.multi_binary_label_cross_entropy_cost(
            input=predict, label=label)
        paddle.evaluator.classification_error(
            name="classification_error", input=predict, label=label)
        paddle.evaluator.auc(name="auc", input=predict, label=label) 
        return cost
    else:
        return predict

其中,主要包括三個(gè)部分,一個(gè)是多個(gè)fc組成的deep部分,第二個(gè)是sparse fm部分,然后是dense fm部分,如圖:

 

 

這里蠻簡(jiǎn)單的,具體的api去查下文檔就可以了,這里稍微說(shuō)明一下的是,sparse feature這塊有兩部分一塊是embedding的處理,這里是先生成對(duì)應(yīng)的id,然后用id來(lái)做embedding,用作后面fc的輸出,然后sparse_input是onehot表示用來(lái)作為fm的輸出,fm來(lái)計(jì)算一階和二階隱變量關(guān)系。

模型訓(xùn)練

數(shù)據(jù)量太大,單機(jī)上跑是沒(méi)有問(wèn)題,可以正常運(yùn)行成功,在我內(nèi)部機(jī)器上,可以運(yùn)行成功,但是有兩個(gè)問(wèn)題:

  1. fm由于處理的特征為稀疏表示,而paddlepaddle在這塊的FM層的支持只有在cpu上,速度很慢,分析原因其實(shí)不是fm的速度的問(wèn)題,因?yàn)閐eepfm有設(shè)計(jì)多個(gè)fc,應(yīng)該是這里的速度影響, 在paddlepaddle github上有提一個(gè)issue,得知暫時(shí)paddlepaddle不能把部分放到gpu上面跑,給了一個(gè)解決方案把所有的sparse改成dense,發(fā)現(xiàn)在這里gpu顯存hold不住;
  2. 我的機(jī)器太渣,因?yàn)橛虚_(kāi)發(fā)任務(wù)不能長(zhǎng)期占用;

所以綜上,我打算研究下在百度云上怎么通過(guò)k8s來(lái)布置paddlepaddle的分布式集群。

文檔https://cloud.baidu.com/doc/CCE/GettingStarted.html#.E9.85.8D.E7.BD.AEpaddlecloud

研究來(lái)研究去,***步加卡主了,不知道怎么回事,那個(gè)頁(yè)面就是出不來(lái)...出師未捷身先死,提了個(gè)issue: https://github.com/PaddlePaddle/cloud/issues/542,等后面解決了再來(lái)更新分布式訓(xùn)練的部分。

單機(jī)的訓(xùn)練沒(méi)有什么大的問(wèn)題,由上面所說(shuō),因?yàn)閒m的sparse不支持gpu,所以很慢,拉的百度云上16核的機(jī)器,大概36s/100 batch,總共樣本4000多w,一個(gè)epoch預(yù)計(jì)4個(gè)小時(shí),MMP,等吧,分布式的必要性就在這里。

另外有在paddlepaddle里面提一個(gè)issue:

https://github.com/PaddlePaddle/Paddle/issues/7010,說(shuō)把sparse轉(zhuǎn)成dense的話可以直接在gpu上跑起來(lái),這個(gè)看起來(lái)不值得去嘗試,sparse整個(gè)維度還是挺高的,期待對(duì)sparse op 有更好的解決方案,更期待在能夠把單層單層的放在gpu,多設(shè)備一起跑,這方面,TensorFlow和MXNet要好太多。

這里我遇到一個(gè)問(wèn)題,我使用paddle的docker鏡像的時(shí)候,可以很穩(wěn)定的占用16個(gè)cpu的大部分計(jì)算力,但是我在云主機(jī)上自己裝的時(shí)候,cpu占用率很低,可能是和我環(huán)境配置有點(diǎn)問(wèn)題,這個(gè)問(wèn)題不大,之后為了不污染環(huán)境主要用docker來(lái)做相關(guān)的開(kāi)發(fā)工作,所以這里問(wèn)題不大。

cpu占有率有比較明顯的跳動(dòng),這里從主觀上比TensorFlow穩(wěn)定性要差一些,不排除是sparse op的影響,印象中,TensorFlow cpu的占用率很穩(wěn)定。

 

 

到發(fā)這篇文章位置,跑到17300個(gè)batch,基本能達(dá)到auc為0.8左右,loss為0.208左右。

預(yù)測(cè)

預(yù)測(cè)代碼和前一篇將paddle里面的demo一樣,只需要,重新定義一下網(wǎng)絡(luò),然后綁定好模型訓(xùn)練得到的參數(shù),然后傳入數(shù)據(jù)即可完成inference,paddle,有專門(mén)的Inference接口,只要傳入output_layer,和訓(xùn)練學(xué)習(xí)到的parameters,就可以很容易的新建一個(gè)模型的前向inference網(wǎng)絡(luò)。

def infer():
    args = parse_args()
    paddle.init(use_gpu=False, trainer_count=1)
    model = DeepFM(args.factor_size, infer=True)
    parameters = paddle.parameters.Parameters.from_tar(
        gzip.open(args.model_gz_path, 'r'))
    inferer = paddle.inference.Inference(
        output_layer=model, parameters=parameters)
    dataset = reader.Dataset()
    infer_reader = paddle.batch(dataset.infer(args.data_path),  batch_size=1000)
    with open(args.prediction_output_path, 'w') as out:
        for id, batch in enumerate(infer_reader()):
            res = inferer.infer(input=batch)
            predictions = [x for x in itertools.chain.from_iterable(res)]
            out.write('\n'.join(map(str, predictions)) + '\n')

總結(jié)

照例總結(jié)一下,DeemFM是17年深度學(xué)習(xí)在點(diǎn)擊率預(yù)估、推薦這塊的新的方法,有點(diǎn)類似于deep and wide的思想,將傳統(tǒng)的fm來(lái)nn化,利用神經(jīng)網(wǎng)絡(luò)強(qiáng)大的建模能力來(lái)挖掘數(shù)據(jù)中的有效信息,paddlepaddle在這塊有現(xiàn)成的deepfm模型,單機(jī)部署起來(lái)比較容易,分布式,這里我按照百度云上的教程還未成功,后續(xù)會(huì)持續(xù)關(guān)注。另外,因?yàn)樽罱谧龃笠?guī)模機(jī)器學(xué)習(xí)框架相關(guān)的工作,越發(fā)覺(jué)得別說(shuō)成熟的,僅僅能夠work的框架就很不錯(cuò)了,而比較好用的如現(xiàn)在的TensorFlow\MXNet,開(kāi)發(fā)起來(lái)真的難上加難,以前光是做調(diào)包俠時(shí)沒(méi)有體驗(yàn),現(xiàn)在深入到這塊的工作時(shí),才知道其中的難度,也從另一個(gè)角度開(kāi)始審視現(xiàn)在的各種大規(guī)模機(jī)器學(xué)習(xí)框架,比如TensorFlow、MXNet,在深度學(xué)習(xí)的支持上,確實(shí)很棒,但是也有瓶頸,對(duì)于大規(guī)模海量的feature,尤其是sparse op的支持上,至少現(xiàn)在還未看到特別好的支持,就比如這里的FM,可能大家都會(huì)吐槽為啥這么慢,沒(méi)做框架之前,我也會(huì)吐槽,但是開(kāi)始接觸了一些的時(shí)候,才知道FM,主要focus在sparse相關(guān)的數(shù)據(jù)對(duì)象,而這部分?jǐn)?shù)據(jù)很難在gpu上完成比較高性能的計(jì)算,所以前面經(jīng)過(guò)paddle的開(kāi)發(fā)者解釋sparse相關(guān)的計(jì)算不支持gpu的時(shí)候,才感同身受,一個(gè)好的大規(guī)模機(jī)器學(xué)習(xí)框架必須要從不同目標(biāo)來(lái)評(píng)價(jià),如果需求是大規(guī)律數(shù)據(jù),那穩(wěn)定性、可擴(kuò)展性是重點(diǎn),如果是更多算法、模型的支持,可能現(xiàn)在的TensorFlow、MXNet才是標(biāo)桿,多么希望現(xiàn)在大規(guī)模機(jī)器學(xué)習(xí)框架能夠多元化的發(fā)展,有深度學(xué)習(xí)支持力度大的,也有傳統(tǒng)算法上,把數(shù)據(jù)量、訓(xùn)練規(guī)模、并行化加速并做到***的,這樣的發(fā)展才或許稱得上百花齊放,其實(shí)我們不需要太多不同長(zhǎng)相的TensorFlow、MXNet錘子,有時(shí)候我們就需要把鐮刀而已,希望大規(guī)模機(jī)器學(xué)習(xí)框架的發(fā)展,不應(yīng)該僅僅像TensorFlow、MXNet一樣,希望有一個(gè)專注把做大規(guī)模、大數(shù)據(jù)量、***并行化加速作為roadmap的新標(biāo)桿,加油。

責(zé)任編輯:張昂 來(lái)源: 知乎
相關(guān)推薦

2018-03-26 20:28:24

深度學(xué)習(xí)

2021-07-01 15:56:42

深度學(xué)習(xí)人工智能互聯(lián)網(wǎng)

2021-11-12 15:16:32

深度學(xué)習(xí)數(shù)據(jù)合成人工智能

2024-10-08 08:19:19

2011-06-20 15:55:14

SEO

2013-10-30 10:39:25

Banner

2016-11-22 19:54:56

點(diǎn)擊率預(yù)估推薦算法廣告

2017-05-23 14:00:26

機(jī)器學(xué)習(xí)編程技術(shù)計(jì)算模型

2017-05-08 23:02:56

敏捷學(xué)習(xí)GitHubissue

2016-12-28 15:19:22

大數(shù)據(jù)機(jī)器學(xué)習(xí)銷售預(yù)測(cè)

2009-09-28 10:40:28

.NET學(xué)習(xí)

2018-04-23 14:49:31

表征句子深度學(xué)習(xí)自然語(yǔ)言

2009-09-04 09:37:49

思科認(rèn)證CCNA學(xué)習(xí)方法

2016-09-30 15:33:02

集成學(xué)習(xí)機(jī)器學(xué)習(xí)算法

2018-09-06 11:25:46

機(jī)器學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)人工智能

2015-07-28 15:41:06

機(jī)器學(xué)習(xí)算法數(shù)據(jù)挖掘

2011-07-10 15:07:37

2017-11-27 15:24:02

Linux學(xué)習(xí)方法優(yōu)勢(shì)

2017-12-01 17:35:02

2023-11-21 09:32:17

深度學(xué)習(xí)人工智能
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)