调参工程师的日常

近期调参感受:

  1. 在实际项目中数据和特征对最终的效果贡献是最大的,所以要花时间打造你的数据流,花时间多想一些特征,特征要算准。
  2. word2vec、FFM、XgBoost这些算法之所以能得到业界公认,是因为他们在各种数据集上都表现良好,而且对参数不太敏感。

试验总结:

  1. FFM优于FM,FM优于LR。
  2. XGBoost和LightGBM效果几乎接近,比上述线性模型(多项式模型)好很多,LightGBM训练速度比XGBoost快。
  3. 利用LightGBM产生组合特征,再过一层LR/FM/FFM,效果并没有超越单纯的LightGBM。

word2vec

from gensim.models import Word2Vec
model = Word2Vec(sentences,
                     size=100,  # 特征向量的维度,比200好
                     window=5,  # 前后各取5个词作为context,增到8效果没有好转
                     min_count=20,  # 出现次数低于该频率的词直接忽略掉
                     iter=150,  # 迭代次数
                     hs=0,  # hs=1表示hierarchical softmax。负采样比hierarchical softmax效果好
                     negative=10,  # 如果要采用负采样,negative表示负采样时背景噪声词的个数。改为20后效果并没有好转
                     workers=8,  # 并行数
                     sample=1e-4,  # 对高频词进行下采样,通常取值在(0,1e-5)。调参结果见下表
                ) 

可见下采样参数sample还是很重要的,由1e-3降为1e-4后,<数据挖掘,机器学习>和<机器学习,深度学习>的相似度得到了明显改善。

有2个用户,他们的标签分别是【java|工程师|python|机器学习|模式识别|算法】、【研究生|机器学习|硕士|it研发】,我们有每个词的word2vec向量,现在要计算2个词集的相似度,有3各方法:

  1. 各词向量取average。考虑了每个词的信息
  2. 各词向量取max。考虑最显著特征信息(比较注重关键词,忽略平常词)
  3. average的max拼接起来

 

max法重点强调了“机器学习”这个关键词,得到的相似度比较高。方法3是前2种方法的中和。此处参考基线系统需要受到更多关注:基于词向量的简单模型 | ACL 2018论文解读

XGBoost LightGBM

import xgboost
params = {
    'booster': 'gbtree',    #单个booster是采用线性模型还是树模型
    'objective': 'binary:logistic', #目标函数
    'eta': 0.01,  # 每个booster设置相同的学习率
    'gamma': 0.1,  # 对叶节点个数的惩罚系数
    'lambda': 2,  # L2正则化项系数,控制叶节点的输出值
    'max_depth': 15,
    'subsample': 0.7,  # 行采样。是否进行行采样对效果没什么影响
    'colsample_bytree': 0.7,  # 列采样。不进行列采样效果会差一点
    'min_child_weight': 10,  # 叶节点最少样本数
    'silent': 0,  # 设置成1则没有运行信息输出,最好是设置为0.
    'seed': 0,
    'eval_metric': 'logloss',
    'nthread': 8,  # 并行数
    'tree_method': 'exact',  # 在所有样本上遍历可能的分割点。计算量太大,默认使用的是approx,即只在分位点上尝试分割。exact比approx效果会好一点点
}
# num_boost_round:booster的个数,对于tree boost就是树的个数。每生成一棵树都会去调用一个callback,比如通过callback可以重置学习率[xgb.callback.reset_learning_rate(custom_rates)]
model = xgboost.train(params.items(), train_data, num_boost_round=300, callbacks=[])

使用列采样技巧后,AUC提升了1个点,其他参数对AUC影响不大。

import lightgbm
params = {
    'task': 'train',
    'boosting_type': 'dart',# gbdt:0.795695; GOSS:0.7917279;  dart:0.7985638; rf:0.714062
    'objective': 'binary',
    'metric': {'binary_logloss', 'auc'},
    'max_bin': 255,
    'num_leaves': 500,
    'min_data_in_leaf': 10,
    'num_iterations': 300,  # 300棵树
    'learning_rate': 0.2,  # 学习率太大,容易过拟合
    'feature_fraction': 0.7,  # 列采样比例

    # rf时使用,gbdt也可以使用
    # 'bagging_fraction': 0.7,  # 行采样比例,使用rf时这个比例必须小于1
    # 'bagging_freq': 5,  # 每隔几轮进行一次行采样

    # GOSS时使用
    # 'top_rate':0.3,
    # 'other_rate':0.3,

    # dart时使用
    'drop_rate':0.7,
    'skip_drop':0.7,
    'max_drop':5,
    'uniform_drop':False,
    'xgboost_dart_mode':True,
    'drop_seed':4,

    'verbose': 0,
    'num_threads': 8,
}
 gbm = lightgbm.train(params=params, train_set=train_data, valid_sets=test_data)

 

