Vast.ai 환경에서 QLoRA를 활용한 LLM 파인튜닝 상세 가이드북
1. 서론
본 가이드북은 Vast.ai의 GPU 컴퓨팅 자원을 활용하여 대규모 언어 모델(Large Language Model, LLM)을 QLoRA(Quantized Low-Rank Adaptation) 기법으로 파인튜닝하는 과정을 상세히 안내합니다. Vast.ai는 GPU 컴퓨팅 파워를 임대할 수 있는 마켓플레이스로, 효율적인 모델 학습 환경을 제공합니다.1 QLoRA는 모델의 가중치를 4비트로 양자화하고 소수의 학습 가능한 파라미터(LoRA 어댑터)만을 추가하여 파인튜닝하는 기법으로, 메모리 사용량을 획기적으로 줄여 제한된 하드웨어 환경에서도 대규모 모델의 파인튜닝을 가능하게 합니다.2
본 가이드에서는 사용자가 Vast.ai에서 학습에 사용할 GPU를 이미 선택했다는 가정 하에, 환경 설정부터 데이터 준비, QLoRA 설정, 학습 실행 및 모니터링, 그리고 최종적으로 4비트 양자화된 베이스 모델과 LoRA 어댑터를 처리하는 방법까지 단계별로 상세하게 설명합니다.
2. Vast.ai 환경 설정
효율적인 QLoRA 파인튜닝을 위해서는 Vast.ai에서 적절한 환경을 설정하는 것이 중요합니다. 이는 올바른 Docker 이미지 선택, 인스턴스 사양 결정, 안정적인 연결 설정, 그리고 초기 환경 검증 단계를 포함합니다.
2.1 PyTorch 템플릿(Docker 이미지) 선택
Vast.ai 플랫폼의 'Templates' 탭에서 사용 가능한 Docker 이미지 템플릿을 선택합니다.1 QLoRA 파인튜닝을 위해서는 PyTorch 환경이 필요하며, 작업의 특성에 따라 다음 두 가지 권장 템플릿 중 하나를 선택할 수 있습니다 1:
- PyTorch (cuDNN Runtime):
- 표준적인 학습 및 추론 워크로드 실행 시
- 사전 빌드된 PyTorch 함수 및 레이어 사용 시
- 커스텀 CUDA 커널 컴파일 불필요 시
- 더 작은 컨테이너 크기와 빠른 인스턴스 시작 선호 시
- 프로덕션 추론 워크로드 실행 시
- PyTorch (cuDNN Devel):
- 커스텀 CUDA 확장 기능 빌드 필요 시 (예: 특정 버전의 Flash Attention) 1
- 새로운 GPU 연산 개발 시
- CUDA 컴파일이 필요한 라이브러리 사용 시
- PyTorch 소스 코드 수정 또는 컴파일 필요 시
- 저수준 GPU 접근이 필요한 PyTorch 개발 또는 연구 수행 시
일반적인 QLoRA 파인튜닝 작업에는 PyTorch (cuDNN Runtime) 템플릿으로 충분한 경우가 많습니다. 하지만 Flash Attention과 같은 특정 최적화 라이브러리를 사용하거나 커스텀 CUDA 코드를 빌드해야 하는 경우 PyTorch (cuDNN Devel) 템플릿이 필요할 수 있습니다.1
2.2 인스턴스 선택 및 실행
템플릿을 선택한 후, 해당 템플릿으로 실행할 수 있는 GPU 인스턴스 목록을 확인합니다.1 QLoRA 파인튜닝을 위한 인스턴스 선택 시 고려해야 할 주요 요소는 다음과 같습니다:
- GPU 메모리(VRAM): 파인튜닝하려는 모델의 크기와 배치 크기에 따라 필요한 VRAM이 결정됩니다. QLoRA는 메모리 효율성이 높지만, 여전히 베이스 모델과 활성화(activation), LoRA 파라미터 등을 저장할 충분한 공간이 필요합니다. 최소 8GB VRAM이 권장되나, 7B 파라미터 모델의 경우 24GB 이상, 더 큰 모델은 48GB 이상이 필요할 수 있습니다.1
- CUDA 버전: PyTorch 2.0 이상 버전은 CUDA 11.7 이상에서 최적의 성능을 보입니다.1 QLoRA에 필요한 bitsandbytes 라이브러리도 특정 CUDA 버전을 요구하므로 (예: CUDA 11.0 - 12.8 지원) 3, 호환성을 확인해야 합니다.
- 디스크 공간: 데이터셋, 모델 체크포인트, 라이브러리 등을 저장하기 위해 최소 50GB 이상의 디스크 공간을 확보하는 것이 좋습니다.1
- 인터넷 속도: 대용량 데이터셋 다운로드를 위해 100 Mbps 이상의 인터넷 속도를 가진 인스턴스를 선택하는 것이 유리합니다.1
요구 사항과 예산에 맞는 GPU 인스턴스를 선택하고 'Rent' 버튼을 클릭하여 임대를 시작합니다.1
2.3 SSH 연결 및 tmux 사용 (권장)
Vast.ai 인스턴스에는 웹 기반 Jupyter 인터페이스를 통해 접속할 수 있지만 1, 장시간 실행되는 파인튜닝 작업에는 SSH(Secure Shell) 연결이 더 안정적이고 권장됩니다. SSH 연결은 로컬 터미널 연결이 끊어지더라도 원격 인스턴스에서 작업이 계속 실행되도록 보장하는 데 유리합니다.1
- 사전 준비:
- 로컬 컴퓨터에 SSH 클라이언트 설치 (Linux/macOS는 기본 제공, Windows는 WSL 또는 PuTTY 사용).1
- 로컬에서 생성한 SSH 공개 키를 Vast.ai 계정의 'Keys' 섹션에 추가.1
- SSH 연결 단계:
- Vast.ai 'Instances' 탭에서 실행 중인 인스턴스 카드 우측의 'CONNECT' 또는 파란색 셸 프롬프트 버튼을 클릭하여 SSH 연결 정보(IP 주소, 포트 번호)를 확인합니다.8
- 로컬 터미널에서 다음 명령어를 사용하여 인스턴스에 연결합니다 (<SSH_PORT>와 <INSTANCE_IP_ADDRESS>를 실제 값으로 대체):
Bash
ssh -p <SSH_PORT> root@<INSTANCE_IP_ADDRESS>
예: ssh -p 42114 root@1.160.174.125 9 - SSH 키가 올바르게 설정되었다면 비밀번호 입력 없이 접속됩니다.8
- tmux 사용: SSH 연결 후, tmux와 같은 터미널 멀티플렉서를 사용하는 것이 강력히 권장됩니다. tmux는 세션을 유지시켜주므로, 로컬 컴퓨터와의 연결이 끊기거나 터미널 창을 닫더라도 원격 인스턴스에서 실행 중인 파인튜닝 프로세스가 중단되지 않습니다.11
- 새 tmux 세션 시작:
Bash
tmux new -s qlora_session
(qlora_session은 원하는 세션 이름으로 변경 가능) - 기존 세션에 다시 연결:
Bash
tmux attach -t qlora_session
Vast.ai의 일부 템플릿은 SSH 접속 시 자동으로 tmux 세션을 시작하기도 합니다.11
2.4 초기 환경 검증
인스턴스에 성공적으로 연결한 후에는 본격적인 작업 시작 전에 기본적인 환경 설정을 확인하는 것이 중요합니다. 이는 잠재적인 설정 오류나 호환성 문제를 조기에 발견하여 시간 낭비를 줄이는 데 도움이 됩니다.
- PyTorch 및 CUDA 확인: Jupyter 터미널 또는 SSH 세션에서 Python 인터프리터를 실행하고 다음 명령어를 입력하여 PyTorch 버전과 CUDA 가용성, 인식된 GPU 장치를 확인합니다 1:
Python
import torch
print(f"PyTorch version: {torch.__version__}")
print(f"CUDA available: {torch.cuda.is_available()}")
if torch.cuda.is_available():
print(f"GPU device: {torch.cuda.get_device_name(0)}")
print(f"CUDA version used by PyTorch: {torch.version.cuda}")
torch.cuda.is_available()가 True를 반환하고 올바른 GPU 이름이 출력되는지 확인합니다. 이는 PyTorch가 GPU를 제대로 인식하고 사용할 준비가 되었음을 의미합니다.1 - NVIDIA 드라이버 및 GPU 상태 확인 (nvidia-smi): 터미널에서 nvidia-smi 명령어를 실행하여 설치된 NVIDIA 드라이버 버전, CUDA 버전 (드라이버 레벨), GPU 상태 (온도, 사용률, 메모리 사용량 등)를 확인합니다.13
Bash
nvidia-smi
여기서 확인된 CUDA 버전과 PyTorch가 사용하는 CUDA 버전 간의 호환성을 확인하는 것이 중요합니다. PyTorch는 특정 범위의 드라이버 CUDA 버전을 요구하며, 불일치 시 런타임 오류가 발생할 수 있습니다.1 이 초기 검증 단계는 선택한 템플릿과 인스턴스가 QLoRA 파인튜닝 요구사항에 맞게 올바르게 구성되었는지 확인하고, 핵심 구성 요소가 정상적으로 작동하는지 보장하여 이후 발생할 수 있는 디버깅의 어려움을 예방합니다.
3. 데이터 및 코드 준비
환경 설정이 완료되면 파인튜닝에 필요한 데이터셋과 코드를 Vast.ai 인스턴스로 옮기고, 필요한 라이브러리를 설치해야 합니다.
3.1 데이터셋 및 코드 전송
로컬 컴퓨터나 웹상의 데이터를 Vast.ai 인스턴스로 전송하는 방법은 여러 가지가 있으며, 데이터의 크기와 위치에 따라 적합한 방법을 선택해야 합니다.
- scp (Secure Copy): 로컬 컴퓨터의 파일이나 디렉토리를 원격 인스턴스로 복사하는 데 사용됩니다. SSH 연결 정보를 활용합니다.15
- 구문:
Bash
scp -P <PORT> /path/to/local/file_or_dir root@<IPADDR>:/path/to/remote/dir
(예: scp -P 7417./my_dataset.zip root@52.204.230.7:/workspace/qlora_project/data/) - -P 옵션으로 포트 번호를 지정해야 합니다 (SSH의 -p와 다름).15
- 코드 파일이나 비교적 작은 데이터셋(예: 1GB 미만) 전송에 편리합니다. Vast.ai의 기본 SSH 연결은 프록시를 사용할 수 있어 대용량 파일 전송 시 속도가 느릴 수 있으므로, 이 경우 직접 SSH 연결(Direct SSH) 설정이나 다른 방법을 고려하는 것이 좋습니다.15
- wget: 웹 URL을 통해 파일을 직접 다운로드하는 데 사용됩니다. 데이터셋이 웹 호스팅(예: Hugging Face Hub, 클라우드 스토리지 공개 링크)되어 있는 경우 유용합니다.1
- 구문:
Bash
wget '<URL>' -O /path/to/save/filename
(예: wget 'https://huggingface.co/datasets/my_dataset/resolve/main/data.zip' -O /workspace/qlora_project/data/my_dataset.zip) - URL은 작은따옴표(' ')로 감싸는 것이 안전합니다.
- 대용량 데이터셋의 경우, 인스턴스의 빠른 인터넷 연결을 활용할 수 있어 scp보다 훨씬 빠를 수 있습니다.1 Kaggle 데이터셋 다운로드 시 특정 방법이 필요할 수 있습니다.16
- Vast.ai CLI (vastai copy): Vast.ai에서 제공하는 명령줄 인터페이스를 사용하여 로컬-인스턴스 간, 또는 인스턴스-인스턴스 간 데이터 복사를 수행할 수 있습니다. rsync를 기반으로 하여 효율적일 수 있습니다.15
- 예시: vastai copy ~/local_data_dir <INSTANCE_ID>:/workspace/remote_data_dir
- Cloud Sync: Vast.ai 계정에 연결된 클라우드 스토리지(S3, Google Drive, Dropbox 등)와 인스턴스 간 데이터를 동기화하는 기능입니다. 인스턴스가 중지된 상태에서도 데이터 전송이 가능합니다.15
데이터의 크기와 원본 위치를 고려하여 최적의 전송 방법을 선택하는 것이 중요합니다. 온라인에 이미 존재하는 대용량 데이터셋은 wget을 사용하는 것이 인스턴스의 네트워크 성능을 활용하여 시간을 절약하는 가장 효율적인 방법일 수 있습니다. 로컬 파일이나 코드는 scp가 간편하지만, 속도 제한을 인지해야 합니다. Vast.ai의 자체 도구들은 플랫폼 내에서의 데이터 이동에 최적화되어 있을 수 있습니다.15
3.2 권장 프로젝트 디렉토리 구조
Vast.ai 인스턴스 내에서 체계적인 디렉토리 구조를 사용하면 프로젝트 관리, 재현성 확보, 탐색 용이성 측면에서 이점이 있습니다. /workspace/ 디렉토리 아래에 프로젝트별 디렉토리를 생성하는 것이 일반적입니다.1
- 예시 구조:
/workspace/qlora_project/
├── code/ # 파인튜닝 스크립트 등 소스 코드
│ └── train_qlora.py
├── data/ # 학습 및 평가 데이터셋
│ ├── train.jsonl
│ └── eval.jsonl
├── output/ # 학습 결과물 (체크포인트, 로그, 어댑터 등)
│ └── qlora_adapter_weights/
└── requirements.txt # 필요한 Python 라이브러리 목록
3.3 필수 라이브러리 및 종속성 설치
QLoRA 파인튜닝은 특정 버전의 라이브러리 간의 호환성에 크게 의존합니다. 특히 bitsandbytes, peft, accelerate, transformers 라이브러리의 버전 조합이 중요합니다.6 잘못된 버전을 사용하면 오류가 발생하거나 성능이 저하될 수 있습니다.
- 설치 명령어: 다음은 권장되는 버전 또는 호환 가능한 버전 범위를 기반으로 한 예시입니다. 최신 안정 버전을 확인하고 필요에 따라 조정해야 합니다.2
Bash
# PyTorch 버전 확인 및 필요시 업그레이드
# pip install torch --upgrade
# QLoRA 관련 핵심 라이브러리 설치
pip install --upgrade \
"transformers>=4.51.3" \
"datasets==3.3.2" \
"accelerate==1.4.0" \
"bitsandbytes==0.45.3" \
"peft==0.14.0" \
"trl==0.15.2" \
"evaluate==0.4.3" \
protobuf \
sentencepiece
# (선택 사항) 최신 기능/버그 수정을 위해 peft, trl을 소스에서 설치해야 할 수 있음 [22]
# pip install git+https://github.com/huggingface/peft.git
# pip install git+https://github.com/huggingface/trl.git
# (선택 사항) Flash Attention (Ampere 이상 GPU에서 성능 향상) [22]
# pip install flash-attn --no-build-isolation - 버전 관리: requirements.txt 파일을 프로젝트 루트에 생성하여 사용된 라이브러리와 버전을 명시하고, 이를 통해 환경을 재현하는 것이 좋습니다.
Bash
pip freeze > /workspace/qlora_project/requirements.txt
# 추후 동일 환경 구성 시: pip install -r /workspace/qlora_project/requirements.txt - Flash Attention: NVIDIA Ampere 아키텍처(예: A100, RTX 3090) 이상 GPU를 사용하는 경우, Flash Attention 라이브러리를 설치하면 학습 속도를 높이고 메모리 사용량을 줄일 수 있습니다.22 설치 시간이 다소 소요될 수 있습니다.22
QLoRA는 bitsandbytes의 양자화 기술, peft의 어댑터 관리, accelerate의 분산 학습 및 메모리 관리, transformers의 모델 및 학습 인프라가 긴밀하게 상호작용하는 복잡한 프로세스입니다.2 이 라이브러리들은 빠르게 발전하므로, 호환되는 버전 조합을 사용하는 것이 중요합니다. 알려진 작동 세트나 권장 버전을 사용하는 것이 예기치 않은 오류나 성능 저하를 피하는 데 필수적입니다.6
다음 표는 QLoRA 파인튜닝에 필요한 주요 라이브러리와 그 역할을 요약한 것입니다.
표 1: 주요 QLoRA 라이브러리 요구사항
라이브러리 | 권장 버전 (예시) | 목적 | 관련 정보 출처 |
torch | >=2.1.0 | 딥러닝 프레임워크, CUDA 연산 기반 | 1 |
transformers | >=4.51.3 | 사전 훈련된 모델 로딩, 토크나이저, Trainer API 제공 | 6 |
peft | ==0.14.0 | 파라미터 효율적 파인튜닝 (LoRA, QLoRA 어댑터 관리) | 2 |
bitsandbytes | ==0.45.3 | 4비트 양자화 (NF4 등), 8비트 양자화, 메모리 효율적 옵티마이저 지원 | 3 |
accelerate | ==1.4.0 | 분산 학습, 혼합 정밀도, 메모리 관리 간소화 | 6 |
datasets | ==3.3.2 | 데이터셋 로딩, 전처리, 포맷팅 지원 | 6 |
trl | ==0.15.2 | SFTTrainer (지도 학습 파인튜닝), 데이터셋 패킹 등 편의 기능 제공 | 7 |
flash-attn | 최신 버전 | (선택) Attention 연산 가속 및 메모리 최적화 (Ampere 이상 GPU) | 22 |
4. QLoRA 파인튜닝 파이프라인 구성 (Hugging Face trl 및 peft 활용)
라이브러리 설치가 완료되면, QLoRA 파인튜닝을 위한 구체적인 설정을 진행합니다. 이는 4비트로 양자화된 베이스 모델 로딩, LoRA 어댑터 설정, 데이터셋 준비, 학습 하이퍼파라미터 정의 단계를 포함합니다.
4.1 4비트 양자화된 베이스 모델 로딩 (BitsAndBytesConfig)
QLoRA 파인튜닝의 첫 단계는 사전 훈련된 베이스 모델을 4비트 정밀도로 로딩하는 것입니다.2 이는 transformers 라이브러리의 BitsAndBytesConfig를 사용하여 설정합니다.2
- 코드 예시:
Python
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch
model_id = "mistralai/Mistral-7B-v0.1" # 파인튜닝할 모델 ID (예: Gemma, Llama 등)
# 4비트 양자화 설정 정의
quantization_config = BitsAndBytesConfig(
load_in_4bit=True, # 4비트 양자화 활성화 [7, 25]
bnb_4bit_quant_type="nf4", # 양자화 타입: nf4 (Normal Float 4) 권장 [3, 4, 5]
bnb_4bit_compute_dtype=torch.bfloat16, # 연산 데이터 타입: bfloat16 (Ampere+) 또는 float16 [4, 5, 6, 7]
bnb_4bit_use_double_quant=True, # 이중 양자화 사용 (추가 메모리 절약) [4, 5, 25]
)
# 양자화 설정을 적용하여 모델 로딩
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=quantization_config,
device_map="auto" # 사용 가능한 GPU/CPU에 모델 레이어 자동 분배
)
# 토크나이저 로딩 및 패딩 토큰 설정
tokenizer = AutoTokenizer.from_pretrained(model_id)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token # pad_token이 없으면 eos_token으로 설정 - 주요 파라미터 설명:
- load_in_4bit=True: 모델 가중치를 4비트로 로드하도록 지시하는 핵심 파라미터입니다.7
- bnb_4bit_quant_type="nf4": 사용할 4비트 양자화 유형을 지정합니다. "nf4"는 정규 분포를 따르는 가중치에 최적화된 데이터 타입으로, 일반적으로 우수한 성능을 제공합니다.3
- bnb_4bit_compute_dtype: 가중치는 4비트로 저장되지만, 실제 연산은 더 높은 정밀도로 수행됩니다. 이 파라미터는 연산에 사용될 데이터 타입을 결정합니다. torch.bfloat16은 넓은 동적 범위를 가져 최신 GPU(Ampere 이상)에서 안정적인 학습에 유리할 수 있으며, torch.float16은 더 많은 하드웨어에서 지원됩니다.4 사용하는 GPU 아키텍처에 맞춰 선택해야 합니다.
- bnb_4bit_use_double_quant=True: 이중 양자화는 양자화 상수 자체를 다시 양자화하여 파라미터당 약 0.4비트의 추가적인 메모리를 절약하는 기법입니다.4 메모리가 극도로 제한적인 상황에서 유용할 수 있습니다.
연산 데이터 타입(bnb_4bit_compute_dtype) 선택은 성능과 메모리 사용량 모두에 영향을 미칩니다. bfloat16은 일반적으로 최신 GPU에서 좋은 균형을 제공하지만, 하드웨어 지원 여부를 확인해야 합니다. float16은 호환성이 높지만 표현 범위가 좁습니다. 이중 양자화는 미미한 성능 비용으로 약간의 메모리 절약을 제공하므로, 필요에 따라 실험해 볼 수 있습니다.
표 2: 주요 BitsAndBytesConfig 파라미터 (QLoRA)
파라미터 | 예시 값 | 설명 | 중요성/트레이드오프 | 관련 정보 출처 |
load_in_4bit | True | 4비트 양자화 활성화 | QLoRA의 핵심, 메모리 사용량 대폭 감소 | 7 |
bnb_4bit_quant_type | "nf4" | 4비트 양자화 유형 (Normal Float 4) | "nf4" 권장, 성능에 영향 | 3 |
bnb_4bit_compute_dtype | torch.bfloat16 | 실제 연산에 사용될 데이터 타입 | bfloat16 (Ampere+): 안정성 유리, float16: 호환성 높음. 성능/메모리 트레이드오프 | 4 |
bnb_4bit_use_double_quant | True | 이중 양자화 적용 여부 | 추가 메모리 절약 (약 0.4 bits/param), 미미한 성능 영향 가능성 | 4 |
4.2 LoRA 설정 정의 (LoraConfig)
4비트 베이스 모델 로딩 후, peft 라이브러리의 LoraConfig를 사용하여 LoRA(Low-Rank Adaptation) 설정을 정의합니다. LoRA는 기존 모델의 가중치는 동결(freeze)시킨 채, 학습 가능한 저차원(low-rank) 행렬들을 모델의 특정 레이어에 주입(inject)하는 방식입니다.2
- 코드 예시:
Python
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# (선택 사항) k-bit 학습을 위한 모델 준비 (그래디언트 체크포인팅 활성화 등)
# 이 함수는 그래디언트 체크포인팅을 사용하도록 모델을 설정하고,
# 입력 임베딩과 출력 레이어의 정밀도를 학습에 맞게 조정하는 등의 준비 작업을 수행합니다.
model = prepare_model_for_kbit_training(model)
# LoRA 설정 정의
lora_config = LoraConfig(
r=16, # LoRA 행렬의 랭크(rank) [20, 24, 28] (일반적으로 8, 16, 32, 64 등)
lora_alpha=32, # LoRA 스케일링 파라미터 (alpha) [20, 28] (종종 r의 2배 사용)
target_modules=
"gate_proj", "up_proj", "down_proj"], # 또는 "all-linear"로 모든 선형 레이어 지정 가능 [20]
lora_dropout=0.05, # LoRA 레이어에 적용할 드롭아웃 비율 [20, 28]
bias="none", # 편향(bias) 학습 방식 ('none', 'all', 'lora_only') [20, 28]
task_type="CAUSAL_LM", # 태스크 유형 (예: 인과적 언어 모델링) [20, 28]
# modules_to_save=["lm_head", "embed_tokens"] # (선택 사항) LoRA 외 추가로 학습/저장할 모듈 [20, 28]
)
# 정의된 LoRA 설정을 모델에 적용
peft_model = get_peft_model(model, lora_config)
# 학습 가능한 파라미터 수 및 비율 확인
peft_model.print_trainable_parameters() - 주요 파라미터 설명:
- r: LoRA 업데이트 행렬의 랭크(rank)입니다. 랭크가 높을수록 더 많은 파라미터를 학습하지만, 메모리 사용량과 어댑터 크기가 증가합니다. 모델 크기와 태스크에 따라 적절한 값을 선택해야 합니다 (일반적으로 8 ~ 64 사이).7
- lora_alpha: LoRA 가중치에 적용되는 스케일링 계수입니다. 학습된 어댑터 가중치의 영향을 조절하며, 보통 r 값의 1~2배로 설정됩니다.7
- target_modules: LoRA를 적용할 대상 모듈(레이어)의 이름을 리스트로 지정합니다. 이는 모델 아키텍처에 따라 다르며, 매우 중요한 파라미터입니다. 일반적으로 어텐션 관련 레이어(q_proj, k_proj, v_proj, o_proj)를 타겟으로 하지만, MLP 레이어(gate_proj, up_proj, down_proj)를 포함하거나 "all-linear"를 사용하여 모든 선형 레이어를 대상으로 지정할 수도 있습니다.7 대상 모듈 선택은 성능과 학습 파라미터 수에 직접적인 영향을 미칩니다.
- lora_dropout: LoRA 레이어에 적용될 드롭아웃 확률입니다.20
- bias: 편향 파라미터의 학습 여부를 결정합니다 ('none': 학습 안 함, 'all': 모든 편향 학습, 'lora_only': LoRA 레이어의 편향만 학습).20 'none'이 일반적입니다.
- task_type: 파인튜닝하는 태스크의 유형을 지정합니다 (예: "CAUSAL_LM", "SEQ_CLS").20
- modules_to_save: LoRA 어댑터 외에 추가적으로 학습시키고 저장해야 할 모듈이 있다면 리스트로 지정합니다 (예: 언어 모델 헤드 lm_head, 임베딩 embed_tokens).20
- prepare_model_for_kbit_training: 이 함수는 그래디언트 체크포인팅을 활성화하고, 모델의 입력 및 출력 임베딩 레이어의 정밀도를 조정하는 등 k-비트(여기서는 4비트) 학습에 필요한 사전 준비 작업을 수행하여 학습 안정성과 효율성을 높입니다.
- target_modules 선택의 중요성: 어떤 모듈을 LoRA 대상으로 지정하는지는 파인튜닝 성능과 효율성에 큰 영향을 미칩니다. 어텐션 레이어만 타겟으로 하는 것이 일반적인 시작점이지만, MLP 레이어를 포함하거나 "all-linear" 옵션을 사용하면 더 많은 파라미터를 학습하게 되어 메모리 사용량은 늘어나지만 특정 태스크에서는 더 나은 성능을 보일 수 있습니다.2 모델 구조와 목표 성능에 따라 실험적으로 결정하는 것이 좋습니다. "all-linear"는 설정의 간편함을 제공합니다.20
표 3: 주요 LoraConfig 파라미터
파라미터 | 예시 값 | 설명 | 중요성/트레이드오프 | 관련 정보 출처 |
r | 16 | LoRA 업데이트 행렬의 랭크 | 높을수록 표현력 증가, 파라미터/메모리 증가. 8~64 사이 값 주로 사용. | 7 |
lora_alpha | 32 | LoRA 스케일링 계수 | 학습된 가중치 영향력 조절. 보통 r의 1~2배. | 7 |
target_modules | ["q_proj", "k_proj", "v_proj", "o_proj",...] 또는 "all-linear" | LoRA 적용 대상 모듈 지정 | 매우 중요. 모델/태스크 의존적. 대상 많을수록 파라미터/메모리 증가, 성능 향상 가능. | 7 |
lora_dropout | 0.05 | LoRA 레이어 드롭아웃 확률 | 과적합 방지. | 20 |
bias | "none" | 편향 학습 방식 | 'none' 권장. 'all'/'lora_only'는 비활성화 시에도 원본 모델과 출력 달라질 수 있음. | 20 |
task_type | "CAUSAL_LM" | 파인튜닝 태스크 유형 | PEFT 라이브러리가 설정을 올바르게 적용하도록 함. | 20 |
modules_to_save | ["lm_head",...] (선택) | LoRA 외 추가 학습/저장 모듈 | 특정 레이어(예: 출력층)를 파인튜닝해야 할 경우 필요. | 20 |
4.3 데이터셋 준비 및 포맷팅 (토크나이징, 프롬프팅, 패킹)
파인튜닝할 데이터셋을 모델과 태스크에 맞게 준비하는 과정입니다. 지도 학습(Supervised Fine-Tuning, SFT)의 경우, 입력(instruction/context)과 출력(response) 쌍으로 구성된 데이터를 사용합니다.6
- 프롬프트 템플릿: 모델이 이해할 수 있는 형식으로 데이터를 변환하기 위해 프롬프트 템플릿을 정의합니다. 예를 들어, 질문-답변 형식의 데이터셋을 특정 프롬프트 구조에 맞게 변환할 수 있습니다.6
Python
def apply_prompt_template(example):
# 예시: Alpaca 스타일 프롬프트
if example.get("input"):
prompt = f"Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.\n\n### Instruction:\n{example['instruction']}\n\n### Input:\n{example['input']}\n\n### Response:\n{example['output']}"
else:
prompt = f"Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n### Instruction:\n{example['instruction']}\n\n### Response:\n{example['output']}"
return {"text": prompt} # SFTTrainer가 사용할 필드명 (예: "text")
# Hugging Face datasets 라이브러리 사용 예시
# from datasets import load_dataset
# dataset = load_dataset("...")
# formatted_dataset = dataset.map(apply_prompt_template) - 토크나이징: 텍스트 데이터를 모델이 처리할 수 있는 토큰 ID 시퀀스로 변환하는 과정입니다. 앞서 로드한 토크나이저를 사용하며, 필요시 패딩(padding)을 적용합니다.6 tokenizer.pad_token = tokenizer.eos_token 설정은 pad_token이 정의되지 않은 모델에서 중요합니다.
Python
# tokenized_dataset = formatted_dataset.map(lambda examples: tokenizer(examples["text"]), batched=True) - 데이터셋 패킹(Packing): 여러 개의 짧은 예제를 하나의 긴 시퀀스로 묶어 모델의 최대 시퀀스 길이(max_seq_length)를 최대한 활용하는 기법입니다. 이는 GPU 연산 효율성을 크게 높여 학습 속도를 개선합니다.7 trl 라이브러리의 SFTTrainer는 packing=True 옵션을 통해 이를 자동으로 처리해 줄 수 있습니다.29
4.4 학습 하이퍼파라미터 설정 (TrainingArguments)
transformers 라이브러리의 TrainingArguments 클래스를 사용하여 학습 루프의 동작을 제어하는 다양한 하이퍼파라미터를 설정합니다.7 QLoRA 파인튜닝 시에는 특히 메모리 관리와 관련된 파라미터 설정이 중요합니다.
- 코드 예시:
Python
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="/workspace/qlora_project/output/results", # 체크포인트 및 로그 저장 디렉토리
per_device_train_batch_size=4, # GPU당 배치 크기 (VRAM에 맞춰 조정) [7, 29]
gradient_accumulation_steps=4, # 그래디언트 누적 스텝 (유효 배치 크기 증가) [7, 29]
optim="paged_adamw_32bit", # QLoRA에 권장되는 메모리 효율적 옵티마이저 [7]
learning_rate=2e-4, # 학습률 (일반적인 시작점) [7, 29]
lr_scheduler_type="cosine", # 학습률 스케줄러 유형 [29]
num_train_epochs=1, # 총 학습 에폭 수 (데이터셋 크기에 따라 조정) [7, 29]
warmup_ratio=0.03, # 학습률 워밍업 비율 [29]
logging_steps=10, # 로그 출력 빈도 (스텝 단위) [7]
save_strategy="steps", # 체크포인트 저장 전략 ("steps" 또는 "epoch")
save_steps=100, # 체크포인트 저장 빈도 (스텝 단위) [7]
# bf16=True, # bfloat16 사용 (compute_dtype과 일치 시) [29]
fp16=True, # float16 사용 (compute_dtype과 일치 시) [7]
gradient_checkpointing=True, # **메모리 절약을 위해 필수적** [29]
report_to="wandb", # (선택 사항) Weights & Biases 로깅 연동 [29]
# max_steps=-1, # (선택 사항) 에폭 대신 총 스텝 수로 학습 제어
) - 주요 파라미터 설명:
- output_dir: 학습 결과물이 저장될 경로입니다.
- per_device_train_batch_size, gradient_accumulation_steps: 이 두 파라미터의 곱은 유효 배치 크기를 결정합니다. VRAM 제약 하에서 가능한 큰 유효 배치 크기를 사용하기 위해 gradient_accumulation_steps를 늘립니다.7
- optim="paged_adamw_32bit": QLoRA와 함께 사용될 때 메모리 사용량을 줄여주는 옵티마이저입니다.7
- learning_rate, lr_scheduler_type, warmup_ratio: 학습률 및 스케줄링 관련 설정입니다.7
- num_train_epochs 또는 max_steps: 학습 종료 조건을 설정합니다.7
- fp16 또는 bf16: 혼합 정밀도 학습을 활성화합니다. BitsAndBytesConfig의 bnb_4bit_compute_dtype과 일치시켜야 합니다.7
- gradient_checkpointing=True: 활성화(activation) 값을 저장하는 대신 역전파 시 재계산하여 메모리 사용량을 크게 줄입니다. QLoRA 파인튜닝 시 메모리 제약을 극복하기 위해 거의 필수적으로 사용됩니다.29 연산 시간은 다소 증가할 수 있습니다.
- save_strategy, save_steps: 모델 체크포인트 저장 방식을 설정합니다. 주기적인 저장은 학습 중단 시 복구를 용이하게 합니다.7
gradient_checkpointing은 QLoRA의 메모리 효율성을 극대화하는 핵심 설정입니다. 4비트 가중치가 정적 메모리를 절약하는 동안, 순전파 과정에서 발생하는 활성화 값은 여전히 상당한 VRAM을 차지합니다. 그래디언트 체크포인팅은 이 활성화 값 대부분을 저장하지 않고 필요할 때 재계산함으로써, 학습 중 최대 메모리 요구량을 크게 낮춥니다.29 이는 동일 하드웨어에서 더 큰 모델을 파인튜닝하거나 더 큰 배치 크기를 사용할 수 있게 해주는 중요한 트레이드오프(메모리 절약 vs. 연산 시간 증가)입니다.
표 4: 주요 TrainingArguments (QLoRA)
파라미터 | 예시 값 | 설명 | 중요성/트레이드오프 | 관련 정보 출처 |
output_dir | "./output/results" | 결과물 저장 경로 | 필수 설정. | 7 |
per_device_train_batch_size | 4 | GPU당 배치 크기 | VRAM에 맞춰 최대화. gradient_accumulation_steps와 함께 유효 배치 크기 결정. | 7 |
gradient_accumulation_steps | 4 | 그래디언트 누적 스텝 | VRAM 제약 하에서 유효 배치 크기 증가. | 7 |
optim | "paged_adamw_32bit" | 옵티마이저 | QLoRA에 권장되는 메모리 효율적 옵티마이저. | 7 |
learning_rate | 2e-4 | 학습률 | 성능에 중요, 튜닝 필요. | 7 |
num_train_epochs/max_steps | 1 / -1 | 학습 종료 조건 (에폭 또는 스텝 수) | 데이터셋 크기와 학습 목표에 따라 설정. | 7 |
fp16/bf16 | True / False | 혼합 정밀도 사용 여부 | bnb_4bit_compute_dtype과 일치. 속도 향상 및 메모리 절약. | 7 |
gradient_checkpointing | True | 그래디언트 체크포인팅 사용 여부 | QLoRA 메모리 절약에 필수적. 연산 시간 증가 트레이드오프. | 29 |
save_strategy/save_steps | "steps" / 100 | 체크포인트 저장 전략 및 빈도 | 주기적 저장은 학습 복구에 중요. 디스크 공간 사용량 고려. | 7 |
5. 파인튜닝 프로세스 실행 및 모니터링
모든 설정이 완료되면, 정의된 파이프라인을 사용하여 실제 파인튜닝을 실행하고, 안정적인 실행과 성능 모니터링을 보장해야 합니다.
5.1 SFTTrainer를 활용한 지도 학습 파인튜닝
trl 라이브러리의 SFTTrainer는 지도 학습 파인튜닝(Supervised Fine-Tuning)을 위한 고수준 인터페이스를 제공합니다. 이는 transformers.Trainer를 기반으로 하며, 데이터셋 포맷팅, 패킹, PEFT 통합 등의 기능을 자동화하여 QLoRA 파인튜닝 과정을 간소화합니다.7
- 코드 예시: 앞서 정의한 peft_model, tokenizer, training_args, 그리고 준비된 데이터셋(tokenized_train_dataset, tokenized_eval_dataset)을 사용하여 SFTTrainer를 초기화하고 학습을 시작합니다.
Python
from trl import SFTTrainer
# SFTTrainer 초기화
trainer = SFTTrainer(
model=peft_model, # PEFT 설정이 적용된 모델
train_dataset=tokenized_train_dataset, # 토크나이징 및 포맷팅된 학습 데이터셋
eval_dataset=tokenized_eval_dataset, # 토크나이징 및 포맷팅된 평가 데이터셋
peft_config=lora_config, # LoRA 설정 (이미 모델에 적용했다면 생략 가능)
# dataset_text_field="text", # 데이터셋 내 텍스트 필드명 (Dataset 객체 직접 사용 시)
# formatting_func=formatting_func,# 또는 데이터 포맷팅 함수 지정 [29]
max_seq_length=1024, # 패킹에 사용될 최대 시퀀스 길이 [29]
tokenizer=tokenizer, # 토크나이저
args=training_args, # TrainingArguments 객체
packing=True, # 데이터셋 패킹 활성화 [29]
# data_collator=... # (선택 사항) 커스텀 데이터 콜레이터
)
# 학습 시작
print("Starting training...")
trainer.train()
print("Training finished.")
# 학습 완료 후 최종 어댑터 저장
print("Saving final adapter...")
final_adapter_path = "/workspace/qlora_project/output/final_qlora_adapter"
trainer.save_model(final_adapter_path) # 어댑터 가중치만 저장됨 [30, 31]
print(f"Adapter saved to {final_adapter_path}") - SFTTrainer 주요 파라미터: model, train_dataset, eval_dataset, peft_config, dataset_text_field 또는 formatting_func, max_seq_length, tokenizer, args, packing 등이 있으며, 파인튜닝 작업의 특성에 맞게 설정합니다.7
5.2 백그라운드에서 안정적으로 학습 스크립트 실행 (tmux, nohup)
장시간 소요되는 파인튜닝 작업을 안정적으로 실행하기 위해서는 tmux 세션 내에서 nohup 명령어를 사용하는 것이 좋습니다.
- 실행 절차:
- tmux 세션에 접속합니다 (tmux attach -t qlora_session).
- 파이썬 스크립트가 있는 디렉토리로 이동합니다 (cd /workspace/qlora_project/code/).
- nohup을 사용하여 스크립트를 백그라운드에서 실행하고, 표준 출력(stdout)과 표준 에러(stderr)를 로그 파일로 리디렉션합니다 13:
Bash
nohup python train_qlora.py > /workspace/qlora_project/output/training.log 2>&1 &
(train_qlora.py는 실제 스크립트 파일명으로 변경) - &는 명령어를 백그라운드에서 실행하도록 합니다.
- nohup은 터미널 연결이 끊겨도 프로세스가 계속 실행되도록 보장하며 (SIGHUP 신호 무시), 출력은 지정된 로그 파일(training.log)에 기록됩니다.32
- 로그 모니터링: 다른 tmux 창이나 분할된 패널에서 tail -f 명령어를 사용하여 로그 파일을 실시간으로 모니터링할 수 있습니다.
Bash
tail -f /workspace/qlora_project/output/training.log - 세션 관리: Ctrl+b d를 눌러 tmux 세션에서 분리(detach)해도 학습은 계속 진행됩니다. 나중에 tmux attach 명령어로 다시 접속하여 상태를 확인할 수 있습니다.13
단순히 &를 사용하여 백그라운드에서 실행하는 것만으로는 부족합니다. nohup을 사용하지 않으면 터미널 연결 종료 시 프로세스가 함께 종료될 수 있으며, 출력 리디렉션 없이는 학습 진행 상황이나 오류 메시지를 추적하기 어렵습니다.32 따라서 nohup과 출력 리디렉션은 비동기적인 장기 실행 작업의 안정성과 디버깅 가능성을 확보하는 데 필수적입니다.
5.3 GPU 성능 모니터링 (nvidia-smi)
파인튜닝 중 GPU의 상태를 모니터링하는 것은 성능 병목 현상을 진단하고 잠재적인 문제를 예방하는 데 중요합니다.13
- 모니터링 방법:
- tmux 세션 내에서 창을 분할합니다 (Ctrl+b % 또는 Ctrl+b ").
- 새로운 패널로 이동하여 nvidia-smi 명령어를 실행합니다.13
- 주기적인 업데이트를 위해 watch 명령어 또는 nvidia-smi -l 옵션을 사용합니다:
Bash
watch -n 1 nvidia-smi # 1초마다 nvidia-smi 실행 결과 갱신
또는
Bash
nvidia-smi -l 1 # 1초 간격으로 nvidia-smi 정보 업데이트 (Ctrl+C로 중지)
- 주요 확인 항목:
- GPU-Util: GPU 사용률. 지속적으로 낮다면 데이터 로딩 등 다른 부분에서 병목이 발생했을 수 있습니다.
- Memory-Usage: GPU 메모리 사용량. 최대치에 근접하면 Out-Of-Memory(OOM) 오류 발생 위험이 높으므로 배치 크기나 시퀀스 길이를 조정해야 할 수 있습니다.6
- Temp: GPU 온도. 과도하게 높으면 성능 저하(throttling)가 발생할 수 있습니다.
- Power: 전력 소모량.
- 상세 로깅: 필요한 경우 --query-gpu 옵션을 사용하여 특정 정보를 CSV 형식 등으로 로깅할 수 있습니다.13
nvidia-smi 모니터링은 QLoRA 설정(배치 크기, 그래디언트 누적 스텝 등)이 현재 하드웨어에 적합한지 실시간 피드백을 제공합니다. 낮은 GPU 사용률은 데이터 파이프라인의 비효율성을 시사할 수 있으며, 높은 VRAM 사용량은 OOM 오류를 예측하게 하여 학습 중단을 미리 방지하고 설정을 조정할 기회를 제공합니다. 이는 QLoRA의 목표인 주어진 하드웨어에서의 최대 효율 달성에 중요한 역할을 합니다.33
6. 파인튜닝된 모델 처리: 4비트 베이스 + LoRA 어댑터
QLoRA 파인튜닝이 완료되면, 결과물인 LoRA 어댑터를 저장하고 이를 원본 4비트 베이스 모델과 함께 사용하는 방법을 이해해야 합니다.
6.1 학습된 LoRA 어댑터 저장 (save_pretrained)
Trainer (또는 SFTTrainer)의 save_model() 메서드나 PEFT 모델 객체의 save_pretrained() 메서드를 호출하면, 파인튜닝 과정에서 학습된 LoRA 어댑터의 가중치와 설정 파일만 저장됩니다. 전체 베이스 모델이 저장되는 것이 아닙니다.7
- 저장되는 파일: 일반적으로 지정된 출력 디렉토리에 다음과 같은 파일들이 생성됩니다 26:
- adapter_model.bin (또는 adapter_model.safetensors): 학습된 LoRA 어댑터 레이어의 가중치를 담고 있는 파일입니다.
- adapter_config.json: 어댑터 설정(랭크 r, lora_alpha, target_modules 등)을 정의하는 JSON 파일입니다.
- 저장 명령어: SFTTrainer 예시에서 trainer.save_model(output_dir)를 호출하면 이 과정이 수행됩니다.
어댑터 파일의 크기는 일반적으로 수십~수백 메가바이트(MB) 수준으로, 원본 LLM의 크기(수십~수백 기가바이트(GB))에 비해 매우 작습니다.21 이 작은 크기는 PEFT/QLoRA 방식의 핵심 장점 중 하나로, 파인튜닝된 모델의 저장, 공유, 배포를 훨씬 효율적이고 비용 효과적으로 만듭니다.2 여러 버전의 어댑터를 쉽게 관리하고, 필요에 따라 베이스 모델에 적용하여 사용할 수 있습니다.
6.2 명확화: 4비트 베이스 모델은 동적으로 로드, 튜닝 후 저장되지 않음
사용자의 질문에 대한 명확한 답변은 다음과 같습니다: QLoRA 파인튜닝 프로세스는 새로운, 수정된 4비트 베이스 모델을 생성하여 저장하지 않습니다. 파인튜닝 중 사용된 원본 4비트 양자화 베이스 모델은 변경되지 않고 그대로 유지됩니다.26
파인튜닝된 모델을 사용하기 위한 워크플로우는 항상 다음과 같습니다 25:
- 원본(파인튜닝 전) 베이스 모델을 4비트 양자화 설정과 함께 로드합니다.
- 이 로드된 베이스 모델 위에 저장된 LoRA 어댑터 가중치를 적용합니다.
이는 전체 모델 가중치가 업데이트되고 저장되는 완전 파인튜닝(full fine-tuning) 방식과 대조됩니다.
6.3 추론/사용을 위한 베이스 모델 로딩 및 어댑터 적용
파인튜닝된 QLoRA 모델을 실제로 사용(예: 텍스트 생성 추론)하려면, 앞서 설명한 대로 베이스 모델과 어댑터를 순차적으로 로드해야 합니다.
- 코드 예시:
Python
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import PeftModel
import torch
base_model_id = "mistralai/Mistral-7B-v0.1" # 학습 시 사용했던 베이스 모델 ID
adapter_path = "/workspace/qlora_project/output/final_qlora_adapter" # 저장된 어댑터 경로
# 1. 학습 시와 동일한 양자화 설정으로 베이스 모델 로드
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16, # 또는 torch.float16
bnb_4bit_use_double_quant=True,
)
base_model = AutoModelForCausalLM.from_pretrained(
base_model_id,
quantization_config=quantization_config,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(base_model_id)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
# 2. 로드된 베이스 모델 위에 PEFT 어댑터 로드
# PeftModel.from_pretrained() 함수는 베이스 모델과 어댑터 경로를 인자로 받습니다.
inference_model = PeftModel.from_pretrained(base_model, adapter_path)
inference_model.eval() # 추론 모드로 설정
print("PEFT model loaded successfully for inference.")
# 이제 'inference_model' 객체를 사용하여 텍스트 생성 등 추론 작업을 수행할 수 있습니다.
# 예시:
# inputs = tokenizer("Translate to French: Hello, how are you?", return_tensors="pt").to(inference_model.device)
# outputs = inference_model.generate(**inputs, max_new_tokens=50)
# print(tokenizer.decode(outputs, skip_special_tokens=True))
# (선택 사항) 어댑터 가중치를 베이스 모델에 병합 (메모리 증가 및 비양자화 유발 가능)
# merged_model = inference_model.merge_and_unload()
# print("Adapter merged into the base model. Note: The model might no longer be quantized.") - 로딩 절차: 먼저 AutoModelForCausalLM.from_pretrained를 사용하여 베이스 모델을 학습 시와 동일한 BitsAndBytesConfig로 로드합니다. 그 다음, PeftModel.from_pretrained를 호출하여 로드된 base_model 객체와 저장된 adapter_path를 전달하여 어댑터를 적용합니다.25
- merge_and_unload(): 이 메서드는 LoRA 어댑터 가중치를 베이스 모델 가중치에 직접 병합하여 단일 모델로 만듭니다.25 하지만 이 과정은 일반적으로 모델을 원래 정밀도(예: float16)로 되돌리므로, 4비트 양자화의 메모리 이점을 상실하게 됩니다. 병합된 모델은 더 많은 메모리를 요구하지만, 특정 배포 시나리오(예: llama.cpp를 사용하여 GGUF 형식으로 변환 37)나 추론 속도 최적화에 유용할 수 있습니다.
베이스 모델과 어댑터의 분리는 QLoRA의 효율성의 근간입니다. 어댑터 파일은 파인튜닝을 통해 학습된 '차이' 또는 '수정' 정보만을 담고 있으며 2, 모델의 대부분 파라미터는 동결된 양자화 베이스 모델에 존재합니다.4 따라서 두 구성 요소를 순차적으로 로드하는 것이 필수적입니다. 베이스 모델이 기반을 제공하고, 어댑터가 그 위에 태스크별 조정을 적용하는 방식입니다.25 어댑터 디렉토리만 직접 로드하려고 시도하면 실패합니다. 이 로딩 메커니즘을 정확히 이해하는 것이 파인튜닝된 모델을 올바르게 사용하거나 배포하는 데 중요합니다.
7. 결론
본 가이드북은 Vast.ai 환경에서 QLoRA 기법을 사용하여 대규모 언어 모델을 파인튜닝하는 전 과정을 상세히 다루었습니다. 주요 단계는 다음과 같습니다:
- Vast.ai 환경 설정: 적절한 PyTorch Docker 템플릿 선택, GPU 인스턴스 사양 고려, 안정적인 SSH 연결 및 tmux 사용, 초기 환경 검증 (torch, cuda, nvidia-smi).
- 데이터 및 코드 준비: 데이터 크기와 위치에 따른 최적의 전송 방법 선택 (scp, wget), 체계적인 디렉토리 구조 구성, QLoRA 호환성을 위한 특정 버전의 라이브러리 설치.
- QLoRA 파이프라인 구성: BitsAndBytesConfig를 이용한 4비트 양자화 베이스 모델 로딩, LoraConfig를 이용한 LoRA 어댑터 설정 (특히 target_modules 선택의 중요성), 데이터셋 포맷팅 및 패킹, TrainingArguments를 통한 학습 하이퍼파라미터 설정 (특히 gradient_checkpointing의 중요성).
- 실행 및 모니터링: trl의 SFTTrainer를 활용한 간소화된 학습 실행, tmux와 nohup을 이용한 안정적인 백그라운드 실행 및 로깅, nvidia-smi를 통한 실시간 GPU 성능 모니터링.
- 결과물 처리: 파인튜닝 결과로 LoRA 어댑터만 저장되며(save_pretrained), 사용 시에는 원본 4비트 베이스 모델을 먼저 로드한 후 어댑터를 적용(PeftModel.from_pretrained)해야 한다는 점 명확화.
Vast.ai의 유연한 GPU 자원과 QLoRA의 메모리 효율성을 결합함으로써, 이전에는 접근하기 어려웠던 대규모 언어 모델의 파인튜닝이 개인 연구자나 소규모 팀에게도 가능해졌습니다.21
성공적인 QLoRA 파인튜닝을 위해서는 본 가이드에서 제시된 단계별 지침을 따르는 것 외에도, 사용 중인 모델, 데이터셋, 하드웨어에 맞춰 하이퍼파라미터(LoRA 랭크 r, lora_alpha, 학습률, 대상 모듈 등)를 실험적으로 조정하는 과정이 필요합니다. 또한, tmux를 활용한 안정적인 실행 환경 구축과 nvidia-smi를 통한 세심한 모니터링은 예상치 못한 문제를 조기에 발견하고 자원을 효율적으로 사용하는 데 필수적입니다. 향후 모델 성능 평가 및 실제 서비스 배포 등의 추가 단계를 고려할 수 있습니다.
참고 자료
- PyTorch - Guides - Vast.ai, 4월 24, 2025에 액세스, https://docs.vast.ai/pytorch
- PEFT - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/transformers/peft
- Bitsandbytes - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/transformers/main/quantization/bitsandbytes
- Enhancing LLM Accessibility: A Deep Dive into QLoRA Through Fine-tuning Llama Model on a single AMD GPU, 4월 24, 2025에 액세스, https://rocm.blogs.amd.com/artificial-intelligence/llama-Qlora/README.html
- Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA, 4월 24, 2025에 액세스, https://letter-night.tistory.com/m/379
- Fine-Tuning Open-Source LLM using QLoRA with MLflow and PEFT, 4월 24, 2025에 액세스, https://mlflow.org/docs/latest/llms/transformers/tutorials/fine-tuning/transformers-peft
- deep-learning-pytorch-huggingface/training/fine-tune-llms-in-2024 ..., 4월 24, 2025에 액세스, https://github.com/philschmid/deep-learning-pytorch-huggingface/blob/main/training/fine-tune-llms-in-2024-with-trl.ipynb
- Instances Guide - Guides - Vast.ai, 4월 24, 2025에 액세스, https://docs.vast.ai/instances-guide
- SSH/SCP - Vast.ai, 4월 24, 2025에 액세스, https://docs.vast.ai/instances/sshscp
- Creating a Custom Template - Guides - Vast.ai, 4월 24, 2025에 액세스, https://docs.vast.ai/creating-a-custom-template
- Open WebUI + Ollama - Vast.ai | Console, 4월 24, 2025에 액세스, https://cloud.vast.ai/template/readme/5d2c8df8e0d0ab7d1a7a3ed0f9105637
- How to render blender with Vast.AI - Crypto Labs (Pty) Ltd, 4월 24, 2025에 액세스, https://www.cryptolabs.co.za/2020/04/30/how-to-render-blender-with-vast-ai/
- Displaying Full GPU Details With nvidia-smi | Baeldung on Linux, 4월 24, 2025에 액세스, https://www.baeldung.com/linux/nvidia-smi-full-gpu-details
- Machine Hosting Setup guide - Vast.ai | Console, 4월 24, 2025에 액세스, https://cloud.vast.ai/host/setup
- Data Movement - vast.ai, 4월 24, 2025에 액세스, https://docs.vast.ai/instances/data-movement
- Data Movement - Guides - Vast.ai, 4월 24, 2025에 액세스, https://docs.vast.ai/data-movement
- Transfer all content from one shared server to another using wget? - Stack Overflow, 4월 24, 2025에 액세스, https://stackoverflow.com/questions/15017441/transfer-all-content-from-one-shared-server-to-another-using-wget
- Introduction to High-Performance Computing: Transferring files - GitHub Pages, 4월 24, 2025에 액세스, https://epcced.github.io/hpc-intro-2020-06-30/15-transferring-files/index.html
- Preliminary guide to renting GPUs via vast.ai. May or may not have incomplete or wrong instructions, so follow this at your own risk. : r/GameUpscale - Reddit, 4월 24, 2025에 액세스, https://www.reddit.com/r/GameUpscale/comments/bf7jk6/preliminary_guide_to_renting_gpus_via_vastai_may/
- Fine-Tune Gemma using Hugging Face Transformers and QloRA ..., 4월 24, 2025에 액세스, https://ai.google.dev/gemma/docs/core/huggingface_text_finetune_qlora
- huggingface/peft: PEFT: State-of-the-art Parameter-Efficient Fine-Tuning. - GitHub, 4월 24, 2025에 액세스, https://github.com/huggingface/peft
- How to Fine-Tune LLMs in 2024 with Hugging Face - Philschmid, 4월 24, 2025에 액세스, https://www.philschmid.de/fine-tune-llms-in-2024-with-trl
- Fine-tuning - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/transformers/en/training
- Fine-Tuning Gemma Models in Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/blog/gemma-peft
- How to load a model fine-tuned with QLoRA - Transformers - Hugging Face Forums, 4월 24, 2025에 액세스, https://discuss.huggingface.co/t/how-to-load-a-model-fine-tuned-with-qlora/78157
- LoRA - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/peft/main/developer_guides/lora
- QLoRA-LLM - A custom implementation of Quantized LoRA for fine-tuning a LLM, 4월 24, 2025에 액세스, https://www.vectortheta.com/blog/QLoRA-LLM
- LoRA - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/peft/package_reference/lora
- How to Fine-tune an LLM Part 3: The HuggingFace Trainer | alpaca_ft - Wandb, 4월 24, 2025에 액세스, https://wandb.ai/capecape/alpaca_ft/reports/How-to-Fine-tune-an-LLM-Part-3-The-HuggingFace-Trainer--Vmlldzo1OTEyNjMy
- Load adapters with PEFT - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/transformers/v4.43.0/peft
- Correct way to save/load adapters and checkpoints in PEFT - Hugging Face Forums, 4월 24, 2025에 액세스, https://discuss.huggingface.co/t/correct-way-to-save-load-adapters-and-checkpoints-in-peft/77836
- How to run a python program in the background even after closing the terminal? [duplicate], 4월 24, 2025에 액세스, https://askubuntu.com/questions/396654/how-to-run-a-python-program-in-the-background-even-after-closing-the-terminal
- In-depth guide to fine-tuning LLMs with LoRA and QLoRA - Mercity AI, 4월 24, 2025에 액세스, https://www.mercity.ai/blog-post/guide-to-fine-tuning-llms-with-lora-and-qlora
- Using, saving, and loading an encapsulated PEFT-tuned model inside a regular pytorch model - Hugging Face Forums, 4월 24, 2025에 액세스, https://discuss.huggingface.co/t/using-saving-and-loading-an-encapsulated-peft-tuned-model-inside-a-regular-pytorch-model/133577
- bitsandbytes - Hugging Face, 4월 24, 2025에 액세스, https://huggingface.co/docs/transformers/quantization/bitsandbytes
- Issues when switching between multiple adapters LoRAs · Issue #1802 · huggingface/peft, 4월 24, 2025에 액세스, https://github.com/huggingface/peft/issues/1802
- How to save a quantized model · Issue #114 · artidoro/qlora - GitHub, 4월 24, 2025에 액세스, https://github.com/artidoro/qlora/issues/114