
在 Ray Tune 中使用 Nevergrad无导数超参数优化的完整实战指南【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray导读本文围绕 Ray Tune 官方提供的 Nevergrad 集成示例讲解如何将 Facebook 的无导数优化框架 Nevergrad 作为 Tune 的搜索算法Search Algorithm自动完成超参数寻优。读完本文你将掌握NevergradSearch的完整配置方式、Tune 搜索空间与 Nevergrad 参数化对象的自动/手动转换、并发限制与调度器组合用法以及底层 ask/tell 优化循环与检查点恢复原理可直接套用到真实训练任务中。一、Nevergrad 与 Ray Tune从官方示例说起Ray Tune 提供了丰富的搜索算法生态NevergradSearch是其与 facebookresearch/nevergrad文档页 doc/source/tune/examples/includes/nevergrad_example.rst 通过literalinclude指令直接引用该脚本并在 doc/source/tune/examples/index.rst 中以Nevergrad Example条目呈现同时提供了可交互运行的 Notebook 版本 doc/source/tune/examples/nevergrad_example.ipynb。示例脚本的 docstring 说明了它的两个核心用途This example demonstrates the usage of Nevergrad with Ray Tune. It also checks that it is usable with a separate scheduler.也就是说该示例不仅是集成展示还专门验证了Nevergrad 搜索算法与独立调度器如 AsyncHyperBandScheduler可以协同工作——这是很多初学者容易忽略的要点搜索算法负责建议下一组超参数调度器负责提前终止或放行试验两者职责正交、可自由组合。前置依赖运行示例前必须安装 Nevergradpip install nevergrad在 nevergrad_search.py 的源码中import nevergrad as ng被包在try/except ImportError中未安装时相关符号被置为None而NevergradSearch.__init__会直接断言报错提示安装命令。因此不安装依赖就实例化NevergradSearch会在构造阶段立即失败而不是等到运行期才暴露。二、示例代码逐段拆解2.1 训练目标函数import time from ray import tune from ray.tune.schedulers import AsyncHyperBandScheduler from ray.tune.search import ConcurrencyLimiter from ray.tune.search.nevergrad import NevergradSearch def evaluation_fn(step, width, height): return (0.1 width * step / 100) ** (-1) height * 0.1 def easy_objective(config): # Hyperparameters width, height config[width], config[height] for step in range(config[steps]): # Iterative training function - can be any arbitrary training procedure intermediate_score evaluation_fn(step, width, height) # Feed the score back back to Tune. tune.report({iterations: step, mean_loss: intermediate_score}) time.sleep(0.1)easy_objective是一个典型的迭代式训练函数每次迭代计算一个中间分数并通过tune.report把iterations和mean_loss汇报给 Tune。time.sleep(0.1)用于模拟真实训练的开销让调度器有观察中途结果的窗口。这里tune.report的机制非常关键——它使得Tune 可以按mean_loss这一指标实时比较试验AsyncHyperBandScheduler能据此提前终止表现不佳的试验把资源让给更有潜力的配置。2.2 主流程组装搜索算法与调度器if __name__ __main__: import argparse import nevergrad as ng parser argparse.ArgumentParser() parser.add_argument( --smoke-test, actionstore_true, helpFinish quickly for testing ) args, _ parser.parse_known_args() # Optional: Pass the parameter space yourself # space ng.p.Dict( # widthng.p.Scalar(lower0, upper20), # heightng.p.Scalar(lower-100, upper100), # activationng.p.Choice(choices[relu, tanh]) # ) algo NevergradSearch( optimizerng.optimizers.OnePlusOne, # spacespace, # If you want to set the space manually ) algo ConcurrencyLimiter(algo, max_concurrent4) scheduler AsyncHyperBandScheduler() tuner tune.Tuner( easy_objective, tune_configtune.TuneConfig( metricmean_loss, modemin, search_algalgo, schedulerscheduler, num_samples10 if args.smoke_test else 50, ), run_configtune.RunConfig(namenevergrad), param_space{ steps: 100, width: tune.uniform(0, 20), height: tune.uniform(-100, 100), activation: tune.choice([relu, tanh]), }, ) results tuner.fit() print(Best hyperparameters found were: , results.get_best_result().config)主流程包含几个值得深入说明的环节选择 Nevergrad 优化器这里使用ng.optimizers.OnePlusOne(11)-ES 进化策略无导数优化的经典基线算法。Nevergrad 提供了大量优化器均可直接传入。并发限制ConcurrencyLimiter(algo, max_concurrent4)将搜索算法的最大并行试验数限制为 4。原因在于 Nevergrad 的 ask/tell 协议本质上是串行依赖的——下一步建议依赖上一步反馈天然不擅长高并发。关于这一点下文底层原理一节会结合源码详细解释。独立调度器AsyncHyperBandScheduler()是 Tune 内置的异步超带调度器与搜索算法并行配置、互不干扰这正是示例想验证的核心场景。指标与方向metricmean_loss, modemin告诉 Tune 和 Nevergrad 要最小化mean_loss。--smoke-test模式将采样数从 50 压缩到 10用于快速验证管线是否打通适合 CI 与本地冒烟测试。运行方式# 正常完整运行50 次采样 python python/ray/tune/examples/nevergrad_example.py # 快速冒烟测试10 次采样 python python/ray/tune/examples/nevergrad_example.py --smoke-test运行结束后打印最优配置results.get_best_result().config。三、NevergradSearch 核心参数详解NevergradSearch的构造签名位于 nevergrad_search.py完整参数如下参数类型含义默认值optimizerOptimizer/Type[Optimizer]/ConfiguredOptimizerNevergrad 提供的优化器类或实例None必传optimizer_kwargsdict实例化optimizer时传入的关键字参数Nonespacedict/ParameterNevergrad 参数化对象或传入优化器实例时传参数名列表Nonemetricstr目标指标名称不传但指定了mode时默认使用匿名指标_metricNonemodestrmin或max决定最小化还是最大化Nonepoints_to_evaluateList[Dict]首批优先运行的初始参数建议热启动None结合源码逐项说明3.1 optimizer三类可接受对象源码 nevergrad_search.py 对optimizer参数做了严格的三分支校验Optimizer实例直接使用该实例。此时space要么是None要么是参数名列表不能是参数字典否则抛ValueError同时不能再传optimizer_kwargs。Optimizer子类class保存为_opt_factory在_setup_nevergrad中通过self._opt_factory(self._space, **self._optimizer_kwargs)延迟实例化。这是示例采用的方式。ConfiguredOptimizer实例Nevergrad 0.2.0 支持的预配置优化器同样走_opt_factory路径。三者都不满足时抛ValueError提示必须传入Optimizer或ConfiguredOptimizer。optimizer_kwargs的典型用法见测试 test_searchers.py某些优化器如ng.optimizers.CM构造时必须指定budget此时必须用optimizer_kwargsdict(budget16)补全NevergradSearch(optimizerng.optimizers.CM, optimizer_kwargsdict(budget16))3.2 metric / mode 与符号处理mode只允许min或max否则断言失败。值得注意的底层细节在 nevergrad_search.py# nevergrad.tell internally minimizes, so max -1 if self._mode max: self._metric_op -1.0 elif self._mode min: self._metric_op 1.0Nevergrad 优化器内部统一做最小化因此当用户指定modemax时Tune 在把结果反馈给 Nevergrad 前会乘以-1把最大化问题等价转换为最小化问题。这一符号翻转对上层完全透明。3.3 points_to_evaluate热启动已有经验如果你已有一组效果不错的参数例如手工调过的基线可以通过points_to_evaluate让它们最先被运行帮助优化器从好起点出发current_best_params [{ width: 10, height: 0, activation: relu, }] ng_search NevergradSearch( optimizerng.optimizers.OnePlusOne, metricmean_loss, modemin, points_to_evaluatecurrent_best_params, )源码中有一个巧妙的细节nevergrad_search.pyif self._points_to_evaluate: # Nevergrad is LIFO, so we add the points to evaluate in reverse # order. for i in range(len(self._points_to_evaluate) - 1, -1, -1): self._nevergrad_opt.suggest(self._points_to_evaluate[i])Nevergrad 的建议队列是LIFO后进先出因此 Tune 按逆序注入这些初始点保证列表顺序与实际运行顺序一致。points_to_evaluate必须是一个字典的序列否则抛出类型错误的ValueError。四、搜索空间自动转换与手动传递4.1 自动转换Tune 空间 → Nevergrad 参数化示例中不传space而是直接给param_space写 Tune 原生搜索空间param_space{ steps: 100, width: tune.uniform(0, 20), height: tune.uniform(-100, 100), activation: tune.choice([relu, tanh]), },Tune 会在set_search_properties阶段调用convert_search_space将 Tune 空间翻译为ng.p.Dict。转换规则位于 nevergrad_search.pyTune 搜索空间Nevergrad 参数说明tune.uniform(low, high)ng.p.Scalar(lower, upper)连续均匀分布tune.loguniform(low, high)ng.p.Log(lower, upper, exponentmath.e)对数均匀底数为自然对数 etune.randint(low, high)ng.p.Scalar(lower, upper-1).set_integer_casting()整型上界右开自动做整数截断tune.qrandint/tune.quniform同上 丢弃量化见下方量化说明tune.choice([...])ng.p.Choice(choices...)类别选择嵌套字典a/b/c扁平化键最终ng.p.Dict(**space)两个需要特别留意的边界网格搜索grid_search不被支持convert_search_space检测到grid_vars时直接抛ValueErrorGrid search parameters cannot be automatically converted to a Nevergrad search space.。Nevergrad 是无导数连续优化器语义上与网格穷举不兼容。量化Quantized被静默丢弃当检测到Quantized采样器时会打印警告 Nevergrad does not support quantization. Dropped quantization.并退化为底层采样器继续转换。另外Integer域转换为ng.p.Scalar时上界要-1这是为保持 Tune 的右开区间语义randint(low, high)不含high。4.2 手动传递空间若想完全掌控参数化方式可以手动构造ng.p.Dict并传给space参数示例代码中注释掉的部分import nevergrad as ng space ng.p.Dict( widthng.p.Scalar(lower0, upper20), heightng.p.Scalar(lower-100, upper100), activationng.p.Choice(choices[relu, tanh]) ) ng_search NevergradSearch( optimizerng.optimizers.OnePlusOne, spacespace, metricmean_loss, modemin, )手动模式适合使用 Nevergrad 的高级参数化能力如ng.p.Log、ng.p.Choice的权重、软/硬约束、ng.p.Instrumentation等。需注意仪器化instrumentation的约束若优化器带instrumentation且包含 kwargs则_parameters必须为None若非仪器化优化器则必须提供与优化器维度一致的参数名列表否则报错nevergrad_search.py。4.3 维度校验对于非仪器化优化器_setup_nevergrad会校验len(parameters_names)必须等于优化器维度if self._parameters is not None and self._nevergrad_opt.dimension ! len(self._parameters): raise ValueError( len(parameters_names) must match optimizer dimension for non-instrumented optimizers )这能提前发现参数空间与优化器配置不匹配的问题避免运行到一半才暴露。五、底层原理ask/tell 优化循环与并发限制NevergradSearch通过继承Searcher基类融入 Tune 的搜索协议核心是suggest与on_trial_complete两个回调nevergrad_search.pyTune 需要新试验 ──► suggest(trial_id) ──► nevergrad_opt.ask() 取一个候选点 │ 试验结束 ──► on_trial_complete(trial_id, result) │ └──► _process_result: nevergrad_opt.tell(候选点, metric_op * result[metric]) 优化器据此更新内部模型生成更优的下一个建议关键点逐一说明候选与试验的映射suggest用self._live_trial_mapping[trial_id] suggested_config记录哪个候选点给了哪个试验on_trial_complete时再按trial_id取回对应候选点反馈给 Nevergrad。因此试验必须按完成顺序逐个 tell不能乱序。候选格式处理Nevergrad 0.2.0 的ask()返回Candidate对象含args和kwargs字段。Tune 分三种情况处理nevergrad_search.py有kwargs直接返回unflatten_dict(suggested_config.kwargs)无kwargs且传了参数名列表zip参数名与args[0]拼成字典否则使用suggested_config.value。未初始化时报错若优化器尚未建立搜索空间未定义suggest抛UNDEFINED_SEARCH_SPACE若metric或mode缺失抛UNDEFINED_METRIC_MODE。这解释了为什么Tuner配置里必须同时给出metric和mode。串行依赖 ⇒ 需要并发限制由于每次tell后优化器状态才更新、ask才给出新建议Nevergrad 的天然工作方式是一个试验跑完再给下一个。因此示例中用ConcurrencyLimiter(algo, max_concurrent4)把并行度限制为 4——既允许流水线化、不浪费计算资源又不会因海量未完成试验导致建议质量下降。这是使用NevergradSearch时最重要的实践要点。与调度器协同的验证测试 test_searchers.py 使用_invalid_objective会产生nan/inf/负值等异常度量配合ng.optimizers.RandomSearch和modemax运行 16 次采样验证搜索器面对脏数据仍能产出正确实验输出示例脚本则在真实场景层面验证了搜索算法 AsyncHyperBandScheduler的组合可用性。这也印证了 Tune 的设计哲学搜索算法管往哪探索调度器管何时止损两者解耦、可任意组合。六、检查点保存与恢复NevergradSearch实现了save/restorenevergrad_search.py通过 pickle 序列化整个__dict__状态def save(self, checkpoint_path: str): save_object self.__dict__ with open(checkpoint_path, wb) as outputFile: pickle.dump(save_object, outputFile) def restore(self, checkpoint_path: str): with open(checkpoint_path, rb) as inputFile: save_object pickle.load(inputFile) self.__dict__.update(save_object)这意味着优化器的内部状态含已 tell 的所有历史点可以被持久化实验中断后可从检查点恢复避免重复采样。相关测试见 test_searchers.py分别验证了带空间实例化后保存/恢复与只传optimizer的极简实例化后保存/恢复两条路径注释明确说明optimizer是唯一必需参数。由于save使用 pickle恢复场景要求优化器对象可被 pickle 序列化——这也是为什么optimizer推荐传入类而非已实例化对象的原因之一类 空间的组合序列化更稳定。七、总结与最佳实践清单以官方示例 nevergrad_example.py 为骨架使用NevergradSearch的完整套路可归纳为安装依赖pip install nevergrad必须构造阶段即校验。定义训练函数用tune.report周期性汇报中间指标让调度器有止损依据。选择优化器从ng.optimizers中选择如OnePlusOne、RandomSearch、CMA/CM等需要构造参数的用optimizer_kwargs传入。描述搜索空间优先用 Tune 原生空间自动转换需要高级参数化时手动构造ng.p.Dict传给space。避免grid_search与量化参数。设定目标在TuneConfig中明确metric与modemin/max 由 Tune 自动翻转给 Nevergrad。控制并发用ConcurrencyLimiter限制max_concurrent适配 ask/tell 的串行依赖特性。组合调度器可自由叠加AsyncHyperBandScheduler等调度器提前终止差试验、节省算力。热启动已有经验配置通过points_to_evaluate优先运行。容错与恢复利用内置save/restore在中断后继续实验。这套模式对任何评估代价高、参数维度不高的调参场景如模型超参、仿真参数、管线配置都直接适用是 Ray Tune 生态中兼顾算法多样性与工程健壮性的典型范例。【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考