|
20 | 20 | import pprint
|
21 | 21 | pp = pprint.PrettyPrinter(indent=4)
|
22 | 22 |
|
23 |
| -#TODO Different seeds for Ray Trainer (TF, numpy, Python; Torch, Env), Environment (it has multiple sources of randomness too), Ray Evaluator |
24 |
| -# docstring at beginning of the file is stored in __doc__ |
25 |
| -parser = argparse.ArgumentParser(description=__doc__) |
26 |
| -parser.add_argument('-c', '--config-file', dest='config_file', action='store', |
27 |
| - default='default_config', |
28 |
| - help='Configuration file containing configuration to run ' |
29 |
| - 'experiments. It must be a Python file so config can be ' |
30 |
| - 'given programmatically. There are 2 types of configs - ' |
31 |
| - 'VARIABLE CONFIG across the experiments and STATIC CONFIG ' |
32 |
| - 'across the experiments. \nVARIABLE CONFIGS: The ' |
33 |
| - 'OrderedDicts var_env_configs, var_agent_configs and ' |
34 |
| - 'var_model_configs hold configuration options that are ' |
35 |
| - 'variable for the environment, agent and model across the ' |
36 |
| - 'current experiment. For each configuration option, the ' |
37 |
| - 'option is the key in the dict and its value is a list of ' |
38 |
| - 'values it can take for the current experiment. A ' |
39 |
| - 'Cartesian product of these lists is taken to generate ' |
40 |
| - 'various possible configurations to be run. For example, ' |
41 |
| - 'you might want to vary "delay" for the current ' |
42 |
| - 'experiment. Then "delay" would be a key in ' |
43 |
| - 'var_env_configs dict and its value would be a list of ' |
44 |
| - 'values it can take. Because Ray does not have a common ' |
45 |
| - 'way to address this specification of configurations for ' |
46 |
| - 'its agents, there are a few hacky ways to set ' |
47 |
| - 'var_agent_configs and var_model_configs currently. ' |
48 |
| - 'Please see sample experiment config files in the ' |
49 |
| - 'experiments directory to see how to set the values for a ' |
50 |
| - 'given algorithm. \n STATIC CONFIGS: env_config, ' |
51 |
| - 'agent_config and model_config are dicts which hold the ' |
52 |
| - 'static configuration for the current experiment as a ' |
53 |
| - 'normal Python dict.') |
54 |
| -# ####TODO Update docs regarding how to get configs to run: i.e., Cartesian |
55 |
| -# product, or random, etc. |
56 |
| -parser.add_argument('-e', '--exp-name', dest='exp_name', action='store', |
57 |
| - default='mdpp_default_experiment', |
58 |
| - help='The user-chosen name of the experiment. This is used' |
59 |
| - ' as the prefix of the output files (the prefix also ' |
60 |
| - 'contains config_num if that is provided). It will save ' |
61 |
| - 'stats to 2 CSV files, with the filenames as the one given' |
62 |
| - ' as argument' |
63 |
| - ' and another file with an extra "_eval" in the filename ' |
64 |
| - 'that contains evaluation stats during the training. ' |
65 |
| - 'Appends to existing files or creates new ones if they ' |
66 |
| - 'don\'t exist.') |
67 |
| -parser.add_argument('-n', '--config-num', dest='config_num', action='store', |
68 |
| - default=None, type=int, |
69 |
| - help='Used for running the configurations of experiments ' |
70 |
| - 'in parallel. This is appended to the prefix of the output' |
71 |
| - ' files (after exp_name).' |
72 |
| - ' A Cartesian product of different configuration values ' |
73 |
| - 'for the experiment will be taken and ordered as a list ' |
74 |
| - 'and this number corresponds to the configuration number ' |
75 |
| - 'in this list. Please look in to the code for details.') |
76 |
| -# ###TODO Remove? #hack to run 1000 x 1000 env configs x agent configs. |
77 |
| -# Storing all million of them in memory may be too inefficient? |
78 |
| -parser.add_argument('-a', '--agent-config-num', dest='agent_config_num', |
79 |
| - action='store', default=None, type=int, |
80 |
| - help='Used for running the configurations of experiments ' |
81 |
| - 'in parallel. This is appended to the prefix of the output' |
82 |
| - ' files (after exp_name).') |
83 |
| -parser.add_argument('-f', '--framework', dest='framework', action='store', |
84 |
| - default='ray', type=str, help='Specify framework to run ' |
85 |
| - 'experiments (Current options: Ray Rllib, Stable Baselines' |
86 |
| - ').') |
87 |
| -parser.add_argument('-m', '--save-model', dest='save_model', action='store', |
88 |
| - default=False, type=bool, |
89 |
| - help='Option to save trained NN model and framework \ |
90 |
| - generated files at the end of ' |
91 |
| - 'training.') |
92 |
| -parser.add_argument('-t', '--framework-dir', dest='framework_dir', |
93 |
| - action='store', default='/tmp/', type=str, |
94 |
| - help='Prefix of directory to be used by underlying ' |
95 |
| - 'framework (e.g. Ray Rllib, Stable Baselines 3). This ' |
96 |
| - 'name will be passed to the framework.') |
97 |
| -# parser.add_argument('-t', '--tune-hps', dest='tune_hps', action='store', |
98 |
| -# default=False, type=bool, |
99 |
| -# help='Used for tuning the hyperparameters that can be ' |
100 |
| -# 'used for experiments later.' |
101 |
| -# ' A Cartesian product of different configuration values ' |
102 |
| -# 'for the experiment will be taken and ordered as a list ' |
103 |
| -# 'and this number corresponds to the configuration number' |
104 |
| -# ' in this list.' |
105 |
| -# ' Please look in to the code for details.') |
106 |
| -parser.add_argument('-l', '--log-level', default='WARNING', |
107 |
| - help='Set log level.') |
108 |
| - |
109 |
| - |
110 |
| -args = parser.parse_args() |
111 |
| -print("Parsed arguments:", args) |
112 |
| - |
113 |
| -log_levels = { |
114 |
| - 'CRITICIAL': logging.CRITICAL, |
115 |
| - 'ERROR': logging.ERROR, |
116 |
| - 'WARNING': logging.WARNING, |
117 |
| - 'INFO': logging.INFO, |
118 |
| - 'DEBUG': logging.DEBUG, |
119 |
| - 'NOTSET': logging.NOTSET |
120 |
| -} |
121 |
| - |
122 |
| -try: |
123 |
| - log_level_ = log_levels[args.log_level] |
124 |
| -except ValueError: |
125 |
| - logging.error("Log level {} not in {}.".format(args.log_level, |
126 |
| - log_levels.keys())) |
127 |
| - |
128 |
| -config_file = args.config_file |
129 |
| - |
130 |
| -if args.config_file[-3:] == '.py': |
131 |
| - config_file = args.config_file[:-3] |
132 |
| - |
133 |
| -# print("config_file_path:", config_file_path) |
134 |
| - |
135 |
| -stats_file_name = os.path.abspath(args.exp_name) |
136 |
| - |
137 |
| -if args.config_num is not None: |
138 |
| - stats_file_name += '_' + str(args.config_num) |
139 |
| -# elif args.agent_config_num is not None: ###IMP Commented out! If we append both these nums then, that can lead to 1M small files for 1000x1000 configs which doesn't play well with our Nemo cluster. |
140 |
| -# stats_file_name += '_' + str(args.agent_config_num) |
141 |
| - |
142 |
| -print("Stats file being written to:", stats_file_name) |
143 |
| - |
144 |
| -config, final_configs = config_processor.process_configs(config_file, stats_file_prefix=stats_file_name, framework=args.framework, config_num=args.config_num, log_level=log_level_, framework_dir=args.framework_dir) |
145 |
| - |
146 |
| -print("Configuration number(s) that will be run:", "all" if args.config_num is None else args.config_num) |
147 |
| - |
148 |
| - |
149 |
| -# import default_config |
150 |
| -# print("default_config:", default_config) |
151 |
| -# print(os.path.abspath(args.config_file)) # 'experiments/dqn_seq_del.py' |
152 |
| - |
153 |
| - |
154 |
| -import time |
155 |
| -start = time.time() |
156 |
| - |
157 |
| - |
158 |
| - |
159 |
| -if args.config_num is None: |
160 |
| - # final_configs = config.final_configs |
161 |
| - print("Total number of configs to run:", len(final_configs)) |
162 |
| - pass |
163 |
| -else: |
164 |
| - final_configs = [final_configs[args.config_num]] |
165 |
| - |
166 |
| - |
167 | 23 |
|
| 24 | +def main(): |
| 25 | + #TODO Different seeds for Ray Trainer (TF, numpy, Python; Torch, Env), Environment (it has multiple sources of randomness too), Ray Evaluator |
| 26 | + # docstring at beginning of the file is stored in __doc__ |
| 27 | + parser = argparse.ArgumentParser(description=__doc__) |
| 28 | + parser.add_argument('-c', '--config-file', dest='config_file', |
| 29 | + action='store', default='default_config', |
| 30 | + help='Configuration file containing configuration to run ' |
| 31 | + 'experiments. It must be a Python file so config can be ' |
| 32 | + 'given programmatically. There are 2 types of configs - ' |
| 33 | + 'VARIABLE CONFIG across the experiments and STATIC CONFIG ' |
| 34 | + 'across the experiments. \nVARIABLE CONFIGS: The ' |
| 35 | + 'OrderedDicts var_env_configs, var_agent_configs and ' |
| 36 | + 'var_model_configs hold configuration options that are ' |
| 37 | + 'variable for the environment, agent and model across the ' |
| 38 | + 'current experiment. For each configuration option, the ' |
| 39 | + 'option is the key in the dict and its value is a list of ' |
| 40 | + 'values it can take for the current experiment. A ' |
| 41 | + 'Cartesian product of these lists is taken to generate ' |
| 42 | + 'various possible configurations to be run. For example, ' |
| 43 | + 'you might want to vary "delay" for the current ' |
| 44 | + 'experiment. Then "delay" would be a key in ' |
| 45 | + 'var_env_configs dict and its value would be a list of ' |
| 46 | + 'values it can take. Because Ray does not have a common ' |
| 47 | + 'way to address this specification of configurations for ' |
| 48 | + 'its agents, there are a few hacky ways to set ' |
| 49 | + 'var_agent_configs and var_model_configs currently. ' |
| 50 | + 'Please see sample experiment config files in the ' |
| 51 | + 'experiments directory to see how to set the values for a ' |
| 52 | + 'given algorithm. \n STATIC CONFIGS: env_config, ' |
| 53 | + 'agent_config and model_config are dicts which hold the ' |
| 54 | + 'static configuration for the current experiment as a ' |
| 55 | + 'normal Python dict.') |
| 56 | + # ####TODO Update docs regarding how to get configs to run: i.e., Cartesian |
| 57 | + # product, or random, etc. |
| 58 | + parser.add_argument('-e', '--exp-name', dest='exp_name', action='store', |
| 59 | + default='mdpp_default_experiment', |
| 60 | + help='The user-chosen name of the experiment. This is used' |
| 61 | + ' as the prefix of the output files (the prefix also ' |
| 62 | + 'contains config_num if that is provided). It will save ' |
| 63 | + 'stats to 2 CSV files, with the filenames as the one given' |
| 64 | + ' as argument' |
| 65 | + ' and another file with an extra "_eval" in the filename ' |
| 66 | + 'that contains evaluation stats during the training. ' |
| 67 | + 'Appends to existing files or creates new ones if they ' |
| 68 | + 'don\'t exist.') |
| 69 | + parser.add_argument('-n', '--config-num', dest='config_num', action='store', |
| 70 | + default=None, type=int, |
| 71 | + help='Used for running the configurations of experiments ' |
| 72 | + 'in parallel. This is appended to the prefix of the output' |
| 73 | + ' files (after exp_name).' |
| 74 | + ' A Cartesian product of different configuration values ' |
| 75 | + 'for the experiment will be taken and ordered as a list ' |
| 76 | + 'and this number corresponds to the configuration number ' |
| 77 | + 'in this list. Please look in to the code for details.') |
| 78 | + # ###TODO Remove? #hack to run 1000 x 1000 env configs x agent configs. |
| 79 | + # Storing all million of them in memory may be too inefficient? |
| 80 | + parser.add_argument('-a', '--agent-config-num', dest='agent_config_num', |
| 81 | + action='store', default=None, type=int, |
| 82 | + help='Used for running the configurations of experiments ' |
| 83 | + 'in parallel. This is appended to the prefix of the output' |
| 84 | + ' files (after exp_name).') |
| 85 | + parser.add_argument('-f', '--framework', dest='framework', action='store', |
| 86 | + default='ray', type=str, help='Specify framework to run ' |
| 87 | + 'experiments (Current options: Ray Rllib, Stable Baselines' |
| 88 | + ').') |
| 89 | + parser.add_argument('-m', '--save-model', dest='save_model', action='store', |
| 90 | + default=False, type=bool, |
| 91 | + help='Option to save trained NN model and framework \ |
| 92 | + generated files at the end of ' |
| 93 | + 'training.') |
| 94 | + parser.add_argument('-t', '--framework-dir', dest='framework_dir', |
| 95 | + action='store', default='/tmp/', type=str, |
| 96 | + help='Prefix of directory to be used by underlying ' |
| 97 | + 'framework (e.g. Ray Rllib, Stable Baselines 3). This ' |
| 98 | + 'name will be passed to the framework.') |
| 99 | + # parser.add_argument('-t', '--tune-hps', dest='tune_hps', action='store', |
| 100 | + # default=False, type=bool, |
| 101 | + # help='Used for tuning the hyperparameters that can be ' |
| 102 | + # 'used for experiments later.' |
| 103 | + # ' A Cartesian product of different configuration values ' |
| 104 | + # 'for the experiment will be taken and ordered as a list ' |
| 105 | + # 'and this number corresponds to the configuration number' |
| 106 | + # ' in this list.' |
| 107 | + # ' Please look in to the code for details.') |
| 108 | + parser.add_argument('-l', '--log-level', default='WARNING', |
| 109 | + help='Set log level.') |
| 110 | + |
| 111 | + |
| 112 | + args = parser.parse_args() |
| 113 | + print("Parsed arguments:", args) |
| 114 | + |
| 115 | + log_levels = { |
| 116 | + 'CRITICIAL': logging.CRITICAL, |
| 117 | + 'ERROR': logging.ERROR, |
| 118 | + 'WARNING': logging.WARNING, |
| 119 | + 'INFO': logging.INFO, |
| 120 | + 'DEBUG': logging.DEBUG, |
| 121 | + 'NOTSET': logging.NOTSET |
| 122 | + } |
| 123 | + |
| 124 | + try: |
| 125 | + log_level_ = log_levels[args.log_level] |
| 126 | + except ValueError: |
| 127 | + logging.error("Log level {} not in {}.".format(args.log_level, |
| 128 | + log_levels.keys())) |
| 129 | + |
| 130 | + config_file = args.config_file |
| 131 | + |
| 132 | + if args.config_file[-3:] == '.py': |
| 133 | + config_file = args.config_file[:-3] |
| 134 | + |
| 135 | + # print("config_file_path:", config_file_path) |
| 136 | + |
| 137 | + stats_file_name = os.path.abspath(args.exp_name) |
| 138 | + |
| 139 | + if args.config_num is not None: |
| 140 | + stats_file_name += '_' + str(args.config_num) |
| 141 | + # elif args.agent_config_num is not None: ###IMP Commented out! If we append both these nums then, that can lead to 1M small files for 1000x1000 configs which doesn't play well with our Nemo cluster. |
| 142 | + # stats_file_name += '_' + str(args.agent_config_num) |
| 143 | + |
| 144 | + print("Stats file being written to:", stats_file_name) |
| 145 | + |
| 146 | + config, final_configs = config_processor.process_configs(config_file, stats_file_prefix=stats_file_name, framework=args.framework, config_num=args.config_num, log_level=log_level_, framework_dir=args.framework_dir) |
| 147 | + |
| 148 | + print("Configuration number(s) that will be run:", "all" if args.config_num is None else args.config_num) |
| 149 | + |
| 150 | + |
| 151 | + # import default_config |
| 152 | + # print("default_config:", default_config) |
| 153 | + # print(os.path.abspath(args.config_file)) # 'experiments/dqn_seq_del.py' |
| 154 | + |
| 155 | + |
| 156 | + import time |
| 157 | + start = time.time() |
| 158 | + |
| 159 | + |
| 160 | + |
| 161 | + if args.config_num is None: |
| 162 | + # final_configs = config.final_configs |
| 163 | + print("Total number of configs to run:", len(final_configs)) |
| 164 | + pass |
| 165 | + else: |
| 166 | + final_configs = [final_configs[args.config_num]] |
168 | 167 |
|
169 |
| -for enum_conf_1, current_config_ in enumerate(final_configs): |
170 |
| - print("current_config of agent to be run:", current_config_, enum_conf_1) |
171 | 168 |
|
172 |
| - algorithm = config.algorithm |
173 | 169 |
|
174 | 170 |
|
175 |
| - tune_config = current_config_ |
176 |
| - print("tune_config:",) |
177 |
| - pp.pprint(tune_config) |
| 171 | + for enum_conf_1, current_config_ in enumerate(final_configs): |
| 172 | + print("current_config of agent to be run:", current_config_, enum_conf_1) |
178 | 173 |
|
| 174 | + algorithm = config.algorithm |
179 | 175 |
|
180 |
| - if 'timesteps_total' in dir(config): |
181 |
| - timesteps_total = config.timesteps_total |
182 |
| - else: |
183 |
| - timesteps_total = tune_config["timesteps_total"] |
184 |
| - |
185 |
| - del tune_config["timesteps_total"] #hack Ray doesn't allow unknown configs |
186 |
| - |
187 |
| - |
188 |
| - print("\n\033[1;32m======== Running on environment: " + tune_config["env"] \ |
189 |
| - + " =========\033[0;0m\n") |
190 |
| - print("\n\033[1;32m======== for " + str(timesteps_total) \ |
191 |
| - + " steps =========\033[0;0m\n") |
192 |
| - |
193 |
| - analysis = tune.run( |
194 |
| - algorithm, |
195 |
| - name=algorithm + '_' + str(stats_file_name.split('/')[-1]) + '_' \ |
196 |
| - , ####IMP "name" has to be specified, otherwise, |
197 |
| - # it may lead to clashing for temp file in ~/ray_results/... directory. |
198 |
| - stop={ |
199 |
| - "timesteps_total": timesteps_total, |
200 |
| - }, |
201 |
| - config=tune_config, |
202 |
| - checkpoint_at_end=args.save_model, |
203 |
| - local_dir=args.framework_dir + '/_ray_results_' + str(args.config_num), |
204 |
| - #return_trials=True # add trials = tune.run( above |
205 |
| - ) |
206 |
| - |
207 |
| - if args.save_model: |
208 |
| - pickle.dump(analysis, open("{}_analysis.pickle".format(args.exp_name), |
209 |
| - "wb")) |
210 |
| - |
211 |
| -config_processor.post_processing(framework=args.framework) |
212 |
| - |
213 |
| -end = time.time() |
214 |
| -print("No. of seconds to run:", end - start) |
| 176 | + |
| 177 | + tune_config = current_config_ |
| 178 | + print("tune_config:",) |
| 179 | + pp.pprint(tune_config) |
| 180 | + |
| 181 | + |
| 182 | + if 'timesteps_total' in dir(config): |
| 183 | + timesteps_total = config.timesteps_total |
| 184 | + else: |
| 185 | + timesteps_total = tune_config["timesteps_total"] |
| 186 | + |
| 187 | + del tune_config["timesteps_total"] #hack Ray doesn't allow unknown configs |
| 188 | + |
| 189 | + |
| 190 | + print("\n\033[1;32m======== Running on environment: " + tune_config["env"] \ |
| 191 | + + " =========\033[0;0m\n") |
| 192 | + print("\n\033[1;32m======== for " + str(timesteps_total) \ |
| 193 | + + " steps =========\033[0;0m\n") |
| 194 | + |
| 195 | + analysis = tune.run( |
| 196 | + algorithm, |
| 197 | + name=algorithm + '_' + str(stats_file_name.split('/')[-1]) + '_' \ |
| 198 | + , ####IMP "name" has to be specified, otherwise, |
| 199 | + # it may lead to clashing for temp file in ~/ray_results/... directory. |
| 200 | + stop={ |
| 201 | + "timesteps_total": timesteps_total, |
| 202 | + }, |
| 203 | + config=tune_config, |
| 204 | + checkpoint_at_end=args.save_model, |
| 205 | + local_dir=args.framework_dir + '/_ray_results_' + str(args.config_num), |
| 206 | + #return_trials=True # add trials = tune.run( above |
| 207 | + ) |
| 208 | + |
| 209 | + if args.save_model: |
| 210 | + pickle.dump(analysis, open("{}_analysis.pickle".format(args.exp_name), |
| 211 | + "wb")) |
| 212 | + |
| 213 | + config_processor.post_processing(framework=args.framework) |
| 214 | + |
| 215 | + end = time.time() |
| 216 | + print("No. of seconds to run:", end - start) |
| 217 | + |
| 218 | + |
| 219 | +if __name__ == '__main__': |
| 220 | + main() |
0 commit comments