分类 机器学习 下的文章

使用Kaggle的步骤

我在参与新类型Kaggle竞赛时采用的步骤如下,在赛程一半的时候进入(很多图像类竞赛没办法用Kernel跑完,可以在Discussion里找github上的代码,或者直接上github搜baseline代码,用谷歌搜比赛名也会出来不少github代码)。

  1. 仔细阅读Overview和Data中的内容。

  2. 下载数据后,对Kernels分数排序,优先查看分数高的和票数高的,如果某个Kernel是fork别人的,先看源头,选择几个采用不同方法的代码复制下来跑,感受下运行时间和效果。

  3. 按照方法名称搜原理,基本看懂这个方法的用途、优缺点、有哪些参数影响较大。

  4. 查看该方法的文档,对照着手上的代码看懂,然后把文档看几遍,里面会有少量技巧和调参方法,然后搜一下他人对参数的理解。

  5. 手工调参,看时间和效果的变化(本地和提交的差距)。

  6. 查看Kernels中的EDA,增加对这些数据的感受,大概记一下数据的分布、范围、意义。

  7. 查看Kernels中fork别人然后改进的代码,找一下哪里的代码变了,分析一下为什么好,是否会过拟合。

  8. 尝试自己想一些预处理方法,或者是特征工程,看效果。

  9. 然后再手工调参,注意观察Discussion里大家的讨论,有时候会有一些灵感,也可以直接根据提示写代码执行。

  10. 在觉得排名还可以时,可以使用多折平均,分数一般都会好一些,而且减少过拟合的概率。

  11. 调参可以使用Grid或者Bayesian Optimization。

  12. 使用不同方法得到相似分数的结果进行平均,通常分数可以高一截。

  13. 尝试stacking,方式很多,有时会过拟合,处理得好可以提高非常多,融合多个方法,多层stacking。

  14. 手工平均可以根据验证集的分数选择合适的权重,也可以根据测试集分数选择权重。注意在选择哪些结果进行平均时,可以计算一下相关系数corr,选择相关系数小并且在测试集表现不错的结果进行平均。

  15. 有些情况下伪标签效果不错。

  16. 选择最终的两个提交很重要,如果测试数据非常多,分布也很均匀(比如正例只有1%就是不均匀),基本上可以尽情过拟合。根据一定逻辑进行后处理风险很大。小测试数据对stacking很敏感,不过直接平均的方法在小数据上一般都还行。

  17. 可以看到这里用的很多方法,在工作环境中是没有的,我猜测优化单模型是主流,而且我在参与过程中花时间最多的也是优化单模型,融合水平很低。如何根据Kaggle中学到的知识解决实际问题,是我非常想知道的。

回归LightGBM Cross Validation

使用LightGBM,Cross Validation进行回归,RMSE loss。

