Kaggle Feedback Prize冠军方案分享
本文将介绍最近刚结束的Kaggle Feedback Prize - English Language Learning的赛题任务和冠军解决方案。
赛题介绍
本次比赛的目标是评估8-12年级英语学习者(English Language Learners, ELLs)的语言能力。利用ELL撰写的作文数据集,开发有助于支持学生的模型。你的工作将帮助ELL获得更准确的语言发展反馈,并加快教师的评分周期。这些结果可以使ELL接受更合适的学习任务,帮助他们提高英语水平。
具体来说,你需要训练模型,对每篇议论文的六个指标进行评分:衔接、语法、词汇、短语、语法和惯例。每项指标都代表论文写作熟练程度的一个组成部分,得分越高,该指标的熟练程度越高。分数范围从1.0到5.0,以0.5为增量。你的任务是预测测试集中给出的六项测试中每一项的分数。
数据集介绍
数据集每条样本包含一篇议论文,训练集有对应的六个指标的评分,测试集只有议论文的文本信息,没有标签。
评价指标
评价指标为MCRMSE,对六个标签列分别计算RMSEh后取平均。
冠军方案
第一名的整体方案如下图所示,包括数据增强,模型训练,构造稳定的线下验证策略,以及模型集成。
总的策略是训练很多具有多样性的方案进行融合。其中多样性包括数据的多样性和模型的多样性。
线下验证策略
使用了MultilabelStratifiedKFold策略,由于CV和LB的趋势较为一致,在集成的时候只会将同时在CV和LB上都有提升的方案加入到最终的集成方案中。
def create_folds(cfg): df = pd.read_csv(cfg.dataset.comp_train_dataframe) mskf = MultilabelStratifiedKFold(n_splits=cfg.dataset.num_folds, shuffle=True, random_state=cfg.environment.seed) for fold, ( _, val_) in enumerate(mskf.split(X=df, y=df[cfg.dataset.target_cols])): df.loc[val_ , "fold"] = int(fold) df["fold"] = df["fold"].astype(int) df.to_csv(f"{cfg.dataset.base_dir}/train_{cfg.dataset.num_folds}folds.csv", index=False)
数据增强
数据增强模块包括以下三个策略:
1) 用模型的预测结果作为伪标签加入到训练集中;
2) 用1)中的预测结果和真实值求均值后,作为伪标签加入到训练集中;
3) Meta Pseudo Labels
其中,1)和3)除了使用训练集的的数据,还使用了feedback1的数据
模型
3.1 Bert
Bert的模型方案细节:
1) 使用不同Max_len获得不同的方案
768/1462 for deberta models, 512 for others
2) 不同的backbone
- microsoft-deberta-v3-base
- deberta-v3-large
- deberta-v2-xlarge
- roberta-large
- distilbert-base-uncased
3) 不同的pooling层
- MeanPooling
- ConcatPooling
- WeightedLayerPooling
- GemPooling
- LSTMPooling
4) 不同的reinit策略
设置是否reinit_top layer weights的开关,获得不同的方案
5) 不同的学习率
使用不同的学习率获得不同的方案
6) 冻结top_n层参数
if 'deberta-v3-base' in cfg.architecture.model_name or 'mdeberta-v3-base' in cfg.architecture.model_name: self.model.embeddings.requires_grad_(False) self.model.encoder.layer[:9].requires_grad_(False)
7) 使用了Adversarial Weight Perturbation(AWP)
3.2 SVR
采用多个bert作为特征提取器,提取后的特征进行拼接,输入到SVR模型中。
其中,特征提取器包括:
- bart-large
- all_datasets_v3_roberta-large
- bart-large-mnli
这部分可以参考下面的链接:
https://www.kaggle.com/code/cdeotte/rapids-svr-cv-0-450-lb-0-44x#Make-25-Stratified-Folds!
集成学习
集成学习部分使用optuna进行搜索,对不同的方案赋予不同的权重.
参考代码:
target_cols = ["cohesion", "syntax", "vocabulary", "phraseology", "grammar", "conventions"] csvs = ["model1.csv",'model2.csv','model3.csv', ...] def MCRMSE(y_trues, y_preds): scores = [] idxes = y_trues.shape[1]for i in range(idxes): y_true = y_trues[:,i] y_pred = y_preds[:,i] score = mean_squared_error(y_true, y_pred, squared=False) # RMSE scores.append(score) mcrmse_score = np.mean(scores)return mcrmse_score, scores def MCRMSE_SINGLE(y_trues, y_preds): scores = [] mcrmse_score = mean_squared_error(y_trues, y_preds, squared=False) # RMSEreturn mcrmse_score, scores def get_score(y_trues, y_preds, single=False):if single: mcrmse_score, scores = MCRMSE_SINGLE(y_trues, y_preds)else: mcrmse_score, scores = MCRMSE(y_trues, y_preds)return mcrmse_score, scores all_preds = []target_cols = ["cohesion", "syntax", "vocabulary", "phraseology", "grammar", "conventions"] labels = Nonefor index, csv in enumerate(csvs): oof_df = pd.read_csv(csv) oof_df = oof_df.sort_values('text_id').reset_index(drop=True)if index==0: print(oof_df.shape) df = pd.read_csv(csvs[0]) df = df.sort_values('text_id').reset_index(drop=True) labels = df[target_cols].values if f"pred_{target_cols[0]}" in oof_df.columns: preds = oof_df[[f"pred_{c}" for c in target_cols]].valueselse: preds = oof_df[target_cols].values all_preds.append(preds) single=False scores = []if single: score = get_score(labels, preds, single=True)else: score, scores = get_score(labels, preds) print(score, scores) def minimize_rmse(params): preds = Nonefor index, val in enumerate(params.keys()):if index == 0: preds = params[val]*all_preds[0]else: preds += params[val]*all_preds[index] param_sum = 0for key, val in params.items(): param_sum += val preds = preds/param_sum score, scores = get_score(labels, preds) return score def objective(trial): params = {}for i in range(num_of_csv): params[f"w{i+1}"] = trial.suggest_float(f'w{i+1}', 0, 1) score = minimize_rmse(params)return score study = optuna.create_study(direction='minimize')study.optimize(objective, n_trials=2000)study.best_params
参考链接
https://www.kaggle.com/competitions/feedback-prize-english-language-learning/discussion/369457