boosting_type效果对比:rf<gbdt<goss<dart。

学习率太大,容易过拟合。每轮迭代都打印训练集和测试集上的AUC,会发现learning_rate>0.2时,比如0.5、1.0,在训练集上的AUC会比较高,而在测试集上的AUC比较低,learning_rate为0.2时在测试集上的AUC是最高的。

LightGBM在100棵的时候,测试集上的AUC就已经到0.78了,后面的200棵树只是将AUC提升了1个点。

LightGBM由于是采样训练,效果比XGBoost稍差一点,但速度快,能快多少取决采样的比例,试验中LightGBM dart耗时是XGBoost的一半。

 

LightGBM+LR

用LightGBM根节点到每一个叶节点的路径作为一个组合特征,再输给LR去训练。LR拿到的特征数等于所有叶节点的个数,一棵树有500个叶节点,lightgbm有300棵树,那一共就有150000个叶节点,维度很高,但实际上一个样本在一棵树上只会命中一个叶节点,所以一个样本上非0的维度等于树的个数。试验中我们只取了LightGBM的前100棵树(别忘了LightGBM在100棵树的时候AUC是0.78)。另外这里选用LightGBM而不是XGBoost,是因为LightGBM是leaf-wise生长的,max leaf是可以控制的(实际上每棵树都可以达到max leaf),这样在给所有叶节点编号时简单一些,仅此而已,并不是说XGBoost效果不好。

还可以把LightGBM产生的组合特征与原始特征拼接起来,一同输给LR去训练。

 

看来LightGBM已把这些特征学习到极致了,即使LR拿到这些组合特征也学不到更好的效果。线性模型还是敌不过非线性模型。决策树得到的是特征组合,但还是在原先的特征空间内,而深度学习是创造了新的特征,超越了原始的特征空间。

LR FM FFM

import xlearn
ffm_model = xlearn.create_ffm()
ffm_model.setTrain(ffm_train_file)
ffm_model.setValidate(ffm_test_file)
params = {
    'task': 'binary',  # 二分类。也可以设为reg
    'lr': 0.2,  # 学习率。adagrad的学习率是自适应的,这个学习率只是初始的学习率
    'lambda': 0,  # 正则系数
    'metric': 'auc',
    'opt': 'adagrad',  # sgd,ftlr。如果采用ftlr,则还可以指定其他参数alpha, beta, lambda_1, lambda_2
    'k':16,  # 隐因子个数。FFM中的k可以比FM中的k小很多
    'init': 0.5,  # 初始化参数
    'epoch': 50,
    'stop_window': 5,  # 连续5轮指标没有创建新高就停止迭代
}  # 不用设置核数,会自动把所有核都利用起来
# ffm_model.disableLockFree()
# ffm_model.setQuiet()#迭代时不做evaluation
# ffm_model.setOnDisk()#内存容不下所有训练数据时,数据存到磁盘,每次只加载一个block的数据,在params中可以设置block_size
ffm_model.setTXTModel(model_explain_file)
ffm_model.fit(params, ffm_model_file)

LR、FM、FFM这3个算法对学习率都比较敏感,需要扩大搜索范围多尝试一些学习率。k从4增加到32的过程中AUC是递增的,另外FFM的k值可以比FM小很多。

  1. LightGBM+LR/FM/FFM都没有超越单纯的LightGBM
  2. 除了LightGBM组合特征外,把原始特征也加进来对FM的提升比较明显,对LR和FFM无提升
  3. 从FFM可以看到,使用LightGBM组合特征比只使用原始特征有很大的效果提升

 

posted @ 2018-06-28 18:26  高性能golang  阅读(4717)  评论(1编辑  收藏  举报