Conda导出环境YAML含多余依赖,求原因及精简方法
问题背景
我使用conda==4.12.0(基于Miniconda)通过脚本创建了干净的py37_clean环境,用pip安装了requirements.txt中的指定包后,执行conda env export生成environment.yml时,发现文件包含多余依赖(比如pytorch=1.3.1=cpu_py37h0c87eb2_0)。用mamba repoquery depends -t pytorch检查未找到其依赖关系,想知道该情况的原因,以及如何限制Conda包仅保留必要项。
requirements.txt内容(已翻译注释):
boto31.26.117
matplotlib3.3.4
numpy1.15 # PySpark要求的版本
pandas1.0.5 # PySpark要求的版本
pre-commit2.21.0
praw7.7.0
pg80001.29.4 # 这个包用pip安装比psycopg2更简单
pyarrow2.0.0
pyspark3.3.0 # 用这个版本是因为PySpark 3.4.0不再支持Python 3.7
scikit-learn1.0.2
seaborn0.11.2
shap0.41.0
sqlalchemy==1.4.46 # 最初试了2.0.10,但和旧版pandas不兼容
一、多余依赖出现的原因
依赖查询命令使用错误
你用mamba repoquery depends -t pytorch查的是pytorch本身依赖哪些包,而不是哪些包依赖pytorch。要找pytorch的被依赖关系,应该用mamba repoquery whoneeds -t pytorch,这样才能定位到是哪个包间接引入了它(大概率是shap,因为shap依赖PyTorch或TensorFlow作为后端)。Conda与Pip的依赖解析逻辑冲突
Conda和Pip的依赖管理体系不同:Pip安装包时会直接拉取满足版本要求的依赖,而Conda在跟踪环境包时,会把所有存在于Conda仓库中的包(哪怕是Pip安装的同名包)纳入导出列表。旧版本Conda(如4.12.0)的依赖解析逻辑可能存在bug,会误将某些间接依赖标记为环境的顶层包。环境缓存或残留包干扰
如果之前的环境有残留的pytorch包,或者Conda缓存中有旧版本的安装记录,创建新环境时可能会被误引入,尤其是脚本创建环境时如果没有彻底清理缓存。
二、限制Conda导出仅保留必要项的方法
使用
--from-history参数导出
执行conda env export --from-history > environment.yml,这个参数只会导出你明确通过Conda命令安装的包,不会包含自动安装的依赖。如果你的环境主要用Pip安装包,导出后可以手动补充pip部分的内容。手动清理导出文件
导出environment.yml后,直接删除多余的依赖项(比如pytorch那一行),然后用conda env create -f environment.yml重建环境,测试是否能正常运行所有代码。如果运行无报错,说明该依赖确实是非必要的。分离Conda与Pip的包管理
优先用Conda安装能在Conda仓库找到的包,仅用Pip安装Conda无法提供的包:# 先创建环境并安装Conda可管理的包 conda create -n py37_clean python=3.7 numpy=1.15 pandas=1.0.5 matplotlib=3.3.4 pyarrow=2.0.0 scikit-learn=1.0.2 seaborn=0.11.2 sqlalchemy=1.4.46 # 再用pip安装剩余包 pip install boto3==1.26.117 pre-commit==2.21.0 praw==7.7.0 pg8000==1.29.4 pyspark==3.3.0 shap==0.41.0这样Conda导出的环境文件只会包含你明确安装的Conda包,减少多余项。
清理Conda缓存后重建环境
先清理Conda缓存,避免旧包干扰:conda clean -a然后重新创建干净环境并安装包,再导出环境文件。
检查Pip包的依赖链
用pip show shap查看shap的依赖,确认是否是它引入了pytorch。如果确实是shap的依赖,但你不需要PyTorch后端,可以在安装shap时指定仅安装TensorFlow后端,或者安装不依赖PyTorch的版本。
内容的提问来源于stack exchange,提问作者Ken Myers

