☰
从 run_tests.sh 到 uv+pytest:Hyperopt 单元测试完整运行指南
2026/9/28 7:51:36 网站建设 项目流程
  • 机器学习
  • AutoML

【免费下载链接】hyperopt

Distributed Asynchronous Hyperparameter Optimization in Python

项目地址:https://gitcode.com/gh_mirrors/hy/hyperopt
点击查看免费下载

本篇指南围绕仓库文档 docs/templates/setup/running-tests.md 展开,系统讲解 Hyperopt 单元测试的运行方法:SPARK_HOME与HYPEROPT_FMIN_SEED两个环境变量的含义、run_tests.sh的四种调用形态(全量、单文件、跳过 Spark、组合使用),并结合当前仓库的源码与 CI 配置,给出uv run pytest、nox、GitHub Actions 等现代等价实践。读完本文,你可以本地复现 Hyperopt 的全部或部分测试套件,并理解随机种子在fmin()底层是如何生效的。

环境准备:运行测试前的依赖清单

原文档假设你已经在项目根目录下拿到了仓库源码,并且本地具备 Python 环境。从当前仓库快照看,pyproject.toml 声明了核心运行依赖(numpy>=1.17、scipy>=1.5.0、networkx>=2.2、tqdm、cloudpickle),并限定requires-python = ">=3.10"。

测试相关依赖按用途拆分在 pyproject.toml 中:

  • SparkTrials可选依赖:["pyspark", "py4j"],运行 Spark 集成测试时必需;
  • MongoTrials可选依赖:["pymongo>=4.0.0"],运行 MongoDB 相关测试时必需;
  • ATPE可选依赖:["lightgbm", "scikit-learn"];
  • 依赖组testing:pytest加以上全部 extras,即"pytest", "hyperopt[SparkTrials,MongoTrials,ATPE]";
  • 依赖组dev:包含testing组、lint(mypy)、pre-commit、nox、pyyaml。

因此,一条命令即可装齐测试环境:

# 方式一:pip 直接安装(含全部测试可选依赖) pip install "hyperopt[SparkTrials,MongoTrials,ATPE]" pytest # 方式二:uv 一键同步(README 推荐的开发方式,见 README.md 第 87 行) uv sync --group dev

需要特别说明:原文档所引用的run_tests.sh、.travis.yml、download_spark_dependencies.sh在当前仓库快照中均已不存在(仓库根目录已无任何.sh脚本,CI 配置全部收敛到 .github/workflows 下)。也就是说,文档描述的是早期 Travis CI 时代的测试入口,而当前仓库已经迁移到「uv 管理依赖 + pytest 执行 + nox 多版本 + GitHub Actions 持续集成」的体系。下文会同时保留原文档命令的完整用法,并给出当前仓库中的等价做法。

两个关键环境变量

SPARK_HOME:本地 Apache Spark 副本路径

原文档要求设置SPARK_HOME指向本地 Apache Spark 副本,并提示“查看.travis.yml和download_spark_dependencies.sh了解下载细节”。在那个年代,跑 Spark 相关测试需要预先下载并解压 Spark 发行包,然后通过SPARK_HOME让 PySpark 找到它。

当前仓库的测试不再依赖本地 Spark 发行包:SparkTrials所需的pyspark与py4j直接作为 Python 包安装(见 pyproject.toml),集成测试通过SparkSession.builder.master("local[N]")在进程内拉起本地 Spark 集群(见 hyperopt/tests/integration/test_spark.py,默认 4 个 executor)。因此,在当前的 uv/pytest 体系下,SPARK_HOME通常不再需要显式设置;只有当你的环境仍在使用老脚本或自定义 Spark 安装时,才需要按原文档的方式配置它。

HYPEROPT_FMIN_SEED:fmin 的随机种子

原文档要求从.travis.yml中获取该值,其本质是让整轮调优过程可复现。这个环境变量并不仅是测试脚本的“装饰品”,它在fmin()的源码中真实生效:

hyperopt/fmin.py 中,fmin()在rstate参数未显式给出时,会读取该环境变量:

env_rseed = os.environ.get("HYPEROPT_FMIN_SEED", "") if env_rseed: rstate = np.random.default_rng(int(env_rseed)) else: rstate = np.random.default_rng()

对应的文档注释在 hyperopt/fmin.py:每次调用搜索算法(algo)都需要一个随机种子,rstate就是用来通过randint派生这些种子的对象。设置HYPEROPT_FMIN_SEED后,测试中的随机搜索、TPE 等算法会以确定性方式推进,保证同一份代码、同一个种子得到完全一致的试验序列,这正是单元测试稳定可复现的关键。示例命令中使用的3是当时.travis.yml约定的取值;在当前 CI 中并未硬编码该变量(见 .github/workflows/test.yml),具体测试也可以通过rstate=np.random.default_rng(...)在调用层直接指定,例如 hyperopt/tests/integration/test_spark.py。

