一、迁移要搬的两样东西
Python 项目从一台机器搬到另一台机器,本质上只需要复制两样东西:虚拟环境配置和第三方依赖包。使用 conda 管理的项目,对应的就是 environment.yml 和 requirements.txt 两个文件。
流程看着简单,但实际迁移时最容易卡在三个位置:requirements.txt 里残留了本机构建路径、依赖包之间的版本冲突、平台相关的二进制依赖(典型如 CUDA)无法匹配。下面按“旧机导出 → 处理文件 → 新机重建 → 疑难包手动安装 → 验证”的顺序说明。
二、在旧电脑导出环境配置
导出必须在激活目标虚拟环境之后执行,否则会把全局环境一起写进文件,新电脑上会装进大量并不需要的包。
- conda activate your_env_name
- conda env export > environment.yml
- pip freeze > requirements.txt
复制代码 生成的是 conda 环境的完整快照,生成的是 pip 侧的包列表,两者结合才能覆盖 conda 与 pip 混合安装的项目。
三、清理 requirements.txt 中的本机构建路径
直接拿导出的 requirements.txt 去安装,经常会遇到下面这类报错:
ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: 'C:\\home\\conda\\feedstock_root\\build_artifacts\\absl-py_1705494584803\\work'
原因是部分包在记录里带有 @file:// 形式的本地构建路径,新机器上这个路径根本不存在。解决办法是只保留包名和版本号,把 @ 及其后面的路径信息全部去掉:
- import os
- def clean_requirements_file(file_path):
- with open(file_path, 'r') as f:
- lines = f.readlines()
- cleaned_lines = []
- for line in lines:
- # 移除 @ 及其后的路径信息
- cleaned_line = line.split('@')[0].strip()
- if cleaned_line:
- cleaned_lines.append(cleaned_line)
- with open(file_path, 'w') as f:
- f.write('\n'.join(cleaned_lines))
- print(f"已清理 {file_path} 文件中的本地路径信息")
- # 使用示例
- clean_requirements_file(r'C:\path\to\requirements.txt')
复制代码
这段脚本的逻辑很直接:逐行读取,用截断路径部分,再去掉首尾空白,空行直接丢弃,最后整体覆写回文件。建议在清理之前把原始 requirements.txt 备份一份,后面补版本号时还要参考它。
四、在新电脑用 environment.yml 重建环境
- conda env create -f environment.yml
复制代码
这一步通常能顺利完成,但可能撞上三类问题:某些包在默认 channel 中不存在、Python 版本与新系统不兼容、平台特定依赖冲突。channel 问题可以补上 conda-forge 并设置优先级:
- conda config --add channels conda-forge
- conda config --set channel_priority strict
复制代码
五、用 yml 里的版本信息回填 requirements.txt
清理后的 requirements.txt 可能丢掉了部分版本约束,直接安装就会出现版本冲突。此时可以反过来利用 environment.yml 中记录的版本号来补齐,脚本同时兼容 dependencies 下的字符串条目和 pip 子列表两种写法:
- import yaml
- def sync_versions(yml_path, req_path):
- # 从 yml 读取版本信息
- with open(yml_path) as f:
- env_data = yaml.safe_load(f)
- pip_deps = {}
- for dep in env_data.get('dependencies', []):
- if isinstance(dep, str) and '==' in dep:
- pkg, ver = dep.split('==')
- pip_deps[pkg] = ver
- elif isinstance(dep, dict) and 'pip' in dep:
- for pip_dep in dep['pip']:
- if '==' in pip_dep:
- pkg, ver = pip_dep.split('==')
- pip_deps[pkg] = ver
- # 更新 requirements.txt
- with open(req_path, 'r') as f:
- req_lines = f.readlines()
- updated_lines = []
- for line in req_lines:
- line = line.strip()
- if not line or line.startswith('#'):
- updated_lines.append(line)
- continue
- pkg = line.split('==')[0].split('>')[0].split('<')[0].split('~')[0].strip()
- if pkg in pip_deps:
- updated_lines.append(f"{pkg}=={pip_deps[pkg]}")
- else:
- updated_lines.append(line)
- with open(req_path, 'w') as f:
- f.write('\n'.join(updated_lines))
- print(f"已同步 {req_path} 中的版本信息")
- # 使用示例
- sync_versions('environment.yml', 'requirements.txt')
复制代码
关键点在于包名的提取方式:依次以 ==、>、<、~ 作为分隔符取第一段,这样无论是锁定版本、范围约束还是兼容约束,都能拿到纯包名,再和 yml 中的版本字典比对后写成固定版本。
六、无法自动安装的依赖怎么处理
走完上面的流程,仍可能有包装不上,常见原因有三类:平台特定的编译依赖缺失、CUDA 等 GPU 组件版本不匹配、包已从 PyPI 移除。
以 PyTorch 为例,需要先查历史版本页面拿到对应安装命令,再按 CUDA 版本选包。例如 CUDA 12.1 环境下:
- conda install pytorch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 pytorch-cuda=12.1 -c pytorch -c nvidia
复制代码
七、分步安装策略
当依赖冲突比较多时,一次性安装往往定位不到问题源头。更稳的做法是分三步:先装基础科学计算包,再装框架核心,最后用 requirements.txt 补齐剩余依赖。
- conda create -n new_env python=3.9
- conda activate new_env
- # 安装基础科学计算包
- conda install numpy scipy pandas matplotlib
- # 安装机器学习框架
- conda install pytorch torchvision -c pytorch
- # 安装剩余依赖
- pip install -r requirements.txt
复制代码
这样每一步都能单独验证,出错时也容易判断是基础层、框架层还是辅助包的问题。
八、迁移后的验证
环境建好后必须验证,至少跑一遍项目测试套件、检查关键功能点,涉及 GPU 的还要确认 CUDA 是否可用。一个最小的检查脚本如下:
- import torch
- import numpy as np
- import pandas as pd
- print("PyTorch版本:", torch.__version__)
- print("CUDA可用:", torch.cuda.is_available())
- print("NumPy版本:", np.__version__)
- print("Pandas版本:", pd.__version__)
- # 执行简单计算验证功能正常
- x = torch.rand(5, 3)
- print("随机矩阵乘法结果:", x @ x.T)
复制代码
九、排查思路与经验
遇到装不上的包,可以按下面的顺序排查:
1. 先看错误信息里具体是哪个包、要求什么版本;
2. 到 PyPI 或 conda-forge 上确认该版本是否还存在;
3. 尝试指定稍旧或稍新的版本;
4. 检查系统依赖是否满足,例如 gcc 版本、CUDA 驱动;
5. 在一个干净的新虚拟环境里单独测试该包的安装。
几条实践下来的经验:优先用 conda,它对二进制依赖和平台差异的处理更好,科学计算和机器学习项目尤其明显;清理 requirements.txt 前保留原始快照作为参考;分阶段安装便于定位问题;对需要特殊渠道安装的包(本地编译、私有源)把步骤记录下来;把 environment.yml 和 requirements.txt 纳入版本控制,方便协作和环境重建;生产环境的复杂场景可以直接考虑 Docker 容器化,获得真正的环境一致性。
最后提醒一点:关键项目建议保留旧环境,等新环境完整跑通测试套件后再清理。 |