import lightgbm as lgb
import matplotlib.pyplot as plt
import numpy as np
import random
import os
from lightgbm import LGBMClassifier
from sklearn import metrics
from sklearn.metrics import mean_squared_error
from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.metrics import log_loss
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.preprocessing import LabelEncoder
import seaborn as sns
import gc
def kfold_lightgbm(train_df, test_df, y, num_folds, stratified = False, debug= False):
    if stratified:
        folds = StratifiedKFold(n_splits= num_folds, shuffle=True, random_state=17)
    else:
        folds = KFold(n_splits= num_folds, shuffle=True, random_state=17)
    # Create arrays and dataframes to store results
    oof_preds = np.zeros(train_df.shape[0])
    sub_preds = np.zeros(test_df.shape[0])
    feature_importance_df = pd.DataFrame()
    feats = train.columns.tolist()
    test_df = test_df[feats]
    #test_df = csr_matrix(test_df)
    for n_fold, (train_idx, valid_idx) in enumerate(folds.split(train_df, y)):
        print('FOLD {}'.format(n_fold))
        train_x, train_y = train_df.iloc[train_idx], y.iloc[train_idx]
        valid_x, valid_y = train_df.iloc[valid_idx], y.iloc[valid_idx]

        # LightGBM parameters found by Bayesian optimization
        lgb_params =  {
            'task': 'train',
            'boosting_type': 'gbdt',
            'objective': 'regression',
            'metric': 'rmse',
            #"n_estimators":10000,
            "learning_rate": 0.01,
            
            'num_leaves': 60,
            'subsample': 0.6143,
            'colsample_bytree': 0.6453,
            'min_split_gain': np.power(10, -2.5988),
            'reg_alpha': np.power(10, -2.2887),
            'reg_lambda': np.power(10, 1.7570),
            'min_child_weight': np.power(10, -0.1477),
            'max_depth': -1,
            #'zero_as_missing':True
        }
        '''
        lgb_params = {
            'objective': 'regression',
            'metric': 'rmse',
            'learning_rate': 0.01,
            'num_leaves': 16,
            'max_depth': -1,
            'min_child_samples': 1,
            'max_bin': 300,
            'subsample': 1.0,
            'subsample_freq': 1,
            'colsample_bytree': 0.5,
            'min_child_weight': 10,
            'reg_lambda': 0.1,
            'reg_alpha': 0.0,
            'scale_pos_weight': 1,
            'zero_as_missing': True,
            'num_threads': -1,
        }
        '''
        #train_x = csr_matrix(train_x)
        #valid_x = csr_matrix(valid_x)
        lgtrain = lgb.Dataset(train_x, train_y,
                        feature_name=feats,
                        categorical_feature = 'auto')
        lgvalid = lgb.Dataset(valid_x, valid_y,
                        feature_name=feats,
                        categorical_feature = 'auto')
        clf = lgb.train(
            lgb_params,
            lgtrain,
            num_boost_round=3000,
            valid_sets=[lgtrain, lgvalid],
            valid_names=['train','valid'],
            early_stopping_rounds=200,
            verbose_eval=100
        )
        
       # clf.fit(train_x, train_y, eval_set=[(train_x, train_y), (valid_x, valid_y)], 
            #eval_metric= 'auc', verbose= 100, early_stopping_rounds= 200)

        #oof_preds[valid_idx] = clf.predict_proba(valid_x, num_iteration=clf.best_iteration_)[:, 1]
        #sub_preds += clf.predict_proba(test_df[feats], num_iteration=clf.best_iteration_)[:, 1] / folds.n_splits
        
        oof_preds[valid_idx] = clf.predict(valid_x, num_iteration=clf.best_iteration)
        sub_preds += clf.predict(test_df, num_iteration=clf.best_iteration)/ folds.n_splits
        
        fold_importance_df = pd.DataFrame()
        fold_importance_df["feature"] = feats
        fold_importance_df["importance"] = clf.feature_importance()
        #fold_importance_df["importance"] = clf.feature_importances_
        fold_importance_df["fold"] = n_fold + 1
        feature_importance_df = pd.concat([feature_importance_df, fold_importance_df], axis=0)
        #print('Fold %2d AUC : %.6f' % (n_fold + 1, roc_auc_score(valid_y, oof_preds[valid_idx])))
        print('Fold %2d RMSE : %.6f' % (n_fold, np.sqrt(metrics.mean_squared_error(valid_y, oof_preds[valid_idx]))))      
        del clf, train_x, train_y, valid_x, valid_y
        gc.collect()

    rmse = np.sqrt(metrics.mean_squared_error(y, oof_preds))
    #print('Full AUC score %.6f' % roc_auc_score(y, oof_preds))
    print('Full RMSE score %.6f' % rmse)
    
    display_importances(feature_importance_df)
    return feature_importance_df, sub_preds