使用 run_tests.sh 运行单元测试(原文档命令全量保留)

run_tests.sh是仓库根目录下的测试入口脚本,通过前置环境变量和位置参数组合出四种运行形态。

1. 运行全部单元测试

hyperopt$ HYPEROPT_FMIN_SEED=3 SPARK_HOME=/usr/local/lib/spark-2.4.4-bin-hadoop2.7 ./run_tests.sh
  • 不带任何参数时执行完整测试套件;
  • SPARK_HOME指向spark-2.4.4-bin-hadoop2.7这类具体发行版目录(版本号仅为示例,按你本地实际下载的 Spark 版本填写);
  • HYPEROPT_FMIN_SEED=3让随机性可复现。

2. 只运行单个测试文件

hyperopt$ HYPEROPT_FMIN_SEED=3 SPARK_HOME=/usr/local/lib/spark-2.4.4-bin-hadoop2.7 ./run_tests.sh hyperopt/tests/test_spark.py

把目标文件路径作为位置参数传给脚本即可,适合迭代式开发时快速验证某一个模块。

3. 运行全部单元测试但跳过 Spark 相关用例

hyperopt$ HYPEROPT_FMIN_SEED=3 ./run_tests.sh --no-spark

--no-spark用于排除 Spark 依赖场景:当本地没有 Spark 环境、不想启动本地 Spark 集群、或只想快速跑非分布式逻辑时使用。注意此形态下SPARK_HOME已不再需要。

4. 跳过 Spark 并只运行单个非 Spark 测试文件

hyperopt$ HYPEROPT_FMIN_SEED=3 ./run_tests.sh --no-spark test_base.py

--no-spark之后的位置参数指定具体文件,例如test_base.py(对应 hyperopt/tests/test_base.py)。

四种形态可以归纳为一张参数语义表:

调用形态参数作用域是否需要 SPARK_HOME
./run_tests.sh无全部测试是
./run_tests.sh <file>文件路径仅该文件是
./run_tests.sh --no-spark--no-spark全部测试,排除 Spark否
./run_tests.sh --no-spark <file>--no-spark+ 文件路径仅该非 Spark 文件否

一个需要注意的路径差异:原文档命令写作hyperopt/tests/test_spark.py,而当前仓库中该文件实际位于 hyperopt/tests/integration/test_spark.py(test_base.py仍在 hyperopt/tests/test_base.py)。按当前仓库结构执行时应使用hyperopt/tests/integration/test_spark.py。

当前仓库的现代测试路径:uv + pytest + nox + CI

直接运行 pytest

README.md 给出的测试命令是:

uv run pytest

由于 pytest 配置([tool.pytest.ini_options],见 pyproject.toml)已排除dist、build、.venv、.nox等目录,并从 scipy 内部测试继承了slow、xslow、thread_unsafe三个 marker,因此一条uv run pytest即可覆盖全部单测与集成测试(前提是已通过uv sync --group dev装好pyspark、pymongo等可选依赖)。

只跑一个文件等价于原文档的第二种形态:

uv run pytest hyperopt/tests/integration/test_spark.py # 或非 Spark 文件 uv run pytest hyperopt/tests/test_base.py

跳过 Spark 的等价做法是只选择对应路径:

uv run pytest hyperopt/tests/unit hyperopt/tests/test_base.py

多 Python 版本矩阵:nox

noxfile.py 以 .github/workflows/test.yml 为“单一事实来源”,自动解析 CI 中的 Python 版本矩阵与测试步骤并生成对应 session:

uv run nox # 所有支持的 Python 版本顺序执行 uv run nox -s tests_parallel # 所有版本并行执行 uv run nox -p 3.12 # 只跑某个具体版本

CI 中的真实测试流程

.github/workflows/test.yml 展示了当前仓库 CI 的实际测试步骤,它是原文档“从.travis.yml获取种子/Spark 配置”的现代替代品:

  1. 在 Python 3.10–3.14 矩阵上安装 uv;
  2. uv sync --group dev安装全部依赖;
  3. PYSPARK_PIN_THREAD=true uv run pytest:pin 线程模式下跑全量测试;
  4. PYSPARK_PIN_THREAD=false uv run pytest hyperopt/tests/integration/test_spark.py:再以非 pin 线程模式单独验证 Spark 插件。

PYSPARK_PIN_THREAD控制 PySpark 线程模型,两种模式都要覆盖正是 Spark 集成测试的特别之处——这也解释了原文档为何要为 Spark 单独设置SPARK_HOME并允许--no-spark跳过:Spark 相关用例对环境最敏感,理应可独立开关。

测试套件全景:unit 与 integration

从当前仓库目录结构看,测试分为三层:

