nlp-recipes 工具链实战:用 generate_conda_file.py 一键生成 Conda 环境,用 remove_pixelserver.py 清理 Notebook 遥测
nlp-recipes 工具链实战:用 generate_conda_file.py 一键生成 Conda 环境,用 remove_pixelserver.py 清理 Notebook 遥测
本篇技术指南聚焦 microsoft nlp-recipes 开源仓库中 tools 子模块的两大核心脚本:负责为 Python 脚本与示例 Notebook 生成 Conda 环境文件的 generate_conda_file.py,以及用于批量移除示例 Notebook 中 pixelserver 遥测追踪单元的 remove_pixelserver.py。阅读完本文,你将掌握环境 YAML 的生成原理、CPU/GPU 环境与 CUDA 版本参数的全套用法,并理解 Notebook 遥测单元的清理机制,能够在本地、Docker 与 CI 流水线中正确使用这套工具链。
一、tools 子模块概览
仓库根目录的 tools 目录 是 nlp-recipes 的“工具抽屉”,官方 README 明确了该子模块包含两个主要工具:
- generate_conda_file.py:生成用于运行本仓库 Python 脚本与 Notebook 的 Conda 环境文件(YAML);
- remove_pixelserver.py:从所有示例 Notebook 中移除 pixelserver 遥测追踪单元。
除此之外,目录中还包含一个与前者配套的辅助脚本 generate_requirements_txt.py:它直接复用 generate_conda_file.py 中定义的依赖字典,输出一份 requirements.txt,便于在无法使用 Conda 的场景下列出全部依赖。这三个脚本连同 tools/__init__.py 共同构成了仓库的环境与工程化管理基础设施。
二、generate_conda_file.py:环境文件的“生成器”
2.1 设计动机
nlp-recipes 的示例横跨文本分类、命名实体识别、摘要、蕴含推理、问答、句子相似度等多个 NLP 场景,底层依赖既有 PyTorch、TensorFlow 这类深度学习框架,也有 Azure ML SDK、AllenNLP、spaCy、transformers 等繁多的第三方库。手写环境文件既容易出错,也难以在 CPU/GPU、不同操作系统之间保持一致。该脚本用 Python 字典集中管理依赖清单,再按参数与平台动态组装 YAML,从源码注释(generate_conda_file.py)可以清楚看到它的两种基础调用方式:
# 生成仅运行 Python 代码的环境文件(CPU)
python tools/generate_conda_file.py
# 生成支持 GPU 的环境文件
python tools/generate_conda_file.py --gpu
2.2 命令行参数详解
脚本通过标准库 argparse 解析参数(generate_conda_file.py),支持三个选项:
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
--name |
字符串 | nlp_cpu / nlp_gpu |
指定 Conda 环境名,同时决定输出 YAML 文件名 |
--gpu |
布尔开关 | 关闭 | 是否合并 GPU 专属依赖(cudatoolkit、GPU 版 PyTorch、numba) |
--cuda_version |
字符串 | 10.1 |
指定 cudatoolkit 的运行时版本,如 --cuda_version 9.2 |
环境名与输出文件的联动逻辑在 generate_conda_file.py:默认输出 nlp_cpu.yaml,加 --gpu 后输出 nlp_gpu.yaml;一旦传入 --name,则环境名与文件名均使用自定义值。例如在 extractive_summarization_cnndm_aml_distributed.ipynb 中,Notebook 内通过 os.system("python ../../tools/generate_conda_file.py --gpu --name {}".format(CONDA_ENV_NAME)) 动态生成指定名称的 GPU 环境文件,说明该参数在实际示例中被直接依赖。
值得特别注意的是 --cuda_version 与 PyTorch 版本的绑定关系:GPU 模式下脚本固定安装 pytorch==1.4.0,该版本仅兼容 CUDA 9.2 与 10.1 两档运行时(SETUP.md 对此有明确说明)。因此当机器 CUDA 驱动版本低于 10.1 时,必须显式传入 --cuda_version 9.2:
python tools/generate_conda_file.py --gpu --cuda_version 9.2
2.3 依赖清单的组织方式
脚本用一组模块级常量字典维护依赖(generate_conda_file.py),这是整个工具的核心数据结构:
- CHANNELS:
["defaults", "conda-forge", "pytorch"],作为 YAML 中channels:段的三个源,pytorch 频道保证了pytorch-cpu与pytorch==1.4.0可被 conda 正确解析; - CONDA_BASE:所有环境共用的 conda 层依赖,锁定了 Python 运行时与基础科学计算栈;
- CONDA_GPU:仅
--gpu时并入,覆盖 numba、cudatoolkit 与 GPU 版 PyTorch; - PIP_BASE:通过 YAML 的
- pip:子段安装的 pip 依赖,涵盖 NLP 框架、Azure ML SDK 与工程化工具; - 平台分支字典:
CONDA_DARWIN/PIP_LINUX/CONDA_WIN32等按操作系统预置(当前均为空字典,留作扩展位)。
下面将各层的关键依赖分类列出,便于查阅:
conda 层(CONDA_BASE)
| 依赖 | 版本约束 | 用途 |
|---|---|---|
| python | ==3.6.8 |
锁定 Python 运行时 |
| pip | >=19.1.1 |
pip 版本下限 |
| ipykernel / jupyter | >=4.6.1 / >=1.0.0 |
Notebook 内核支持 |
| numpy / scipy / pandas | >=1.13.3 / >=1.0.0 / >=0.24.2 |
科学计算基础 |
| matplotlib | >=2.2.2 |
可视化 |
| pytorch-cpu | >=1.0.0 |
CPU 版 PyTorch |
| tensorflow / tensorflow-hub | ==1.15.0 / ==0.7.0 |
TensorFlow 生态(旧版本锁定) |
| dask[dataframe] | ==1.2.2 |
分布式数据处理 |
| papermill | ==1.2.1 |
Notebook 参数化执行 |
| pytest | >=3.6.4 |
测试 |
conda 层(CONDA_GPU,仅 --gpu)
| 依赖 | 版本约束 | 用途 |
|---|---|---|
| numba | >=0.38.1 |
JIT 编译加速 |
| cudatoolkit | =10.1(可被 --cuda_version 覆盖) |
CUDA 运行时 |
| pytorch | ==1.4.0 |
GPU 版 PyTorch,兼容 CUDA 9.2/10.1 |
pip 层(PIP_BASE)
| 类别 | 依赖及版本约束 |
|---|---|
| 深度学习 | allennlp==0.8.4、transformers==2.9.0、pytorch-pretrained-bert>=0.6、torchtext>=0.4.0、gensim>=3.7.0 |
| Azure ML | azureml-sdk[automl,notebooks,contrib]==1.0.85、azureml-train-automl==1.0.85、azureml-dataprep==1.1.8、azureml-widgets==1.0.85、azureml-mlflow==1.0.85、pydocumentdb>=2.3.3 |
| NLP 工具 | spacy==2.1.8(含 en_core_web_sm 模型)、nltk>=3.4、seqeval>=0.0.12、sklearn-crfsuite>=0.3.6、indic-nlp-library>=0.6、pyrouge>=0.1.3、py-rouge>=1.1 |
| 工程化 | black>=18.6b4、pre-commit>=1.14.4、jupyter 相关(nteract-scrapbook>=0.2.1、ipywebrtc==0.4.3)、tqdm==4.32.2、requests==2.22.0、requests-oauthlib==1.2.0、regex==2020.2.20 |
| 其他 | scikit-learn>=0.19.0,<=0.20.3、seaborn>=0.9.0、pyemd==0.5.1、cached-property==1.5.1、jsonlines>=1.2.0、multiprocess==0.70.9、tensorboardX==1.8、Cython>=0.29.13、googledrivedownloader>=0.4、methodtools、s2s-ft(以可编辑模式从 microsoft/unilm 仓库安装) |
可见 PIP_BASE 中既有 scikit-learn 这类带上下限约束的依赖(>=0.19.0,<=0.20.3),也有大量精确锁定的版本(如 requests==2.22.0、regex==2020.2.20),这保证了仓库示例在不同机器上的可复现性。读者在使用时应以当前仓库源码为准,若将其移植到新项目,需按自身框架版本重新评估这些旧版本约束。
2.4 平台适配与 YAML 组装流程
脚本根据 sys.platform 选择平台专属依赖(generate_conda_file.py):
darwin(macOS)、linux、win32(Windows)分别并入对应的CONDA_*与PIP_*字典;- 不支持的平台直接抛出
Exception("Unsupported platform. Must be Windows, Linux, or macOS"); - 值得注意的是,Windows 并非完全支持,SETUP.md 明确提示“Windows machines are not FULLY SUPPORTED. Please use at your own risk”;
- Windows GPU 分支(
CONDA_WIN32_GPU)在源码中预置了pytorch==1.0.0与cuda90两对键值,属于平台差异化配置的示例。
组装逻辑随后遍历合并后的字典,按固定顺序写出 YAML(generate_conda_file.py):文件头部以 # 注释形式嵌入帮助信息,随后依次输出 name:、channels: 与 dependencies:,并在 dependencies: 末尾追加 - pip: 子段列出所有 pip 包。最终脚本打印生成的文件名与后续使用提示,帮助信息原文如下:
To create the conda environment:
$ conda env create -f {conda_env}.yaml
To update the conda environment:
$ conda env update -f {conda_env}.yaml
To register the conda environment in Jupyter:
$ conda activate {conda_env}
$ python -m ipykernel install --user --name {conda_env} \
--display-name "Python ({conda_env})"
2.5 标准使用流程
结合 SETUP.md 的官方安装指南,完整流程为:
# 1. 生成 CPU 环境文件(默认输出 nlp_cpu.yaml)
python tools/generate_conda_file.py
# 2. 创建环境
conda env create -f nlp_cpu.yaml
# 3. 将环境注册为 Jupyter 内核
conda activate nlp_cpu
python -m ipykernel install --user --name nlp_cpu --display-name "Python (nlp_cpu)"
GPU 机器请先通过 nvidia-smi 查看 CUDA 驱动版本,再决定运行时版本(运行时 ≤ 驱动版本)。驱动 ≥ 10.1 时直接执行 python tools/generate_conda_file.py --gpu;驱动 < 10.1 时使用 --cuda_version 9.2。两种情况下创建环境均为:
conda env create -n nlp_gpu -f nlp_gpu.yaml
环境创建完成后,还需要在仓库根目录执行 pip install -e . 将 utils_nlp 以开发模式安装(详见 setup.py 与 SETUP.md),示例 Notebook 才能正常导入该包。generate_conda_file.py 生成的 YAML 只负责安装依赖,不包含 utils_nlp 本身,二者是配套关系。
2.6 在 Docker 与 CI 流水线中的实际应用
该脚本并非仅供人工使用,仓库内部多处直接依赖它:
- Docker 镜像构建:docker/Dockerfile 在构建阶段执行
python /root/nlp-recipes-staging/tools/generate_conda_file.py --gpu生成nlp_gpu.yaml,随后conda env create -n nlp_gpu -f nlp_gpu.yaml创建环境、pip install -e .安装 utils、并以ipykernel install注册nlp_gpu内核,最终容器以 Jupyter Notebook 形式对外提供8888端口服务; - CI 集成测试:cpu_integration_tests_linux.yml 每晚用
python tools/generate_conda_file.py生成 CPU 环境并执行 smoke/integration 测试;gpu_integration_tests_linux.yml 与 azureml_integration_tests.yml 则使用--gpu分支。这说明“脚本生成环境 → 创建环境 → 跑测试”是该仓库 CI 的标准链路。
2.7 配套脚本:generate_requirements_txt.py
generate_requirements_txt.py 从 generate_conda_file.py 导入全部依赖字典(CONDA_BASE、CONDA_GPU、PIP_BASE、各平台分支等),将所有值合并后用 set 去重,写入根目录下的 requirements.txt。它的存在意味着依赖清单只有一份事实来源——只要 generate_conda_file.py 中的字典更新,requirements.txt 即可重新生成,避免两处手工维护导致漂移。CI 中的 component_governance.yml 就使用该脚本校验依赖清单的一致性。
三、remove_pixelserver.py:批量清理 Notebook 遥测单元
3.1 背景:Notebook 中的数据遥测
仓库中的 Azure ML 相关示例 Notebook 会收集浏览器使用数据并发送给微软用于改进产品(examples/README.md 有官方说明)。这类遥测通常以 markdown 单元格内嵌一张隐藏的“Impressions”图片链接实现,脚本将其称为 pixelserver 追踪。对于不希望上报数据的用户,仓库提供了 remove_pixelserver.py 一键清除。
3.2 识别签名与核心清理逻辑
脚本的核心是 SIGNATURE 常量(remove_pixelserver.py):
SIGNATURE = " 函数(remove_pixelserver.py)的处理流程如下:
- 以 UTF-8 编码读取 Notebook 的 JSON 结构(
json.load); - 若顶层不存在
cells键则直接返回,跳过非 Notebook 文件; - 遍历所有单元格,仅检查
cell_type == 'markdown'的单元格,逐行判断source中是否有以SIGNATURE开头的行,命中则记录该单元格索引并打印定位信息; - 对收集到的索引倒序执行
cells.pop(cell_id)(remove_pixelserver.py)。倒序删除是刻意为之:正序删除会改变后续索引位置,倒序则保证每个索引仍指向原始单元格; - 仅当确有改动时,才以
indent=1回写 JSON 文件,未命中的文件保持原样、不做无谓写入。
3.3 批量处理与使用方式
get_all_notebook_files()(remove_pixelserver.py)以脚本所在路径向上定位仓库根目录,再通过 glob.glob(os.path.join(examples_path, "*/*.ipynb"), recursive=True) 收集 examples 目录下所有子目录中的 .ipynb 文件;若找不到 examples 目录则抛出 ValueError 提示路径错误。main() 遍历全部 Notebook 逐个执行清理。
按 examples/README.md 的官方用法,在仓库根目录执行:
python tools/remove_pixelserver.py
运行后,凡命中签名单元格的 Notebook 都会被就地修改,终端会输出类似 Found pixelserver in file: "...", cell N 的定位日志。从 remove_pixelserver.py 的实现看,它只删除遥测 markdown 单元格,不影响代码单元格与输出,对 Notebook 的正常运行无副作用。
四、工具链小结
| 脚本 | 核心能力 | 关键参数/机制 | 仓库内应用 |
|---|---|---|---|
| generate_conda_file.py | 生成 CPU/GPU Conda 环境 YAML | --gpu、--name、--cuda_version;按平台合并依赖字典 |
docker/Dockerfile、cpu_integration_tests_linux.yml、SETUP.md |
| generate_requirements_txt.py | 从依赖字典生成 requirements.txt | 复用 generate_conda_file.py 的常量,set 去重 | component_governance.yml |
| remove_pixelserver.py | 移除 Notebook 遥测单元格 | SIGNATURE 前缀匹配 + 倒序 pop markdown 单元格 | examples/README.md |
这三个脚本共同体现了 nlp-recipes 工程化的设计思路:用单一事实来源(依赖字典)驱动多格式环境产物,并为示例代码的可复现运行与可选的遥测退出机制提供了开箱即用的解决方案。无论是本地复现示例、构建 Docker 镜像,还是接入 CI 流水线,都可以从这套工具链中找到对应的入口。