# Display/plot feature importance
def display_importances(feature_importance_df_):
    cols = feature_importance_df_[["feature", "importance"]].groupby("feature").mean().sort_values(by="importance", ascending=False)[:40].index
    best_features = feature_importance_df_.loc[feature_importance_df_.feature.isin(cols)]
    plt.figure(figsize=(8, 10))
    sns.barplot(x="importance", y="feature", data=best_features.sort_values(by="importance", ascending=False))
    plt.title('LightGBM Features (avg over folds)')
    plt.tight_layout()
    plt.savefig('lgb_importances.png')

多分类LightGBM Cross Validation

使用LightGBM,Cross Validation进行多分类,multi log loss。

import lightgbm as lgb
import matplotlib.pyplot as plt
import numpy as np
import random
import os
from lightgbm import LGBMClassifier
from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.metrics import log_loss
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.preprocessing import LabelEncoder
import seaborn as sns
import gc
def multi_log_loss(y_true, y_pred, num_classes):  # score function for CV
    esp = 1e-12
    y_pred += esp
    y_true = y_true.astype('int')
    # Handle all zeroes
    all_zeros = np.all(y_pred == 0, axis=1)
    y_pred[all_zeros] = 1/num_classes
    # Normalise sum of row probabilities to one
    row_sums = np.sum(y_pred, axis=1)
    y_pred /= row_sums.reshape((-1, 1))
    # Calculate score
    n_rows = y_true.size
    score_sum = 0
    for i in range(y_true.size):
        score_sum -= np.log(y_pred[i, y_true[i]])
    score = score_sum / n_rows
    return score
def kfold_lightgbm(train_df, test_df, y, num_folds, stratified = False, debug= False):
    if stratified:
        folds = StratifiedKFold(n_splits= num_folds, shuffle=True, random_state=SEED)
    else:
        folds = KFold(n_splits= num_folds, shuffle=True, random_state=SEED)
    num_classes = 6
    # Create arrays and dataframes to store results
    oof_preds = np.zeros((train_df.shape[0],num_classes))
    sub_preds = np.zeros((test_df.shape[0],num_classes))
    feature_importance_df = pd.DataFrame()
    feats = train_df.columns.tolist()
    cat_feats = 'auto'
    #feats = select
    for n_fold, (train_idx, valid_idx) in enumerate(folds.split(train_df[feats], y)):
        train_x, train_y = train_df[feats].iloc[train_idx], y.iloc[train_idx]
        valid_x, valid_y = train_df[feats].iloc[valid_idx], y.iloc[valid_idx]
        
        lgtrain = lgb.Dataset(train_x, train_y,
                        feature_name=feats,
                        categorical_feature = cat_feats)
        lgvalid = lgb.Dataset(valid_x, valid_y,
                        feature_name=feats,
                        categorical_feature = cat_feats)

        print('get lgb train valid dataset end')
        lgb_params =  {
            'task': 'train',
            'boosting_type': 'gbdt',
            'objective': 'multiclass',
            'num_class':num_classes,
            'metric': 'multi_logloss',
            #"n_estimators":10000,
            
            "learning_rate": 0.02,
            #"num_leaves": 200,
            #"feature_fraction": 0.50,
            #"bagging_fraction": 0.50,
            #'bagging_freq': 4,
            #"max_depth": -1,
            
            'num_leaves': 32,
            'max_depth': 8,
            'bagging_fraction': 0.7,
            'bagging_freq': 5,
            'feature_fraction': 0.7,
            
            "reg_alpha": 0.3,
            "reg_lambda": 0.1,
            'min_child_samples': 100,
            #'max_bin': 100,
            "min_split_gain":0.2,
            'nthread': 4,
            "min_child_weight":10,
        }
        clf = lgb.train(
            lgb_params,
            lgtrain,
            num_boost_round=3000,
            valid_sets=[lgtrain, lgvalid],
            valid_names=['train','valid'],
            early_stopping_rounds=100,
            verbose_eval=100
        )

        #clf.fit(train_x, train_y, eval_set=[(train_x, train_y), (valid_x, valid_y)], 
        #    eval_metric= 'auc', verbose= 100, early_stopping_rounds= 200)

        #oof_preds[valid_idx] = clf.predict_proba(valid_x, num_iteration=clf.best_iteration_)[:, 1]
        #sub_preds += clf.predict_proba(test_df[feats], num_iteration=clf.best_iteration_)[:, 1] / folds.n_splits
        
        oof_preds[valid_idx] = clf.predict(valid_x, num_iteration=clf.best_iteration)
        sub_preds += clf.predict(test_df, num_iteration=clf.best_iteration)/ folds.n_splits
        
        fold_importance_df = pd.DataFrame()
        fold_importance_df["feature"] = feats
        fold_importance_df["importance"] = clf.feature_importance()
        #fold_importance_df["importance"] = clf.feature_importances_
        fold_importance_df["fold"] = n_fold + 1
        
        feature_importance_df = pd.concat([feature_importance_df, fold_importance_df], axis=0)
        print('Fold %2d Multi Log Loss : %.6f' % (n_fold + 1, multi_log_loss(valid_y.values, oof_preds[valid_idx], num_classes)))
        del clf, train_x, train_y, valid_x, valid_y
        gc.collect()

    print('Full Multi Log Loss %.6f' % multi_log_loss(y.values, oof_preds, num_classes))
    display_importances(feature_importance_df)
    return feature_importance_df,sub_preds