目录文件覆盖内容
hyperopt/tests/test_base.py基础Trials/状态机等核心逻辑
hyperopt/tests/unit/test_anneal.py、test_atpe_basic.py、test_criteria.py、test_domains.py、test_fmin.py、test_ipy.py、test_pchoice.py、test_plotting.py、test_progress.py、test_pyll_utils.py、test_rand.py、test_randint.py、test_rdists.py、test_tpe.py、test_utils.py、test_vectorize.py、test_webpage.py各搜索算法(TPE、ATPE、anneal、随机搜索)、搜索空间采样、pyll 工具、进度条与绘图等纯 Python 单元逻辑
hyperopt/tests/integration/test_mongoexp.py、test_sklearn.py、test_spark.py需要外部运行时(MongoDB、scikit-learn、Spark 集群)的集成场景

原文档中“跑单个非 Spark 文件”的典型对象test_base.py位于最顶层目录,是快速冒烟的首选;而test_spark.py属于集成测试,对应--no-spark所要排除的那一类。

Spark 集成测试深入:test_spark.py 与 SparkTrials

既然原文档围绕SPARK_HOME与test_spark.py展开,这里给出该测试文件背后的实现细节,方便理解“为什么要单独处理 Spark 测试”。

本地集群的拉起方式

hyperopt/tests/integration/test_spark.py 中,测试基类通过SparkSession.builder.master(f"local[{NUM_SPARK_EXECUTORS}]")启动本地集群,NUM_SPARK_EXECUTORS = 4,并顺手把spark.sql.shuffle.partitions调成 4 以加速小测试。这意味着 Spark 集成测试并不依赖外部集群,只需pyspark已安装。

SparkTrials 的可配置项

被测对象SparkTrials定义在 hyperopt/spark.py,其构造参数(hyperopt/spark.py)与原文档配套文档 docs/templates/scaleout/spark.md 一致:

  • parallelism:最大并发试验数。若为None或非正值,将取 SparkdefaultParallelism与 1 的较大者;同时受硬上限MAX_CONCURRENT_JOBS_ALLOWED = 128约束(hyperopt/spark.py 中的_decide_parallelism会打印警告并封顶);
  • timeout:允许fmin()运行的最大秒数,超时后取消未完成任务并返回已有结果;
  • loss_threshold:提前停止阈值;
  • spark_session:显式传入SparkSession,否则自动getOrCreate();
  • resource_profile:stage 级调度资源画像,仅当 Spark 版本支持时生效。

对应的集成测试逐一验证了这些行为,例如以SparkTrials(parallelism=4)跑通test_quadratic1_tpe(复用 hyperopt/tests/unit/test_fmin.py 的用例,见 hyperopt/tests/integration/test_spark.py)、验证 parallelism 超过 128 被截断(hyperopt/tests/integration/test_spark.py)、验证非法timeout(如-1、True)被validate_timeout拒绝(hyperopt/tests/integration/test_spark.py)。这些测试正是原文档中./run_tests.sh hyperopt/tests/test_spark.py这条命令实际要执行的内容。

注意事项与常见问题

  • 脚本与文件路径的版本差异:原文档中的run_tests.sh、.travis.yml、download_spark_dependencies.sh在当前仓库快照中已不存在,hyperopt/tests/test_spark.py也已迁移到hyperopt/tests/integration/。以当前仓库为准时,请使用 .github/workflows/test.yml 与 noxfile.py 描述的流程,并注意路径为hyperopt/tests/integration/test_spark.py。
  • SPARK_HOME是否必需:原文档要求设置该变量,但这属于旧版本地 Spark 发行包的用法;当前pyspark/py4j通过 pip 安装即可,local[N]模式会自动拉起进程内集群。若使用老脚本或自定义 Spark 安装,仍需按原文档配置。
  • HYPEROPT_FMIN_SEED的作用范围:它只影响fmin()默认rstate的初始化(hyperopt/fmin.py),对显式传入rstate的调用不生效;测试中若要精确控制随机性,更推荐像 hyperopt/tests/integration/test_spark.py 那样直接传入np.random.default_rng(seed)。
  • MongoDB 相关测试:test_mongoexp.py属于集成测试,需要 MongoDB 可用(安装与验证方式见 docs/templates/setup/installation-notes.md)。在当前仓库中其路径为hyperopt/tests/integration/test_mongoexp.py,且依赖MongoTrials可选组中的pymongo>=4.0.0。

总之,原文档给出的四种run_tests.sh形态——全量、单文件、--no-spark、--no-spark+ 单文件——构成了 Hyperopt 测试的基本操作骨架;在理解SPARK_HOME与HYPEROPT_FMIN_SEED语义的基础上,将其映射到当前仓库的uv run pytest/ nox / CI 流程,即可在任何环境下稳定地复现和验证 Hyperopt 的测试套件。

  • 机器学习
  • AutoML

【免费下载链接】hyperopt

Distributed Asynchronous Hyperparameter Optimization in Python

项目地址:https://gitcode.com/gh_mirrors/hy/hyperopt
点击查看免费下载

相关推荐

上一篇:Easy-Scraper:让网页数据采集变得简单高效
下一篇:如何快速上手harrier-oss-v1-270m?Sentence Transformers与Transformers双实现教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询