Python 가상환경
의존성 지옥(Dependency hell)은 실제로 존재합니다. 가상환경(virtual environment)이 그 치료법입니다.
유형: Build
언어: Python
선수 지식: Phase 0, Lesson 01
예상 시간: 약 30분
학습 목표
uv, venv, conda로 격리된 가상환경(isolated virtual environment)을 만듭니다.
- 선택 의존성 그룹(optional dependency group)이 있는
pyproject.toml을 작성하고 재현 가능한 설치(reproducible install)를 위한 lockfile을 생성합니다.
- 전역 설치(global install), pip/conda 혼용(pip/conda mixing), CUDA 버전 불일치(version mismatch) 같은 흔한 함정을 진단하고 고칩니다.
- 의존성이 충돌할 수 있는 여러 프로젝트를 위해 단계(phase)별 환경 전략(environment strategy)을 적용합니다.
문제
파인튜닝(fine-tuning) 프로젝트를 위해 PyTorch 2.4를 설치했습니다. 다음 주에는 다른 프로젝트가 CUDA 빌드(build)가 고정된 PyTorch 2.1을 요구합니다. 전역 환경을 업그레이드하면 첫 프로젝트가 깨지고, 다운그레이드하면 두 번째 프로젝트가 깨집니다.
이것이 의존성 지옥입니다. AI/ML 작업에서는 특히 자주 발생합니다.
- PyTorch, JAX, TensorFlow는 각각 CUDA 바인딩(binding)을 함께 제공합니다.
- 모델 라이브러리는 특정 프레임워크(framework) 버전을 고정(pin)할 수 있습니다.
- 전역
pip install은 이전에 있던 패키지를 덮어쓸 수 있습니다.
- CUDA 11.8 빌드는 CUDA 12.x 드라이버와 맞지 않을 수 있고, 반대도 마찬가지입니다.
해결책은 프로젝트마다 자기 패키지를 가진 격리 환경(isolated environment)을 두는 것입니다.
개념
graph TD
subgraph without["Virtual environment가 없을 때"]
SP[System Python] --> T24["torch 2.4.0 (CUDA 12.4)<br>Project A needs this"]
SP --> T21["torch 2.1.0 (CUDA 11.8)<br>Project B needs this"]
SP --> CONFLICT["CONFLICT: 하나의 torch version만 존재 가능"]
end
subgraph with["Virtual environment가 있을 때"]
PA["Project A (.venv/)"] --> PA1["torch 2.4.0 (CUDA 12.4)"]
PA --> PA2["transformers 4.44"]
PB["Project B (.venv/)"] --> PB1["torch 2.1.0 (CUDA 11.8)"]
PB --> PB2["diffusers 0.28"]
end
PAI 기준 Python 버전은 3.13입니다. 새 Python 문서, 예제, 검증 스크립트는 Python 3.13 기준으로 작성합니다.
직접 만들기
Option 1: uv venv (권장)
uv는 Python 버전, 가상환경(virtual environment), 의존성 해결(dependency resolution), 패키지 설치를 한 도구에서 처리합니다. 이 과정의 기본 Python 도구입니다.
curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.13
cd your-project
uv venv --python 3.13
source .venv/bin/activate
패키지를 설치합니다.
uv pip install torch numpy
pyproject.toml이 있는 프로젝트를 한 번에 만들 수도 있습니다.
uv init my-ai-project
cd my-ai-project
uv add torch numpy matplotlib
Option 2: venv (Python 내장)
uv를 설치할 수 없다면 Python에 내장된 venv를 사용할 수 있습니다.
python3.13 -m venv .venv
source .venv/bin/activate
.venv\Scripts\activate
pip install torch numpy
uv보다 느리지만 Python만 설치되어 있으면 어디서나 동작합니다.
Option 3: conda (필요할 때)
Conda는 CUDA 툴킷(toolkit), cuDNN, C 라이브러리 같은 비(non) Python 의존성도 함께 관리합니다. 아래 상황에서는 conda가 유용할 수 있습니다.
- 시스템 전역(system-wide) 설치 없이 특정 CUDA 툴킷 버전이 필요합니다.
- 시스템 패키지를 설치할 수 없는 공유 클러스터(shared cluster)를 사용합니다.
- 라이브러리 설치 문서가 conda를 명시합니다.
curl -LsSf https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o miniconda.sh
bash miniconda.sh -b
conda create -n myproject python=3.13
conda activate myproject
conda install pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia
규칙은 하나입니다. conda 환경을 쓴다면 그 환경 안에서는 가능한 한 conda로 패키지를 관리합니다. conda 환경에 pip install을 섞으면 의존성 추적(dependency tracking)이 깨져 디버깅이 어려워질 수 있습니다.
이 과정에서의 단계(phase)별 전략
과정 전체에 하나의 환경을 쓰고 싶을 수 있습니다. 권장하지 않습니다. 단계마다 필요한 의존성이 다르고 때로는 충돌합니다.
ai-engineering-from-scratch/
├── .venv/ <-- phases 0-3용 가벼운 공유 env
├── phases/
│ ├── 04-neural-networks/
│ │ └── .venv/ <-- PyTorch env
│ ├── 05-cnns/
│ │ └── .venv/ <-- 같은 PyTorch env를 공유하거나 symlink
│ ├── 08-transformers/
│ │ └── .venv/ <-- 다른 transformer version이 필요할 수 있음
│ └── 11-llm-apis/
│ └── .venv/ <-- API SDK, torch 불필요
code/env_setup.sh는 이 과정의 기본 환경(base environment)을 생성합니다.
pyproject.toml 기본
모든 Python 프로젝트는 pyproject.toml을 갖는 것이 좋습니다. setup.py, setup.cfg, requirements.txt 역할을 하나의 표준 파일로 모읍니다.
[project]
name = "ai-engineering-from-scratch"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
"numpy>=1.26",
"matplotlib>=3.8",
"jupyter>=1.0",
"scikit-learn>=1.4",
]
[project.optional-dependencies]
torch = ["torch>=2.3", "torchvision>=0.18"]
llm = ["anthropic>=0.39", "openai>=1.50"]
설치 예시는 아래와 같습니다.
uv pip install -e ".[torch]"
uv pip install -e ".[llm]"
uv pip install -e ".[torch,llm]"
Lockfile
록파일(lockfile)은 직접 의존성(direct dependency)과 전이 의존성(transitive dependency)까지 정확한 버전(exact version)으로 고정합니다. 같은 록파일에서 설치한 사람은 같은 패키지 집합(package set)을 받습니다.
uv add numpy
uv pip compile pyproject.toml -o requirements.lock
uv pip install -r requirements.lock
록파일은 Git에 커밋합니다. 다른 사람이 저장소를 클론하면 록파일 기준으로 설치해 같은 버전을 재현할 수 있습니다.
흔한 실수
1. 전역 설치(Global install)
pip install torch
source .venv/bin/activate
pip install torch
어디에 설치되는지 확인합니다.
which python
which pip
2. pip와 conda 섞기
conda create -n myenv python=3.13
conda activate myenv
conda install pytorch -c pytorch
pip install some-other-package
conda install some-other-package
pip 전용 패키지가 꼭 필요하다면 conda 패키지를 먼저 설치하고 pip 패키지를 마지막에 설치합니다.
3. 활성화(activate) 잊기
python train.py
source .venv/bin/activate
python train.py
셸 프롬프트(shell prompt)에 환경 이름(environment name)이 보이는지 확인합니다.
(.venv) $ python train.py
4. .venv를 Git에 커밋하기
echo ".venv/" >> .gitignore
가상환경은 크고 컴퓨터마다 다릅니다. .venv 대신 pyproject.toml과 록파일을 커밋합니다.
5. CUDA 버전 불일치
nvidia-smi
python -c "import torch; print(torch.version.cuda)"
nvidia-smi는 드라이버가 지원하는 CUDA 버전을 보여주고, torch.version.cuda는 PyTorch가 빌드된 CUDA 버전을 보여줍니다. PyTorch CUDA 버전은 드라이버가 지원하는 버전과 호환(compatible)되어야 합니다.
사용해보기
설정 스크립트(setup script)를 실행해 과정 환경(course environment)을 만듭니다.
bash phases/00-setup-and-tooling/06-python-environments/code/env_setup.sh
이 스크립트는 저장소 루트(repo root)에 .venv를 만들고 핵심 의존성(core dependency)을 설치한 뒤 검증합니다.
연습문제
env_setup.sh를 실행하고 모든 검사(check)가 통과하는지 확인합니다.
- 두 번째 가상환경을 만들고 다른 NumPy 버전을 설치한 뒤 두 환경이 격리되는지 확인합니다.
- PyTorch와 Anthropic SDK가 모두 필요한 프로젝트용
pyproject.toml을 작성합니다.
- 일부러 가상환경을 활성화하지 않고 패키지를 전역으로 설치해 어디에 들어가는지 확인한 뒤 제거합니다.
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 가상환경(Virtual environment) | venv | 시스템 Python과 분리된 인터프리터(interpreter)와 패키지 디렉터리 |
| 록파일(Lockfile) | 고정된 의존성(pinned dependency) | 모든 의존성의 정확한 버전을 기록해 동일한 설치를 보장하는 파일 |
pyproject.toml | 새 setup.py | Python 프로젝트 메타데이터(metadata)와 의존성을 담는 표준 설정 파일 |
| 전이 의존성(Transitive dependency) | 의존성의 의존성 | A가 B를 요구하고 B가 C를 요구할 때 C는 A의 전이 의존성 |
| CUDA 불일치 | GPU가 안 됨 | PyTorch CUDA 빌드와 GPU 드라이버 CUDA 호환성이 맞지 않는 상태 |
더 읽을거리