# Display/plot feature importance
def display_importances(feature_importance_df_):
    cols = feature_importance_df_[["feature", "importance"]].groupby("feature").mean().sort_values(by="importance", ascending=False)[:40].index
    best_features = feature_importance_df_.loc[feature_importance_df_.feature.isin(cols)]
    plt.figure(figsize=(8, 10))
    sns.barplot(x="importance", y="feature", data=best_features.sort_values(by="importance", ascending=False))
    plt.title('LightGBM Features (avg over folds)')
    plt.tight_layout()
    plt.savefig('lgb_importances.png')

机器学习路径

我接触机器学习的入门书籍是:《机器学习实践指南:案例应用解析》,在这本书上学了python和R的基本语法,还有少量机器学习基础知识。然后是在学校图书馆借了几本AI相关书籍,这些书的最后一章是介绍决策树的,都比较老,具体是哪些书已经找不到了,看完就搁置了一段时间。

再次看机器学习是从Andrew Ng的视频开始,顺便看了台大林轩田机器学习基石的视频,看得云里雾里,顺便翻了一下李航的统计学习方法,无法确定看懂了多少,然后又搁置了很久。

再次看机器学习相关是第一次偶然看到CNN的时候,顺便了解了相关知识,比如CNN原理,用Keras框架CNN进行图像分类,看了很多遍Keras文档,使用预训练模型等。发现R-CNN、Fast R-CNN、Faster R-CNN系列,做了一个Faster R-CNN Caffe版本的PyQt5可视化界面,可以训练、测试、查看每张图像的标注和识别结果,然后又搁置了一段时间。

再次看机器学习相关是参加Kaggle竞赛,第一个参加的竞赛可以不用机器学习,可以转化为最小费用最大流,是在论坛里面学到的,学到之前是采用暴力搜索加优化做的。接下来做了很久的Kaggle竞赛,比如第一个图像分类的竞赛,当时写了一个融合常见预训练模型的框架,可惜那时候除了全连接层的参数都冻结了,试了各种预处理方法,统统效果很差。在接下来的图像分类竞赛,学到了Random Crop,多进程预处理,类别平衡,Test Time Augmentation等方法,离顶尖队伍还有很大的距离,想要提高技巧得查看很多图像竞赛的前几名的解题思路,例如模型的修改和损失函数自定义可能也会有用。然后是一个比较少见的文字分类的竞赛,学习方法就是Kernels里面他人的代码和Discussion里他人提到的思路,需要研究一些预处理的方法,还有word2vec,预训练词向量模型和训练词向量的方法,SpatialDropout1D、BiLSTM、BiGRU,N-Fold平均。

