{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Copyright (c). All rights reserved.\n",
"\n",
"Licensed under the MIT License.\n",
"\n",
"# Troubleshooting HPO for fine-tuning pre-trained language models\n",
"\n",
"## 1. Introduction\n",
"\n",
"In this notebook, we demonstrate a procedure for troubleshooting HPO failure in fine-tuning pre-trained language models (introduced in the following paper):\n",
"\n",
"*[An Empirical Study on Hyperparameter Optimization for Fine-Tuning Pre-trained Language Models](https://arxiv.org/abs/2106.09204). Xueqing Liu, Chi Wang. ACL-IJCNLP 2021*\n",
"\n",
"Notes:\n",
"\n",
"*In this notebook, we only run each experiment 1 time for simplicity, which is different from the paper (3 times). To reproduce the paper's result, please run 3 repetitions and take the average scores.\n",
"\n",
"*Running this notebook takes about one hour.\n",
"\n",
"FLAML requires `Python>=3.7`. To run this notebook example, please install flaml with the `notebook` and `nlp` options:\n",
"\n",
"```bash\n",
"pip install flaml[nlp]==0.7.1 # in higher version of flaml, the API for nlp tasks changed\n",
"```\n",
"\n",
"Our paper was developed under transformers version 3.4.0. We uninstall and reinstall transformers==3.4.0:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"%pip install flaml[nlp]==0.7.1 # in higher version of flaml, the API for nlp tasks changed\n",
"%pip install transformers==3.4.0\n",
"from flaml.nlp import AutoTransformers\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Initial Experimental Study\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load dataset \n",
"\n",
"Load the dataset using AutoTransformer.prepare_data. In this notebook, we use the Microsoft Research Paraphrasing Corpus (MRPC) dataset and the Electra model as an example:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"console_args has no attribute pretrained_model_size, continue\n",
"console_args has no attribute dataset_subdataset_name, continue\n",
"console_args has no attribute algo_mode, continue\n",
"console_args has no attribute space_mode, continue\n",
"console_args has no attribute search_alg_args_mode, continue\n",
"console_args has no attribute algo_name, continue\n",
"console_args has no attribute pruner, continue\n",
"console_args has no attribute resplit_mode, continue\n",
"console_args has no attribute rep_id, continue\n",
"console_args has no attribute seed_data, continue\n",
"console_args has no attribute seed_transformers, continue\n",
"console_args has no attribute learning_rate, continue\n",
"console_args has no attribute weight_decay, continue\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Reusing dataset glue (/home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4)\n",
"Loading cached processed dataset at /home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4/cache-6a78e5c95406457c.arrow\n",
"Loading cached processed dataset at /home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4/cache-e8d0f3e04c3b4588.arrow\n",
"Loading cached processed dataset at /home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4/cache-4b0966b394994163.arrow\n",
"Loading cached processed dataset at /home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4/cache-6a78e5c95406457c.arrow\n",
"Loading cached processed dataset at /home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4/cache-e8d0f3e04c3b4588.arrow\n",
"Loading cached processed dataset at /home/xliu127/.cache/huggingface/datasets/glue/mrpc/1.0.0/7c99657241149a24692c402a5c3f34d4c9f1df5ac2e4c3759fadea38f6cb29c4/cache-4b0966b394994163.arrow\n"
]
}
],
"source": [
"autohf = AutoTransformers()\n",
"preparedata_setting = {\n",
" \"dataset_subdataset_name\": \"glue:mrpc\",\n",
" \"pretrained_model_size\": \"google/electra-base-discriminator:base\",\n",
" \"data_root_path\": \"data/\",\n",
" \"max_seq_length\": 128,\n",
" }\n",
"autohf.prepare_data(**preparedata_setting)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"### Running grid search\n",
"\n",
"First, we run grid search using Electra. By specifying `algo_mode=\"grid\"`, AutoTransformers will run the grid search algorithm. By specifying `space_mode=\"grid\"`, AutoTransformers will use the default grid search configuration recommended by the Electra paper:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"pycharm": {
"name": "#%%\n"
},
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"== Status == Memory usage on this node: 14.2/376.6 GiB Using FIFO scheduling algorithm. Resources requested: 0/96 CPUs, 0/4 GPUs, 0.0/250.73 GiB heap, 0.0/76.9 GiB objects (0/1.0 accelerator_type:V100) Current best trial: 67d99_00002 with accuracy=0.7254901960784313 and parameters={'learning_rate': 0.0001, 'weight_decay': 0.0, 'adam_epsilon': 1e-06, 'warmup_ratio': 0.1, 'per_device_train_batch_size': 32, 'hidden_dropout_prob': 0.1, 'attention_probs_dropout_prob': 0.1, 'num_train_epochs': 0.5, 'seed': 42} Result logdir: /data/xliu127/projects/hyperopt/FLAML/notebook/data/checkpoint/dat=glue_subdat=mrpc_mod=grid_spa=grid_arg=dft_alg=grid_pru=None_pre=electra_presz=base_spt=ori_rep=0_sddt=43_sdhf=42_var1=None_var2=None/ray_result Number of trials: 4/4 (4 TERMINATED)
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2021-06-16 10:45:35,071\tINFO tune.py:450 -- Total run time: 106.56 seconds (106.41 seconds for the tuning loop).\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total running time: 106.57789206504822 seconds\n"
]
}
],
"source": [
"import transformers\n",
"autohf_settings = {\n",
" \"resources_per_trial\": {\"gpu\": 1, \"cpu\": 1},\n",
" \"num_samples\": 1,\n",
" \"time_budget\": 100000, # unlimited time budget\n",
" \"fp16\": True,\n",
" \"algo_mode\": \"grid\", # set the search algorithm to grid search\n",
" \"space_mode\": \"grid\", # set the search space to the recommended grid space\n",
" \"transformers_verbose\": transformers.logging.ERROR\n",
" }\n",
"validation_metric, analysis = autohf.fit(**autohf_settings)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Get the time for running grid search: "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"grid search for glue_mrpc took 106.57789206504822 seconds\n"
]
}
],
"source": [
"GST = autohf.last_run_duration\n",
"print(\"grid search for {} took {} seconds\".format(autohf.jobid_config.get_jobid_full_data_name(), GST))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After the HPO run finishes, generate the predictions and save it as a .zip file to be submitted to the glue website. Here we will need the library AzureUtils which is for storing the output information (e.g., analysis log, .zip file) locally and uploading the output to an azure blob container (e.g., if multiple jobs are executed in a cluster). If the azure key and container information is not specified, the output information will only be saved locally. "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"remove_columns_ is deprecated and will be removed in the next major version of datasets. Use the dataset.remove_columns method instead.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cleaning the existing label column from test data\n"
]
},
{
"data": {
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" \n",
" [432/432 00:34]\n",
"
\n",
" "
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"JobID(dat=['glue'], subdat='mrpc', mod='grid', spa='grid', arg='dft', alg='grid', pru='None', pre_full='google/electra-base-discriminator', pre='electra', presz='base', spt='ori', rep=0, sddt=43, sdhf=42, var1=None, var2=None)\n",
"Your output will not be synced to azure because azure key and container name are not specified\n",
"The path for saving the prediction .zip file is not specified, setting to data/ by default\n",
"Your output will not be synced to azure because azure key and container name are not specified\n",
"{'eval_accuracy': 0.7254901960784313, 'eval_f1': 0.8276923076923076, 'eval_loss': 0.516851007938385}\n"
]
}
],
"source": [
"predictions, test_metric = autohf.predict()\n",
"from flaml.nlp import AzureUtils\n",
"\n",
"print(autohf.jobid_config)\n",
"\n",
"azure_utils = AzureUtils(root_log_path=\"logs_test/\", autohf=autohf)\n",
"azure_utils.write_autohf_output(valid_metric=validation_metric,\n",
" predictions=predictions,\n",
" duration=GST)\n",
"print(validation_metric)"
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"The validation F1/accuracy we got was 92.4/89.5. After the above steps, you will find a .zip file for the predictions under data/result/. Submit the .zip file to the glue website. The test F1/accuracy we got was 90.4/86.7. As an example, we only run the experiment one time, but in general, we should run the experiment multiple repetitions and report the averaged validation and test accuracy."
]
},
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"### Running Random Search\n",
"\n",
"Next, we run random search with the same time budget as grid search:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"def tune_hpo(time_budget, this_hpo_space):\n",
" autohf_settings = {\n",
" \"resources_per_trial\": {\"gpu\": 1, \"cpu\": 1},\n",
" \"num_samples\": -1,\n",
" \"time_budget\": time_budget,\n",
" \"fp16\": True,\n",
" \"algo_mode\": \"hpo\", # set the search algorithm mode to hpo\n",
" \"algo_name\": \"rs\",\n",
" \"space_mode\": \"cus\", # customized search space (this_hpo_space)\n",
" \"hpo_space\": this_hpo_space,\n",
" \"transformers_verbose\": transformers.logging.ERROR\n",
" }\n",
" validation_metric, analysis = autohf.fit(**autohf_settings)\n",
" predictions, test_metric = autohf.predict()\n",
" azure_utils = AzureUtils(root_log_path=\"logs_test/\", autohf=autohf)\n",
" azure_utils.write_autohf_output(valid_metric=validation_metric,\n",
" predictions=predictions,\n",
" duration=GST)\n",
" print(validation_metric)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"== Status == Memory usage on this node: 30.1/376.6 GiB Using FIFO scheduling algorithm. Resources requested: 0/96 CPUs, 0/4 GPUs, 0.0/247.51 GiB heap, 0.0/75.93 GiB objects (0/1.0 accelerator_type:V100) Current best trial: c67b4_00003 with accuracy=0.7303921568627451 and parameters={'learning_rate': 4.030097060410288e-05, 'warmup_ratio': 0.06084844859190755, 'num_train_epochs': 0.5, 'per_device_train_batch_size': 16, 'weight_decay': 0.15742692948967135, 'attention_probs_dropout_prob': 0.08638900372842316, 'hidden_dropout_prob': 0.058245828039608386, 'seed': 42} Result logdir: /data/xliu127/projects/hyperopt/FLAML/notebook/data/checkpoint/dat=glue_subdat=mrpc_mod=hpo_spa=cus_arg=dft_alg=rs_pru=None_pre=electra_presz=base_spt=ori_rep=0_sddt=43_sdhf=42_var1=None_var2=None/ray_result Number of trials: 8/infinite (8 TERMINATED)
\n",
" "
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Your output will not be synced to azure because azure key and container name are not specified\n",
"The path for saving the prediction .zip file is not specified, setting to data/ by default\n",
"Your output will not be synced to azure because azure key and container name are not specified\n",
"{'eval_accuracy': 0.7401960784313726, 'eval_f1': 0.8333333333333334, 'eval_loss': 0.5303606986999512}\n"
]
}
],
"source": [
"hpo_space_min = {\n",
" \"learning_rate\": {\"l\": 3e-5, \"u\": 1.5e-4, \"space\": \"log\"},\n",
" \"warmup_ratio\": [0.1],\n",
" \"num_train_epochs\": [3],\n",
" \"per_device_train_batch_size\": [32],\n",
" \"weight_decay\": [0.0],\n",
" \"attention_probs_dropout_prob\": [0.1],\n",
" \"hidden_dropout_prob\": [0.1],\n",
" }\n",
"tune_hpo(4 * GST, hpo_space_min)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The validation F1/accuracy we got was 93.5/91.1, where the accuracy outperforms grid search. The test F1/accuracy was 90.1/86.1. As a result, random search with 4*GST and the minimum space overfits. We stop the troubleshooting process because the search space cannot be further reduced."
]
}
],
"metadata": {
"interpreter": {
"hash": "bfcd9a6a9254a5e160761a1fd7a9e444f011592c6770d9f4180dde058a9df5dd"
},
"kernelspec": {
"display_name": "Python 3.7.7 64-bit ('flaml': conda)",
"name": "python3"
},
"language_info": {
"name": "python",
"version": ""
}
},
"nbformat": 4,
"nbformat_minor": 1
}