forked from benzakenelad/BitFit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun_glue.py
159 lines (125 loc) · 7.28 KB
/
run_glue.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import argparse
import os
import logging
from utils import setup_logging
from GLUEvaluator import GLUEvaluator, set_seed
setup_logging()
LOGGER = logging.getLogger(__file__)
PADDING = "max_length"
MAX_SEQUENCE_LEN = 128
RAND_UNIFORM_MASK_SIZE = {'bert-base-cased': 100000, 'bert-large-cased': 280000, 'roberta-base': 105000}
def _parse_args():
parser = argparse.ArgumentParser(description='BitFit GLUE evaluation',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--output-path', '-o', required=True, type=str,
help='output directory path for evaluation products.')
parser.add_argument('--task-name', '-t', required=True, type=str, help='GLUE task name for evaluation.',
choices={'cola', 'mnli', 'mrpc', 'qnli', 'qqp', 'rte', 'sst2', 'stsb', 'wnli'})
parser.add_argument('--model-name', '-m', type=str, default='bert-base-cased', help='model-name to evaluate with.',
choices={'bert-base-cased', 'bert-large-cased', 'roberta-base'})
parser.add_argument('--fine-tune-type', '-f', required=True, type=str,
help='Which fine tuning process to perform, types are the types that were performed in BitFit paper.',
choices={'full_ft', 'bitfit', 'frozen', 'rand_uniform', 'rand_row_col'})
parser.add_argument('--bias-terms', metavar='N', type=str, nargs='+', default=['all'],
choices={'intermediate', 'key', 'query', 'value', 'output', 'output_layernorm',
'attention_layernorm', 'all'},
help='bias terms to BitFit, should be given in case --fine-tune-type is bitfit '
'(choose \'all\' for BitFit all bias terms)')
parser.add_argument('--gpu-device', '-d', type=int, default=None,
help='GPU id for BitFit, if not mentioned will train on CPU.')
parser.add_argument('--seed', '-s', type=int, default=0, help='seed value to set.')
parser.add_argument('--learning-rate', '-l', type=float, default=1e-3, help='learning rate for training.')
parser.add_argument('--epochs', '-e', type=int, default=16, help='number of training epochs.')
parser.add_argument('--batch-size', '-b', type=int, default=8, help='training and evaluation batch size.')
parser.add_argument('--optimizer', type=str, default='adamw', choices={'adam', 'adamw'})
parser.add_argument('--save-evaluator', action='store_true', default=False,
help='if given, will save the evaluator for later inference/examination.')
parser.add_argument('--predict-test', action='store_true', default=False,
help='if given, will infer on test set using the fine-tuned model (predictions file will be in '
'GLUE benchmark test server format). Predictions will be saved to output_path.')
parser.add_argument('--verbose', action='store_true', default=True,
help='if given, will plot a list of trainable weights.')
return parser.parse_args()
def _validate_args(args):
if not os.path.exists(args.output_path):
os.makedirs(args.output_path)
if not os.path.isdir(args.output_path):
raise ValueError("--output_path must be a path to directory")
if len(os.listdir(args.output_path)):
raise ValueError("--output_path directory isn't empty, please supply an empty directory path.")
if args.fine_tune_type == 'rand_uniform' and args.model_name not in RAND_UNIFORM_MASK_SIZE.keys():
raise ValueError(f'Currently the rand_uniform fine-tune type is not supported for {args.model_name}.')
def _plot_training_details(args):
[LOGGER.info('############################################################################################') for _
in range(3)]
LOGGER.info('')
LOGGER.info('Training Details: ')
LOGGER.info('----------------------------------------------')
LOGGER.info(f'Model Name: {args.model_name}')
LOGGER.info(f'Task Name: {args.task_name}')
LOGGER.info(f'Fine Tuning Type: {args.fine_tune_type}')
LOGGER.info(f'Output Directory: {args.output_path}')
if args.gpu_device is not None:
LOGGER.info(f'Running on GPU #{args.gpu_device}')
else:
LOGGER.info(f'Running on CPU')
if args.fine_tune_type == 'bitfit':
LOGGER.info(f"Bias Trainable Terms: {'all bias terms' if 'all' in args.bias_terms else args.bias_terms}")
LOGGER.info(f'Epochs: {args.epochs}')
LOGGER.info(f'Learning Rate: {args.learning_rate}')
LOGGER.info(f'Batch Size: {args.batch_size}')
LOGGER.info(f"Optimizer: {'AdamW' if args.optimizer == 'adamw' else 'Adam'}")
LOGGER.info('')
[LOGGER.info('############################################################################################') for _
in range(3)]
def _perform_training_preparations(evaluator, args, trainable_components):
if args.fine_tune_type == 'frozen':
trainable_components = []
if args.fine_tune_type == 'full_ft':
evaluator.training_preparation(learning_rate=args.learning_rate,
optimizer=args.optimizer,
encoder_trainable=True,
verbose=args.verbose)
elif args.fine_tune_type == 'bitfit' or args.fine_tune_type == 'frozen':
evaluator.training_preparation(learning_rate=args.learning_rate,
optimizer=args.optimizer,
encoder_trainable=False,
trainable_components=trainable_components,
verbose=args.verbose)
else:
evaluator.training_preparation(learning_rate=args.learning_rate,
optimizer=args.optimizer,
encoder_trainable=True,
verbose=False)
# randomizing mask
if args.fine_tune_type == 'rand_uniform':
evaluator.set_uniform_mask(mask_size=RAND_UNIFORM_MASK_SIZE[args.model_name])
else: # args.fine_tune_type == 'rand_row_col'
evaluator.set_row_and_column_random_mask()
def main():
# args parsing
args = _parse_args()
_validate_args(args)
_plot_training_details(args)
# seed
set_seed(args.seed)
# evaluator creation
evaluator = GLUEvaluator(args.task_name, args.model_name, args.gpu_device)
# data preprocessing
evaluator.preprocess_dataset(PADDING, MAX_SEQUENCE_LEN, args.batch_size)
# training preparation
trainable_components = GLUEvaluator.convert_to_actual_components(args.bias_terms)
_perform_training_preparations(evaluator, args, trainable_components)
# train and evaluate
evaluator.train_and_evaluate(args.epochs, args.output_path)
# saving artifacts
if args.fine_tune_type == 'bitfit':
evaluator.plot_terms_changes(os.path.join(args.output_path, 'bias_term_changes'))
# save model
if args.save_evaluator:
evaluator.save(os.path.join(args.output_path, 'evaluator'))
# export model test set predictions
if args.predict_test:
evaluator.export_model_test_set_predictions(args.output_path)
if __name__ == '__main__':
main()