Wide & Deep Learning for Recommender Systems(Google&Facebook推薦)
1、背景
文章提出的Wide&Deep模型,旨在使得訓練得到的模型能夠同時獲得記憶(memorization)和泛化(generization)能力:
- 記憶(體現(xiàn)準確性):即從歷史數(shù)據(jù)中發(fā)現(xiàn)item或者特征之間的相關性萨西;
- 泛化(體現(xiàn)新穎性):即相關性的傳遞承璃,發(fā)現(xiàn)在歷史數(shù)據(jù)中很少或者沒有出現(xiàn)的新的特征組合。
2、Wide&Deep模型
2.1丑罪、模型結構
在Wide&Deep模型中包括兩個部分传黄,分別為Wide和Deep部分杰扫,Wide部分如上圖中的左圖所示,Deep部分如上圖中的右圖所示膘掰。
2.2章姓、Wide模型
Memorization主要是學習特征的共性或者說相關性,產(chǎn)生的推薦是和已經(jīng)有用戶行為的物品直接相關的物品识埋。
用的模型是邏輯回歸(logistic regression, LR)凡伊,LR 的優(yōu)點就是簡單(simple)、容易規(guī)闹现郏化(scalable)系忙、可解釋性強(interpretable)。LR 的特征往往是二值且稀疏的(binary and sparse)惠豺,這里同樣采用 one-hot 編碼银还,如 “user_installed_app=netflix”,如果用戶安裝了 Netflix洁墙,這個特征的值為 1蛹疯,否則為 0。
為了達到 Memorization扫俺,我們對稀疏的特征采取 cross-product transformation苍苞,比如說 AND(user_installed_app=netflix, impression_app=pandora”) 這個特征,只有 Netflix 和 Pandora 兩個條件都達到了,值才為 1羹呵,這類 feature 解釋了 co-occurrence 和 target label 之間的關系骂际。一個 cross-product transformation 的局限在于,對于在訓練集里沒有出現(xiàn)過的 query-item pair冈欢,它不能進行泛化(Generalization)
Wide模型的輸入是用戶安裝應用(installation)和為用戶展示(impression)的應用間的向量積(叉乘)歉铝,模型通常訓練one-hot編碼后的二值特征,這種操作不會歸納出訓練集中未出現(xiàn)的特征對凑耻。
實際上太示,Wide模型是一個廣義線性模型:,其中特征是一個d維特征向量香浩,特征包括原始輸入特征以及cross-product transformation特征类缤。交叉積轉換為
為布爾變量,若第i個特征是第k個變換的一部分邻吭,值為1餐弱,否則為0。為模型參數(shù)囱晴。最終在y的基礎上增加Sigmoid函數(shù)作為最終的輸出膏蚓。
2.3、Deep模型
Generalization可以理解為相關性的傳遞(transitivity)畸写,會學習新的特征組合驮瞧,來提高推薦物品的多樣性,或者說提供泛化能力(Generalization)枯芬。
泛化往往是通過學習 low-dimensional dense embeddings 來探索過去從未或很少出現(xiàn)的新的特征組合來實現(xiàn)的论笔,通常的 embedding-based model 有 Factorization Machines(FM) 和 Deep Neural Networks(DNN)。特殊興趣或者小眾愛好的用戶破停,query-item matrix 非常稀疏翅楼,很難學習,然而 dense embedding 的方法還是可以得到對所有 query-item pair 非零的預測真慢,這就會導致 over-generalize毅臊,推薦不怎么相關的物品。這點和 LR 正好互補黑界,因為 LR 只能記住很少的特征組合管嬉。
為了達到 Generalization,文章引入新的小顆粒特征朗鸠,如類別特征(安裝了視頻類應用蚯撩,展示的是音樂類應用,等等)AND(user_installed_category=video, impression_category=music)烛占,這些高維稀疏的類別特征(如人口學特征和設備類別)映射為低緯稠密的向量后胎挎,與其他連續(xù)特征(用戶年齡沟启、應用安裝數(shù)等)拼接在一起,輸入 MLP 中犹菇,最后輸入邏輯輸出單元德迹。
Deep模型是一個前饋神經(jīng)網(wǎng)絡。深度神經(jīng)網(wǎng)絡模型通過需要的輸入是連續(xù)的稠密特征揭芍,對于稀疏胳搞、高維的類別特征,通常首先將其轉換為低維的向量称杨,這個過程也稱為embedding肌毅。
在訓練的時候首先隨機初始化embedding向量,并在模型的訓練過程中通過最小化損失函數(shù)來優(yōu)化模型姑原,逐漸修改該向量的值悬而,即將向量作為參數(shù)參與模型的訓練。
隱層的計算方法為:
其中页衙,f為激活函數(shù)摊滔,如ReLus。
基于embedding的深度模型的輸入是類別特征(生成embedding)+連續(xù)特征店乐。
2.4、Wide&Deep模型聯(lián)合訓練
聯(lián)合訓練是指同時訓練Wide模型和Deep模型呻袭,并將兩個模型的輸出算log odds ratio然后加權求和作為最終的預測結果:
聯(lián)合訓練和embedding方法是不同的眨八。embedding把不同的部分分開訓練,這個過程中不同的模型相互之間不知道彼此的存在左电,也不會互相影響廉侧。但在聯(lián)合訓練中,整個網(wǎng)絡同時被訓練篓足,梯度的反向傳播同時影響整個模型的所有部分段誊,使用mini-batch SGD來訓練模型。
訓練方法:
- Wide模型:FTRL 各大公司廣泛使用的在線學習算法FTRL詳解
其中栈拖,式中第一項是對損失函數(shù)的貢獻的一個估計连舍,第二項是控制w(也就是model)在每次迭代中變化不要太大,第三項代表L1正則(獲得稀疏解)涩哟,表示學習速率索赏。學習速率可以通過超參數(shù)自適應學習。贴彼,下角標表示第t次迭代潜腻,第i維特征,為超參數(shù)器仗。
https://blog.csdn.net/a819825294/article/details/51227265
https://blog.csdn.net/fangqingan_java/article/details/51020653 - Deep模型:AdaGrad
在一般的梯度下降法中融涣,對每一個參數(shù)的訓練都使用了相同的學習率α。Adagrad算法能夠在訓練中自動的對學習率進行調(diào)整,對于出現(xiàn)頻率較低參數(shù)采用較大的α更新威鹿;相反妓盲,對于出現(xiàn)頻率較高的參數(shù)采用較小的α更新。因此专普,Adagrad非常適合處理稀疏數(shù)據(jù)悯衬。
http://www.cnblogs.com/xianhan/p/9347523.html
https://blog.csdn.net/u012759136/article/details/52302426
3、apps的推薦系統(tǒng)
將上述Wide&Deep模型應用在Google play的apps推薦中檀夹。
3.1筋粗、 推薦系統(tǒng)
推薦系統(tǒng)的一般結構如下所示:
當一個用戶訪問App Store時,會產(chǎn)生一個請求炸渡,請求到達推薦系統(tǒng)后娜亿,推薦系統(tǒng)為該用戶返回推薦的apps列表。
在實際的推薦系統(tǒng)中蚌堵,通常將推薦的過程分為兩個部分买决,檢索系統(tǒng)(retrieval)和排序系統(tǒng)(ranking),retrieval從數(shù)據(jù)庫中檢索出與用戶相關的最匹配query的一些apps吼畏,這里的檢索通常會結合采用機器學習模型和人工定義規(guī)則兩種方法督赤。從大規(guī)模樣本中召回最佳候選集后,ranking負責對這些檢索出的apps打分泻蚊、排序躲舌,最終按照分數(shù)的高低返回相應的列表給用戶。分數(shù)P(y|x)性雄,y是用戶采取的行動(例如下載)没卸,x是特征包括:
- user features:eg, country, language, demographics
- contextual features: eg, device, hour of the day, day of the week
- impression features: eg, app age, historical statistics of an app
WDL就是用在排序系統(tǒng)中。
3.2秒旋、apps推薦的特征
模型的訓練之前约计,最重要的工作是訓練數(shù)據(jù)的準備以及特征的選擇,在apps推薦中迁筛,可使用到的數(shù)據(jù)包括用戶數(shù)據(jù)和曝光數(shù)據(jù)煤蚌,因此,每一條樣本對應了一條曝光數(shù)據(jù)瑰煎。樣本點標簽為1表示安裝铺然,0表示未安裝。
對于類別特征酒甸,通過詞典(vocabularies)將其映射成向量魄健;對于連續(xù)的實值特征,將其歸一化到區(qū)間[0,1]插勤。
3.3沽瘦、度量的標準
度量的指標有兩個革骨,分別針對在線的度量和離線的度量,在線時通過A/B test析恋,最終利用安裝率(acquisition)良哲;離線則使用AUC作為評價模型的指標。
4助隧、代碼介紹
數(shù)據(jù)源:UCI開源數(shù)據(jù)集Adult
針對美國某區(qū)域的一次人口普查結果筑凫,共32561條數(shù)據(jù),具體字段如下:
from __future__ import print_function
import tensorflow as tf
import tempfile
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
# Categorical base columns.構建低維離散特征
gender = tf.contrib.layers.sparse_column_with_keys(column_name="gender", keys=["Female", "Male"])
race = tf.contrib.layers.sparse_column_with_keys(column_name="race", keys=["Amer-Indian-Eskimo", "Asian-Pac-Islander", "Black", "Other", "White"])
education = tf.contrib.layers.sparse_column_with_hash_bucket("education", hash_bucket_size=1000)
relationship = tf.contrib.layers.sparse_column_with_hash_bucket("relationship", hash_bucket_size=100)
workclass = tf.contrib.layers.sparse_column_with_hash_bucket("workclass", hash_bucket_size=100)
occupation = tf.contrib.layers.sparse_column_with_hash_bucket("occupation", hash_bucket_size=1000)
native_country = tf.contrib.layers.sparse_column_with_hash_bucket("native_country", hash_bucket_size=1000)
# Continuous base columns.
age = tf.contrib.layers.real_valued_column("age")#構建連續(xù)型實數(shù)特征
age_buckets = tf.contrib.layers.bucketized_column(age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])
education_num = tf.contrib.layers.real_valued_column("education_num")
capital_gain = tf.contrib.layers.real_valued_column("capital_gain")
capital_loss = tf.contrib.layers.real_valued_column("capital_loss")
hours_per_week = tf.contrib.layers.real_valued_column("hours_per_week")
wide_columns = [
gender, native_country, education, occupation, workclass, relationship, age_buckets,
#構建離散組合特征
tf.contrib.layers.crossed_column([education, occupation], hash_bucket_size=int(1e4)),
tf.contrib.layers.crossed_column([native_country, occupation], hash_bucket_size=int(1e4)),
tf.contrib.layers.crossed_column([age_buckets, education, occupation], hash_bucket_size=int(1e6))]
deep_columns = [
#構建embedding特征
tf.contrib.layers.embedding_column(workclass, dimension=8),
tf.contrib.layers.embedding_column(education, dimension=8),
tf.contrib.layers.embedding_column(gender, dimension=8),
tf.contrib.layers.embedding_column(relationship, dimension=8),
tf.contrib.layers.embedding_column(native_country, dimension=8),
tf.contrib.layers.embedding_column(occupation, dimension=8),
age, education_num, capital_gain, capital_loss, hours_per_week]
model_dir = tempfile.mkdtemp()
'''
定義分類模型
n_classes// 分類數(shù)目并村,默認是二分類巍实,>2進行多分類 ;weight_column_name // 訓練實例的權重哩牍;
linear_optimizer = tf.train.FtrlOptimizer( ...) // 線性模型權重更新的optimizer棚潦;
dnn_optimizer=tf.train.AdagradOptimizer( ...) // DNN模型權重更新的optimizer
'''
m = tf.contrib.learn.DNNLinearCombinedClassifier(
model_dir=model_dir,#模型目錄
linear_feature_columns=wide_columns,#輸入線性模型的feature columns
dnn_feature_columns=deep_columns,#輸入DNN模型的feature columns
dnn_hidden_units=[100, 50])#DNN模型隱層單元數(shù)
# Define the column names for the data sets.
COLUMNS = ["age", "workclass", "fnlwgt", "education", "education_num",
"marital_status", "occupation", "relationship", "race", "gender",
"capital_gain", "capital_loss", "hours_per_week", "native_country", "income_bracket"]
LABEL_COLUMN = 'label'
CATEGORICAL_COLUMNS = ["workclass", "education", "marital_status", "occupation",
"relationship", "race", "gender", "native_country"]
CONTINUOUS_COLUMNS = ["age", "education_num", "capital_gain", "capital_loss",
"hours_per_week"]
# Download the training and test data to temporary files.
# Alternatively, you can download them yourself and change train_file and
# test_file to your own paths.
#train_file = tempfile.NamedTemporaryFile()
#test_file = tempfile.NamedTemporaryFile()
#urllib.request.urlretrieve("http://mlr.cs.umass.edu/ml/machine-learning-databases/adult/adult.data", train_file.name)
#urllib.request.urlretrieve("http://mlr.cs.umass.edu/ml/machine-learning-databases/adult/adult.test", test_file.name)
# Read the training and test data sets into Pandas dataframe.
df_train = pd.read_csv('F:/method codes/adult.data.csv', names=COLUMNS, skipinitialspace=True)
df_test = pd.read_csv('F:/method codes/adult.test.csv', names=COLUMNS, skipinitialspace=True, skiprows=1)
df_train[LABEL_COLUMN] = (df_train['income_bracket'].apply(lambda x: '>50K' in x)).astype(int)
df_test[LABEL_COLUMN] = (df_test['income_bracket'].apply(lambda x: '>50K' in x)).astype(int)
def input_fn(df):#定義如何從輸入的dataframe構建特征和標記:
# Creates a dictionary mapping from each continuous feature column name (k) to
# the values of that column stored in a constant Tensor.
'''
tf.constant構建constant tensor,df[k].values是對應feature column的值構成的list
'''
continuous_cols = {k: tf.constant(df[k].values)
for k in CONTINUOUS_COLUMNS}
# Creates a dictionary mapping from each categorical feature column name (k)
# to the values of that column stored in a tf.SparseTensor.
#tf.SparseTensor構建sparse tensor膝昆,SparseTensor由indices,values, dense_shape三個dense tensor構成丸边,
#indices中記錄非零元素在sparse tensor的位置,values是indices中每個位置的元素的值荚孵,dense_shape指定
#sparse tensor中每個維度的大小妹窖。
'''
以下代碼為每個category column構建一個[df[k].size,1]的二維的SparseTensor处窥。
'''
categorical_cols = {k: tf.SparseTensor(
indices=[[i, 0] for i in range(df[k].size)],
values=df[k].values,
dense_shape=[df[k].size, 1])
for k in CATEGORICAL_COLUMNS}
# Merges the two dictionaries into one.
'''
用以下示意圖來表示以上代碼構建的sparse tensor label是一個 constant tensor嘱吗,記錄每個實例的 label
'''
feature_cols = dict(list(continuous_cols.items()) + list(categorical_cols.items()))
# features是continuous_cols和categorical_cols的union構成的dict
# dict中每個entry的key是feature column的name,value是feature column值的tensor
# Converts the label column into a constant Tensor.
label = tf.constant(df[LABEL_COLUMN].values)
# Returns the feature columns and the label.
return feature_cols, label
def train_input_fn():
return input_fn(df_train)
def eval_input_fn():
return input_fn(df_test)
print('df_train shape:',np.array(df_train).shape)
print('df_test shape:',np.array(df_test).shape)
m.fit(input_fn=train_input_fn, steps=200)#訓練模型
results = m.evaluate(input_fn=eval_input_fn, steps=1)#模型評測
for key in sorted(results):
print("%s: %s" % (key, results[key]))
#https://blog.csdn.net/a819825294/article/details/71080472
#https://www.sohu.com/a/190148302_115128
參考資料:http://www.reibang.com/p/28a1849f6707
https://blog.csdn.net/google19890102/article/details/78171283