模型解决问题
因为DeepFM模型基本是在Wide&deep的基础上进行改进而来,所有DeepFM主要解决的问题是:
1、Wide&deep 模型需要手动做特征交叉,而DeepFM因为有FM层进行一阶和二阶特征自动组合,所以不需要手动特征工程
2、FM 模块和 Deep 模块共享 Feature Embedding 部分,可以更快的训练,以及更精确的训练学习
3、能同时学习低阶和高阶的组合特征
模型原理
下面分析原理的过程中结合ChenglongChen的代码进行分析,感谢作者提供了如此完善的代码实现~
数据预处理
因为下文中模型部分用到feat_index, feat_value两个关键变量,故先说明下数据预处理的步骤
-
feat_index中:
1、如果特征是一个数值特征,所有sample的这个特征都是一个值
2、如果特征是一个类别特征,每个类别特征值是一个独立的值 -
feat_value中:
1、如果特征是一个数值特征,保留原值
2、如果特征是一个类别特征,特征值设置为1
# 生成特征列字典
def gen_feat_dict(self):
if self.dfTrain is None:
dfTrain = pd.read_csv(self.trainfile)
else:
dfTrain = self.dfTrain
if self.dfTest is None:
dfTest = pd.read_csv(self.testfile)
else:
dfTest = self.dfTest
df = pd.concat([dfTrain, dfTest])
self.feat_dict = {
}
tc = 0
for col in df.columns:
if col in self.ignore_cols:
continue
if col in self.numeric_cols:
# map to a single index
self.feat_dict[col] = tc
tc += 1
else:
us = df[col].unique()
self.feat_dict[col] = dict(zip(us, range(tc, len(us)+tc)))
tc += len(us)
self.feat_dim = tc
# 根据特征列字典,对数据进行编码
dfv = dfi.copy()
for col in dfi.columns:
if col in self.feat_dict.ignore_cols:
dfi.drop(col, axis=1, inplace=True)
dfv.drop(col, axis=1, inplace=True)
continue
if col in self.feat_dict.numeric_cols:
dfi[col] = self.feat_dict.feat_dict[col]
else:
dfi[col] = dfi[col].map(self.feat_dict.feat_dict[col])
dfv[col] = 1
EMbedding层
FM层同Deep层共享相同的EMbedding,优点:
- 训练更快:同wide&deep相比,wide&deep中wide层和deep层分别对特征进行处理,输入特征维度很大;同时wide中包含大量人工设计的组合特征,权重参数多,计算复杂度大
- 从论文结果看,训练结果更加准确
"""
理解
feat_index维度: [None, field_size] 这里传入的是sample的feature编码
self.weights中feature_embeddings维度:[feature_size, embedding_size]
Embedding实际等于tf.gather,返回维度为None * field_size * embedding_size
filed_size: 每一个特征
embedding_size: 每一个特征embedding后的向量, 针对数据特征来说,所有sample数值特征embedding后完全相同,对sample之间差异没有影响
"""
self.embeddings = tf.nn.embedding_lookup(self.weights["feature_embeddings"],
self.feat_index) # None * F * K
# feat_value = [None * F] => 将二维tensor转化为三位tensor
feat_value = tf.reshape(self.feat_value, shape=[-1, self.field_size, 1])
# feature_value中类别特征为1,此时类别特征即为Embedding weights中的向量
self.embeddings = tf.multiply(self.embeddings, feat_value)
FM层
y F M = < w , x > + ∑ i n ∑ j = i + 1 n < v i , v j > x i x j x i , x j 为 特 征 值 v i , v j 为 特 征