[Ray.Tune]使用心得(待完善)

Posted MarToony|名角

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Ray.Tune]使用心得(待完善)相关的知识,希望对你有一定的参考价值。

首先,report中参数,是自行指定的,而参数对应的值需要在程序中有出现,这一点不需要赘述。
同时在report中指定的参数,将会在Ray运行的过程中以表格的形式展现。
比如,

tune.report(loss=(mean_loss), accuracy=test_accuracy, accuracy2= test_accuracy)
# =======================
+---------------------+------------+---------------------+------+--------+------------------+---------+------------+-------------+
| Trial name          | status     | loc                 |   lr |   iter |   total time (s) |    loss |   accuracy |   accuracy2 |
|---------------------+------------+---------------------+------+--------+------------------+---------+------------+-------------|
| DEFAULT_8aa09_00000 | TERMINATED | 172.27.67.94:290338 | 0.01 |      5 |         137.438  | 1.39491 |    53.7037 |     53.7037 |
| DEFAULT_8aa09_00001 | TERMINATED | 172.27.67.94:290340 | 0.1  |      1 |          29.1316 | 1.50628 |    48.8889 |     48.8889 |
+---------------------+------------+---------------------+------+--------+------------------+---------+------------+-------------+

其次,在report中指定的指标,自然也可以当作相关API中参数的候选值被使用,比如接口analysis.get_best_config(metric="accuracy", mode="max"))

logger.info("Best config: ".format(analysis.get_best_config(metric="accuracy", mode="max")))
logger.info("Best config: ".format(analysis.get_best_config(metric="accuracy2", mode="max")))
logger.info("Best config: ".format(analysis.get_best_config(metric="loss", mode="min")))
# =================================
Best config: 'lr': 0.01
Best config: 'lr': 0.01
Best config: 'lr': 0.01

默认地,ray.tune运行时包含的字典的键有以下:

以上内容是在超参数仅学习率,且学习率可选值未0.1和0.01两个值时得到的结果。
该结果通过analysis.dataframe()函数输出,并通过to_csv保存为CSV文件得到。

除此之外,还有一种全局控制输出字段的方式是:

from ray.tune import CLIReporter
reporter = CLIReporter(metric_columns=["loss", "mean_accuracy2", "training_iteration"])

# =======================
+---------------------+------------+---------------------+------+---------+----------------------+
| Trial name          | status     | loc                 |   lr |    loss |   training_iteration |
|---------------------+------------+---------------------+------+---------+----------------------|
| DEFAULT_2d6b3_00000 | RUNNING    | 172.27.67.94:295017 | 0.01 | 1.54909 |                    1 |
| DEFAULT_2d6b3_00001 | TERMINATED | 172.27.67.94:295016 | 0.1  | 2.01156 |                    1 |
+---------------------+------------+---------------------+------+---------+----------------------+

CLIReporter中指定的指标,将会取代reporter函数的指定内容,但并不是完全覆盖,因为CLIReporter中指定的指标只有在reporter中被赋予值后才会在状态表中显示。

Tune的常用API参考界面

1 搜索空间:提供了定义超参数搜索空间的函数

需要注意,预使用的搜索算法要衡量是否与搜索空间中的函数相适用,因为sample_from和grid_search通常并不受支持。

2 搜索算法:开源优化库的包装器,特定的搜索空间定义方式,用于高效的超参数选择

3 调度程序:提前终止不良试验,暂停试验,克隆试验以及更改正在运行的试验的超参数,以优化超算数

4 教程和常见问题:指导如何选择搜索算法和调度算法以及重现试验

5 使用 RAY TUNE 调整超参数:Pytorch官网对Ray Tune的介绍,包含一个完整的小栗子

+ 经典的框架

1 凤头

即,配置一些基本的内容。

一共包含上面六个部分,但是除此之外,还有一处代码设计需要注意:一般地,参数值可以分为两种,需要调整config和不需要调整的参数arg=parser.parse_args()。分开的方式就是:对于tune.run中调用的主函数spot,通过function.partial方法将其与arg捆绑在一起。

搜索空间的定义方式

tune.run(
    trainable,
    config=
        "param1": tune.choice([True, False]), # 从所列出的有限值中选择
        "bar": tune.uniform(0, 10), # 从一个遵从均匀分布的生成器中选择
        "alpha": tune.sample_from(lambda _: np.random.uniform(100) ** 2),
        "const": "hello",  # 面向常量
        "bar": tune.grid_search([True, False]),
    )

完整的代码如下:


def spot(arg, config, checkpoint_dir=None):
    import copy
    arg = copy.deepcopy(arg)
	
	# 为了尽可能地不去修改原始的代码文件,将yaml文件中需要调整的参数在该函数中替换修改。
    arg.base_lr = config["lr"]
    arg.batch_size = config["batch_size"]
    arg.weight_decay = config["weight_decay"]
    arg.step = config["step"]
    arg.optim_args["momentum"] = config["momentum"]
    arg.warm_up_epoch = config["warm_up_epoch"]

    processor = Processor(arg, logdir, model_save_dir)
    processor.start()


