推薦系統遇上深度學習(十七)--探祕阿里之MLR演算法淺析及實現

weixin_33866037發表於2018-06-23

阿里近幾年公開的推薦領域演算法可真不少,既有傳統領域的探索如MLR演算法,還有深度學習領域的探索如entire -space multi-task model,Deep Interest Network等,同時跟清華大學合作展開了強化學習領域的探索,提出了MARDPG演算法。從本篇開始,我們就一起來探祕這些演算法。這裡,我們只是大體瞭解一下每一個演算法的思路,對於數學部分的介紹,我們不會過多的涉及。

1、演算法介紹

現階段各CTR預估演算法的不足
我們這裡的現階段,不是指的今時今日,而是阿里剛剛公開此演算法的時間,大概就是去年的三四月份吧。

業界常用的CTR預估演算法的不足如下表所示:

方法 簡介 不足
邏輯迴歸 使用了Sigmoid函式將函式值對映到0~1區間作為CTR的預估值。LR這種線性模型很容易並行化,處理上億條訓練樣本不是問題。 線性模型的學習能力有限,需要引入大量的領域知識來人工設計特徵以及特徵之間的交叉組合來間接補充演算法的非線性學習能力,非常消耗人力和機器資源,遷移性不夠友好。
Kernel方法 將低維特徵對映到高維特徵空間 複雜度太高而不易實現
樹模型 如Facebook的GBDT+LR演算法,有效地解決了LR模型的特徵組合問題 是對歷史行為的記憶,缺乏推廣性,樹模型只能學習到歷史資料中的特定規則,對於新規則缺乏推廣性
FM模型 自動學習高階屬性的權值,不用通過人工的方式選取特徵來做交叉 FM模型只能擬合特定的非線性模式,常用的就是二階FM
深度神經網路 使用神經網路擬合資料之間的高階非線性關係,非線性擬合能力足夠強 適合資料規律的、具備推廣性的網路結構業界依然在探索中,尤其是要做到端到端規模化上線,這裡面的技術挑戰依然很大

那麼挑戰來了,如何設計演算法從大規模資料中挖掘出具有推廣性的非線性模式?

MLR演算法

2011-2012年期間,阿里媽媽資深專家蓋坤創新性地提出了MLR(mixed logistic regression)演算法,引領了廣告領域CTR預估演算法的全新升級。MLR演算法創新地提出並實現了直接在原始空間學習特徵之間的非線性關係,基於資料自動發掘可推廣的模式,相比於人工來說效率和精度均有了大幅提升。

MLR可以看做是對LR的一個自然推廣,它採用分而治之的思路,用分片線性的模式來擬合高維空間的非線性分類面,其形式化表達如下:

4155986-d4572939999edaf3.png

其中u是聚類引數,決定了空間的劃分,w是分類引數,決定空間內的預測。這裡面超引數分片數m可以較好地平衡模型的擬合與推廣能力。當m=1時MLR就退化為普通的LR,m越大模型的擬合能力越強,但是模型引數規模隨m線性增長,相應所需的訓練樣本也隨之增長。因此實際應用中m需要根據實際情況進行選擇。例如,在阿里的場景中,m一般選擇為12。下圖中MLR模型用4個分片可以完美地擬合出資料中的菱形分類面。

4155986-d9da3d968a2fdc1c.png

在實際中,MLR演算法常用的形式如下,使用softmax作為分片函式:

4155986-ab8a627ded650751.png

在這種情況下,MLR模型可以看作是一個FOE model:

4155986-c217d227121fa10c.png

關於損失函式的設計,阿里採用了 neg-likelihood loss function以及L1,L2正則,形式如下:

4155986-65a604bb693beebf.png

