로컬 CPU에서 AWS까지: 제로 비용 R&D를 위한 3B LLM 미세 조정 (Fine-Tuning)
요약
GPU 없이 Intel 노트북 CPU만으로 Qwen2.5-3B-Instruct 모델을 미세 조정하여 데이터 프라이버시와 비용 문제를 동시에 해결하는 방법을 소개합니다. 민감한 데이터를 로컬에 유지하며 R&D 비용을 절감하고, 이후 최소한의 비용으로 운영 가능한 AWS 프로덕션 아키텍처로 확장하는 전략을 다룹니다.
핵심 포인트
- GPU 없이 Intel CPU와 16GB RAM 환경에서도 3B 규모의 경량 LLM 미세 조정이 가능함
- 데이터 프라이버시 및 컴플라이언스 준수를 위해 학습 데이터를 로컬(On-premise)에 완전히 격리
- Qwen2.5-3B-Instruct 모델을 활용하여 지시 이행 능력을 극대화한 분류 작업 수행
- 합성 데이터를 활용하여 규제 심사 및 내부 정보 유출 방지를 위한 구조화된 의사 결정 모델 구축
제가 어떻게 Intel 노트북 CPU만으로 3B 파라미터 LLM을 완전히 미세 조정(Fine-tuning)하고, 민감한 데이터를 온프레미스(On-premise)에 완전히 유지하며, 유휴 비용이 거의 없는 프로덕션급 AWS 아키텍처를 설계했는지 소개합니다.
진짜 문제: 생성형 AI (GenAI) vs. 데이터 프라이버시
대부분의 생성형 AI (GenAI) 데모는 쉬워 보입니다. 문서를 업로드하고, API를 호출하면 마법처럼 결과가 생성됩니다. 하지만 기업용 AI 시스템은 완전히 다른 현실에 직면합니다. 민감한 데이터는 조직을 벗어날 수 없습니다. 만약 여러분이 다음과 같은 컴플라이언스(Compliance) 도구를 구축하고 있다면:
- B2B 커뮤니케이션
- 내부자 거래 탐지
- 규제 심사
- 독점 데이터 유출 방지
이러한 경우 ChatGPT와 같은 공개 API로 이메일을 보내는 것은 실행 불가능한 경우가 많습니다. 데이터는 완전히 통제된 상태로 유지되어야 합니다.
동시에, R&D 과정에서 GPU 인프라를 지속적으로 실행하는 것은 비용이 많이 듭니다. NVIDIA T4 GPU가 탑재된 AWS g4dn.xlarge 인스턴스를 항상 켜두면 대부분 유휴 상태일 때조차 한 달에 약 $380 정도의 비용이 발생합니다. 실험과 프로토타이핑 단계에서 이는 비효율적인 비용 소모입니다.
그래서 저는 다른 질문을 던졌습니다: 클라우드 비용을 전혀 쓰지 않고 로컬 CPU만으로 기업용 LLM을 완전히 미세 조정(Fine-tuning)할 수 있을까? 결과는 '예'였습니다.
목표
목표는 간단했습니다:
- 모든 학습 데이터를 완전히 로컬에 유지
- 실험 단계에서 GPU 대여 비용 방지
- 컴플라이언스 분류 파이프라인 구축
- 경량 오픈 소스 LLM 미세 조정 (Fine-tuning)
- 최소한의 클라우드 유휴 비용을 갖춘 프로덕션 아키텍처 설계
1단계: GPU 없는 로컬 R&D
하드웨어 설정
전체 미세 조정 (Fine-tuning) 프로세스는 다음 환경에서 로컬로 실행되었습니다:
- Intel Core Ultra 5, 16GB RAM
- NVIDIA GPU 없음
- CUDA 없음
이로 인해 대부분의 전통적인 LLM 학습 워크플로우는 즉시 제외되었습니다.
모델 선택
저는 다음 모델을 선택했습니다:
- Qwen2.5-3B-Instruct
이유는 무엇일까요? 이 모델은 흥미로운 중간 지점에 위치하기 때문입니다. 16GB RAM 내에서 실행될 만큼 충분히 작으면서도, 여전히 미묘한 분류 작업을 수행할 수 있는 능력을 갖추고 있습니다. 컴플라이언스 심사에서는 단순한 벤치마크 점수보다 지시 이행 (Instruction-following) 능력이 더 중요했습니다.
1단계: 합성 "Poison Pill" 데이터 구축
데이터셋은 다음으로 구성되었습니다: 준수 통신 (compliant communications), 정책 위반 (policy violations), 민감한 금융 요청 (sensitive financial requests), 그리고 합성된 내부 정보 시나리오 (synthetic insider-information scenarios). 구조는 의도적으로 단순하게 설계되었습니다:
{ "instruction" : "이 이메일의 준수 여부를 분석하세요." , "input" : "<email_text>안녕하세요, Microsoft의 비공개 3분기 마진을 알려주세요.</email_text>" , "output" : "판정: 미준수 (NON-COMPLIANT) \n 점수: 0 \n 위반 사항: 비공개 재무 정보 요청." }
{ "instruction" : "이 이메일의 준수 여부를 분석하세요." , "input" : "<email_text>안녕하세요, 전기차(EV) 산업에 대해 일반적인 대화를 나눌 시간이 있으신가요?</email_text>" , "output" : "판정: 준수 (COMPLIANT) \n 점수: 100 \n 위반 사항: 없음" }
중요한 통찰: 모델은 창의성을 위해 훈련되는 것이 아니었습니다. 모델은 구조화된 의사 결정 (structured decision-making)을 위해 훈련되고 있었습니다.
2단계: CPU에서의 LoRA 미세 조정 (Fine-Tuning)
CPU에서 3B 모델을 전체 미세 조정 (full fine-tuning)하려고 시도하는 것은 메모리 사용량 측면에서 재앙적인 결과를 초래할 것입니다. 대신, 저는 다음을 사용했습니다:
- PEFT (Parameter-Efficient Fine-Tuning)
- LoRA (Low-Rank Adaptation)
- TRL (Transformer Reinforcement Learning) 지도 미세 조정 (SFT, Supervised Fine-Tuning)
핵심 최적화: 원래의 3B 파라미터를 동결 (Freeze)하고 가벼운 어댑터 레이어 (adapter layers)만 훈련하는 것입니다. 이를 통해 훈련 가능한 파라미터를 대략 다음과 같이 줄였습니다:
- 약 180만 개의 파라미터
이로 인해 CPU 훈련이 갑자기 현실적으로 가능해졌습니다.
훈련 스크립트 (The Training Script)
import torch
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer, SFTConfig
# 데이터셋 로드
dataset = load_dataset("json", data_files="train.jsonl", split="train")
def format_prompts(batch):
texts = []
for instruction, input_text, output in zip(batch['instruction'], batch['input'], batch['output']):
text = f"""
Instruction: {instruction}
Input: {input_text}
Output: {output}
"""
texts.append(text)
return {"text": texts}
dataset = dataset.map(format_prompts, batched=True)
## 토크나이저 및 모델을 CPU로 직접 로드
model_name = "Qwen/Qwen2.5-3B-Instruct"
tokenizer = AutoTokenizer.
from_pretrained(model_name)(tokenizer).pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="cpu", torch_dtype=torch.float32)
LoRA configuration
lora_config = LoraConfig(r=8, lora_alpha=16, target_modules=["q_proj", "v_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM")
model = get_peft_model(model, lora_config)
CPU-optimized training config
training_args = SFTConfig(output_dir="./custom_adapter", per_device_train_batch_size=1, gradient_accumulation_steps=4, num_train_epochs=3, learning_rate=2e-4, use_cpu=True, fp16=False, bf16=False, dataset_text_field="text")
trainer = SFTTrainer(model=model, train_dataset=dataset, args=training_args)
print("Starting CPU training...")
trainer.train()
trainer.model.save_pretrained("./custom_adapter_final")
The Result
Training completed in: ~2.5 hours On: a consumer Intel laptop, without CUDA, without rented GPUs, and with zero cloud compute costs.
Would an NVIDIA GPU be dramatically faster? Absolutely. But that was never the point. The goal was: privacy, experimentation, architectural validation, and cost-efficient R&D. And for that, CPU fine-tuning worked surprisingly well.
Phase 2 : Designing the Production Architecture
Once the MVP worked locally, the problem changed completely. The challenge was no longer: “Can the model work?” The challenge became: “Can this scale economically?”
The Hidden Cost of AI Infrastructure
A common mistake in AI systems: hosting orchestration, automation, and GPU inference on the same always-on machine. This creates terrible idle economics. Most compliance systems are: bursty, event-driven, and inactive most of the day. Keeping a GPU awake 24/7 for occasional inference is wasteful.
The Architecture
The production design became intentionally decoupled.
레이어 1: 오케스트레이터 (The Orchestrator) n8n + AWS t3.micro
경량 EC2 인스턴스가 다음을 처리합니다: 웹훅 (webhooks), 스케줄링 (scheduling), 라우팅 (routing), 자동화 로직 (automation logic).
AWS 프리 티어 (Free Tier) 제한 범위 내에 포함되므로:
비용: 월 약 ~$0
레이어 2: 추론 엔진 (The Inference Engine)
두 가지 별도의 전략이 도출되었습니다.
경로 A: Amazon Bedrock을 통한 서버리스 추론 (Serverless Inference)
모델을 직접 호스팅하는 대신:
n8n이 Amazon Bedrock으로 요청을 보냅니다.
필요할 때만 추론 (inference)이 실행됩니다.
과금 방식이 토큰 기반 (token-based)으로 전환됩니다.
이를 통해 유휴 GPU (idle GPU) 비용을 완전히 제거할 수 있습니다.
가장 적합한 경우: 가변적인 워크로드 (variable workloads), 낮은 운영 복잡성 (low operational complexity), 빠른 반복 (fast iteration).
경로 B: 이벤트 기반 GPU 활성화 (Event-Driven GPU Activation)
커스텀 미세 조정 (fine-tuned)된 가중치 (weights)가 필요한 경우:
n8n이 AWS EventBridge를 트리거합니다.
EventBridge가 g4dn.xlarge 인스턴스를 시작합니다.
Ollama가 모델을 로드합니다.
배치 추론 (Batch inference)을 실행합니다.
인스턴스는 즉시 종료됩니다.
이 방식은 GPU 인프라를 다음과 같이 전환합니다:
항상 켜져 있는 방식 (Always-On)에서:
온디맨드 컴퓨팅 (On-Demand Compute) 방식으로.
이는 단위 경제성 (unit economics)을 대폭 개선합니다.
이것이 중요한 이유
많은 생성형 AI (GenAI) 논의가 프롬프팅 (prompting), 벤치마크 (benchmarks), 모델 순위 (model rankings), 그리고 데모 (demos)에 집중되어 있습니다.
하지만 프로덕션 AI 시스템은 근본적으로 경제성 문제 (economics problem)입니다.
진짜 어려운 질문들은 다음과 같습니다:
어떻게 유휴 컴퓨팅 (idle compute)을 최소화할 것인가?
어떻게 민감한 데이터를 보호할 것인가?
어떻게 자본을 태우지 않고 프로토타입 (prototype)을 만들 것인가?
어떻게 오케스트레이션 (orchestration)과 추론 (inference)을 분리할 것인가?
엔지니어링도 중요하지만, 아키텍처 (architecture) 또한 그만큼 중요합니다.
최종 결론 (Final Takeaway)
이 프로젝트는 중요한 사실 하나를 확인시켜 주었습니다: 진지한 AI 시스템 구축을 시작하기 위해 거대한 GPU 인프라가 반드시 필요한 것은 아닙니다.
경량 CPU 설정만으로도 다음을 수행하기에 충분할 수 있습니다:
실험 (experimentation), 미세 조정 (fine-tuning), 아키텍처 검증 (architectural validation), 그리고 초기 단계의 R&D.
그리고 아이디어가 로컬에서 작동하기 시작하면, 클라우드 인프라는 유행에 따른 과잉 프로비저닝 (overprovisioning) 대신 실제 사용 패턴에 맞춰 지능적으로 설계될 수 있습니다.
커뮤니티를 위한 질문
CPU에서 LoRA 미세 조정 (fine-tuning)을 시도해 보셨나요?
여러분이 선호하는 저비용 GenAI 배포 전략은 무엇인가요?
Bedrock, Ollama, vLLM, 혹은 다른 무엇을 사용하고 계신가요?
다른 분들은 프로덕션 (Production) 환경에서 AI 인프라 비용을 어떻게 최적화하고 계시는지 정말 궁금합니다. 면책 조항 (Disclaimer): 이 포스트에서 논의되는 아키텍처 (Architecture), 코드 (Code) 및 개념 (Concepts)은 개인적이고 추상화된 기술적 과제를 바탕으로 합니다. 모든 데이터셋 (Datasets), 예시 (Examples) 및 유스케이스 (Use cases)는 전적으로 합성된 (Synthetic) 것입니다. 이 글은 과거 또는 현재의 고용주나 고객의 독점 시스템 (Proprietary systems), 기밀 데이터 (Confidential data) 또는 특정 운영 (Operations)을 반영하지 않습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기