if __name__ == '__main__':
    dataType = "skeletons"  # ["images",skeletons]
    yamlConfigPath = './config/dad/clip225/none/agcn/train_bone.yaml'
    logger.info("配置文件:".format(yamlConfigPath))
    parser = get_parser(yamlConfigPath)
    p = parser.parse_args()  # 当前py文件中预定义好的参数字典。

    if p.config is not None:
        with open(p.config, 'r') as f:
            default_arg = yaml.full_load(f)  # yaml文件中的参数字典
        key = vars(p).keys()
        for k in default_arg.keys():
            if k not in key:
                print('WRONG ARG: '.format(k))
                assert (k in key)
        parser.set_defaults(**default_arg)
    arg = parser.parse_args()

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    init_seed(arg.seed)

    # 所有的参数在这里之前都要确定下来。
    with open('/config.yaml'.format(logdir), 'w') as f:
        yaml.dump(vars(arg), f)

    config = 
        "lr": tune.choice([0.1, 0.01, 0.001, 0.05, 0.005]),
        "batch_size": tune.grid_search([16, 32, 64, 128]),
        "weight_decay": tune.grid_search([0.0001, 0.0003, 0.0005]),
        "step": tune.grid_search([[45, 55, 65],
                                  [30, 50],
                                  [20, 40, 60]]),
        "momentum": tune.grid_search([0.7, 0.8, 0.9]),
        "warm_up_epoch": tune.grid_search([0, 5, 10])
    

    scheduler = ASHAScheduler(
        metric="accuracy",
        mode="max",
        max_t=65,
        grace_period=1,
        reduction_factor=2)

    reporter = CLIReporter(
        metric_columns=["loss", "accuracy", "training_iteration"])

    analysis = tune.run(
        partial(spot, arg),
        num_samples=200,
        resources_per_trial="cpu": 16, "gpu": 1,
        config=config,
        scheduler=scheduler,
        progress_reporter=reporter
    )

2 猪肚

核心还是Processor类,由其中的start函数启动训练。
原始的项目代码基本上没有修改,经由spot函数连接Ray.tune和processor。
耦合度得到提升。

3 龙尾

# 获取结果的 dataframe
import pandas as pd
pd.set_option('display.max_columns', None)

# 1 返回一个由所有实验信息构建成的pandas.DataFrame对象。
df = analysis.dataframe()
df.to_csv("df_testcsv.csv")
logger.info("df:\\n".format(df))

# 2 返回 List of all dataframes of the trials.
dfs = analysis.trial_dataframes
logger.info("dfs:\\n".format(dfs))

# 3 显示各个实验的结果。
from matplotlib.pyplot import plt
ax = None  # This plots everything on the same plot
for d in dfs.values():
    ax = d.loss.plot(ax=ax, legend=True)

plt.xlabel("epoch")
plt.ylabel("Test Accuracy")
plt.show()

# 4 显示最好的配置结果。
logger.info("Best config: ".format(analysis.get_best_config(metric="accuracy", mode="max")))
logger.info("Best config: ".format(analysis.get_best_config(metric="loss", mode="min")))

best_trial = analysis.get_best_trial("loss", "min", "last")
logger.info("Best trial config1: ".format(best_trial.config))
logger.info("Best trial final validation loss: ".format(best_trial.last_result["loss"]))
logger.info("Best trial final validation accuracy: ".format(best_trial.last_result["accuracy"]))

best_trial = analysis.get_best_trial("accuracy", "max", "last")
logger.info("Best trial config2: ".format(best_trial.config))
logger.info("Best trial final validation loss: ".format(best_trial.last_result["loss"]))
logger.info("Best trial final validation accuracy: ".format(best_trial.last_result["accuracy"]))

analysis = tune.run(trainable, search_alg=algo, stop="training_iteration": 20)

best_trial = analysis.best_trial  # Get best trial
best_config = analysis.best_config  # Get best trial's hyperparameters
best_logdir = analysis.best_logdir  # Get best trial's logdir
best_checkpoint = analysis.best_checkpoint  # Get best trial's best checkpoint
best_result = analysis.best_result  # Get best trial's last results
best_result_df = analysis.best_result_df  # Get best result as pandas dataframe

# 5 加持最后的配置参数得到的结果。
import copy
arg = copy.deepcopy(arg)
arg.base_lr = best_trial.config["lr"]
arg.batch_size = best_trial.config["batch_size"]
arg以上是关于[Ray.Tune]使用心得(待完善)的主要内容,如果未能解决你的问题,请参考以下文章

满足复杂条件时提前停止 ray.tune 实验?

Ray[tune] for pytorch TypeError: ray.cloudpickle.dumps

[Ray.Tune] [已解决] TypeError: ray.cloudpickle.dumps

[Ray.Tune] [已解决] TypeError: ray.cloudpickle.dumps

如何在 Ray Tune 中定义与搜索算法无关的高维搜索空间?

[Ray.Tune] [已解决] Queue objects should only be shared between processes through inheritance