由於加入了正則項,MLR演算法變的不再是平滑的凸函式,梯度下降法不再適用,因此模型引數的更新使用LBFGS和OWLQN的結合,具體的優化細節大家可以參考論文(https://arxiv.org/pdf/1704.05194.pdf).

MLR演算法適合於工業級的大規模稀疏資料場景問題,如廣告CTR預估。背後的優勢體現在兩個方面:
端到端的非線性學習:從模型端自動挖掘資料中蘊藏的非線性模式,省去了大量的人工特徵設計,這 使得MLR演算法可以端到端地完成訓練,在不同場景中的遷移和應用非常輕鬆。
稀疏性:MLR在建模時引入了L1和L2,1範數正則,可以使得最終訓練出來的模型具有較高的稀疏度, 模型的學習和線上預測效能更好。當然,這也對演算法的優化求解帶來了巨大的挑戰。

2、演算法簡單實現

我們這裡只是簡單實現一個tensorflow版本的MLR模型,通過程式碼來了解一下模型的思想。

程式碼的github地址為:https://github.com/princewen/tensorflow_practice/tree/master/recommendation/Basic-MLR-Demo

所使用的資料下載地址為:http://archive.ics.uci.edu/ml/datasets/Adult,該資料是一個二分類的資料,所預測的任務是判斷一個人是否能夠一年掙到50K的錢,資料介紹如下:

4155986-8ee65bfd7a611be0.png

資料處理

資料中存在連續特徵和離散特徵,所以我們先要對資料進行一個簡單的處理,處理包括將離散特徵轉換為one-hot以及對連續特徵進行標準化。有一個需要注意的地方,訓練集和測試集中離散特徵出現的個數可能不一樣,因此需要先將資料合併,然後轉換成one-hot,最後再分開,程式碼如下。

import pandas as pd
from sklearn.preprocessing import StandardScaler

def get_data():
    train_data = pd.read_table("data/adult.data.txt",header=None,delimiter=',')
    test_data = pd.read_table("data/adult.test.txt",header=None,delimiter=',')

    all_columns = ['age','workclass','fnlwgt','education','education-num',
                        'marital-status','occupation','relationship','race','sex',
                        'capital-gain','capital-loss','hours-per-week','native-country','label','type']

    continus_columns = ['age','fnlwgt','education-num','capital-gain','capital-loss','hours-per-week']
    dummy_columns = ['workclass','education','marital-status','occupation','relationship','race','sex','native-country']

    train_data['type'] = 1
    test_data['type'] = 2

    all_data = pd.concat([train_data,test_data],axis=0)
    all_data.columns = all_columns

    all_data = pd.get_dummies(all_data,columns=dummy_columns)
    test_data = all_data[all_data['type']==2].drop(['type'],axis=1)
    train_data = all_data[all_data['type']==1].drop(['type'],axis=1)

    train_data['label'] = train_data['label'].map(lambda x: 1 if x.strip() == '>50K' else 0)
    test_data['label'] = test_data['label'].map(lambda x: 1 if x.strip() == '>50K.' else 0)

    for col in continus_columns:
        ss = StandardScaler()
        train_data[col] = ss.fit_transform(train_data[[col]])
        test_data[col] = ss.transform(test_data[[col]])

    train_y = train_data['label']
    train_x = train_data.drop(['label'],axis=1)
    test_y = test_data['label']
    test_x = test_data.drop(['label'],axis=1)

    return train_x,train_y,test_x,test_y

資料處理完後,特徵的維度是108維。

MLR的實現

MLR的實現需要兩組引數,分別是聚類引數和分類引數:

u = tf.Variable(tf.random_normal([108,m],0.0,0.5),name='u')
w = tf.Variable(tf.random_normal([108,m],0.0,0.5),name='w')

隨後,我們要計算我們的預估值:

U = tf.matmul(x,u)
p1 = tf.nn.softmax(U)

W = tf.matmul(x,w)
p2 = tf.nn.sigmoid(W)

pred = tf.reduce_sum(tf.multiply(p1,p2),1)

損失函式我們剛才介紹過了,在tensorflow中,我們選擇FtrlOptimizer作為優化器,可以給我們的損失函式加上正則項:

cost1=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=pred, labels=y))
cost=tf.add_n([cost1])
train_op = tf.train.FtrlOptimizer(learning_rate).minimize(cost)

隨後,我們就可以進行試驗了。

實驗結果
本文對比了在當前給出的資料集下,m=5,10,15,25 以及lr演算法的效果,結果如下:

4155986-236632a5e412a2bb.png
4155986-5fd20cafb4a3fef7.png

可以看到,lr的效果是最好的,隨著m的增加,模型的效果越來越差。當然,這並不能說明mlr效果不如lr好,只是我們的資料實在是太少了,哈哈。

參考文獻

1、https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247485097&idx=1&sn=6dbc197e67e8a2ba3ee78786b13d894d&scene=21#wechat_redirect
2、Learning Piece-wise Linear Models
from Large Scale Data for Ad Click Prediction

歡迎關注個人公眾號:小小挖掘機

4155986-2a82a353433e8a07.png

新增微信sxw2251,可以拉你進入小小挖掘機技術交流群喲!

相關文章