这里有个问题是我比较好奇的,就是假设我自己得到一个还可以的结果,但是公开的Kernels里也有一些还不错的结果,他采用的方法和我不同,分数差不多,这种情况只要和他平均,就可以得到更高的分数,而且过拟合的概率也很小。从规则上来说,这是允许的,私下分享但不组队才是违反规则。假设某人A凭借融合公开的结果,得到某个分数,某人只靠自己得到和A相同的分数,另外一个团队分工合作使用各个方法得到和A相同的分数,这三种情况的数量不同会导致成绩的含金量不同,不过一般公开的结果最终都不会进前10%,据我猜测使用公开Kernel的情况是比较普遍的,不过事实是怎样呢?

在一个竞赛里体验了一下Mask R-CNN,顺便体验了一下2阶段比赛的风险,1阶段小测试集,结束时要上传代码,然后发放大测试集,1星期后2阶段结束。假设在1阶段时经验不足,一味提高分数,没有考虑测试集变化的一些情况(图像尺寸、识别目标大小、图像颜色分布等等),就有可能跌落几百名。

在一个竞赛里发现了LightGBM和它的前身,曾经我以为很弱的决策树竟然可以这么强。文档里参数好多,数据集好大,作为新手依然在公开Kernels里学会了不少东西。可惜有人在最后12小时发布了一个分数和我差不多的Kernel,然后有人用它和一些公开Kernels融合了一下发布了,分数就比我高了一些,导致排名下降了300名,嘿嘿这次我就没有融合公开Kernel,所以说邪恶无法阻止,除非能碾压邪恶。

到这里基本上常见比赛都见过了,后面看到的比赛很多都可以直接用以前的代码来跑了,不过还是有一些新型的比赛出没。比如一个可以用DBSCAN的比赛,预测粒子轨迹,我一开始看到这个比赛的时候第一反应就是不做这个比赛,可惜有一些多余的时间,我就看了它好几次,作为学习聚类的一个途径了解一下,这题的最优解不是聚类。大概就是瞎构造一些已有变量的组合,用贝叶斯优化找线性组合的参数,有时手工调整一下参数看看效果,多看Discussion找方法,时间不多,自己没想出什么思路。还有比如说目标检测的竞赛,刚好是个大数据集,谷歌还提供了一笔赠金跑谷歌云,体验了一下多卡训练的感觉。

我总觉得我在面临重要选择的时候,都会做出错误的决定,就比如说我两个月多前面临做一些准备去找工作的问题,当时有一些备选:1.打比赛得好成绩去找,2.刷leetcode中等难度的题,3.用以前学过的知识做一个靠谱小应用,4.复习和学习机器学习基本知识。只能说我水平确实有限,基础知识不牢,没有办法取得前十的成绩,表面Kaggle银牌已经没啥用了,硬实力才是关键,似乎现在大家要求都挺高。我花了10天去试了一下天池的比赛,感觉有一批人很强,不过实际认真参与的大概是300人,说明很多人不需要参加竞赛,直接就可以去实际应用,想靠竞赛找到工作得进天池决赛。很多公司喜欢考算法题,听说leetcode刷完中等难度就行,可惜我没有选择全刷leetcode,这应该就是一个错误,leetcode我只试了前50题中等难度的,不参考资料会45题,间隔的做花了10天,不过不是一整天都在刷,比较难的一些知识我现在肯定不会,如果多刷一些可能才能看到更多的不足,补完应该会强一些。想做一个完整的小应用至少得花1个月,风险不小,做了不够好人家肯定看不上。机器学习基础知识感觉挺难,想在短时间内灌输进去也不知道有没有用,不过这些基础知识学起来挺快的,暂时不清楚学会了有多大用,可惜了少了论文的积累,估计只能做一些边角的工作。