자연어 처리(NLP) 모델은 계속해서 대규모화되고 있으며, 이를 훈련하거나 활용할 때 필요한 리소스가 엄청나게 증가하고 있습니다. 특히 대형 모델을 활용할 때는 메모리 부족 문제와 계산 비용이 큰 부담이 될 수 있습니다. 이러한 문제를 해결하는 데 있어 LoRA (Low-Rank Adaptation)와 4-bit 양자화 (Quantization)는 매우 유용한 최적화 기법입니다.
DeepSeek가 나옴으로써 새로운 방식이 제시되었지만, 또 다른 방식을 본 포스트를 통해 이 두 가지 기법을 사용하여 효율적으로 모델을 튜닝하는 방법에 대해 작성해보려 합니다. 이해한 내용을 토대로 정리한 것이라 틀린 내용이 있을 수 있으며, 알려주시면 감사하겠습니다.
AutoTokenizer와 AutoModelForCausalLM을 사용하여 베이스 모델을 불러옵니다. 두가지를 사용하여 모델을 메모리와 계산 비용을 줄이면서 로딩할 수 있습니다.
BASE_MODEL = {파인튜닝 할 모델}
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
model = AutoModelForCausalLM.from_pretrained(
BASE_MODEL,
load_in_8bit=True, # 메모리 절약
device_map="auto"
)
AutoTokenizer.from_pretrained(BASE_MODEL)은 사전 훈련된 모델의 토크나이저를 불러오는 함수입니다.
load_in_8bit=True는 모델의 가중치를 8-bit 정밀도로 로딩하여 메모리 사용량을 절약합니다. 8-bit로 로딩된 모델은 계산 속도는 느리지만, 메모리 소비가 크게 줄어듭니다.
device_map="auto"는 모델을 자동으로 GPU에 분배하여, 여러 개의 GPU를 사용할 경우 효율적으로 분산 처리할 수 있게 합니다.
device_map를 통해 원하는 GPU 또는 CPU에 넣어 학습 시킬 수 있습니다.
LoRA는 모델의 가중치를 저차원 형태로 근사하여 파라미터의 수를 줄이는 방법입니다. 이를 통해 훈련 속도는 빠르고 메모리 효율성은 높여주면서 성능 저하를 최소화할 수 있습니다.
LoRA는 특정 레이어에만 적용할 수 있는데, 이를 통해 모델을 최적화할 수 있습니다. LoRA의 핵심 아이디어는 모델의 weight matrix를 두 개의 작은 행렬 곱으로 근사하는 것입니다. 이렇게 하면 매개변수 수가 줄어듭니다.
lora_config = LoraConfig(
r=8, # Rank 값 (작을수록 가볍지만 성능 저하 가능)
lora_alpha=32,
target_modules=["q_proj", "o_proj", "k_proj", "v_proj", "gate_proj", "up_proj", "down_proj"], # 가중치 적용할 레이어
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
r=8은 LoRA의 rank 값을 설정하는 파라미터입니다. r 값이 낮을수록 모델이 가벼워지지만, 너무 낮으면 성능이 저하될 수 있습니다. 일반적으로 r 값은 실험을 통해 최적화됩니다.
lora_alpha=32는 LoRA의 학습률을 설정합니다. 이 값은 모델 학습 과정에서의 가중치 업데이트 크기를 조절합니다.
target_modules는 LoRA를 적용할 레이어들의 목록입니다. 주로 Transformer 모델에서 중요한 역할을 하는 q_proj, o_proj, k_proj, v_proj 등과 같은 레이어를 선택합니다.
lora_dropout=0.05는 LoRA 모델의 드롭아웃 비율입니다. 드롭아웃은 과적합을 방지하고, 모델의 일반화 능력을 높이는 데 도움이 됩니다.
bias="none"는 LoRA가 적용되는 레이어에서 bias 항목을 사용하지 않겠다는 설정입니다.
모델의 크기와 계산 비용을 절감하려면, 모델 가중치의 비트 수를 줄이는 양자화(quantization) 기법을 사용할 수 있습니다. 4-bit 양자화는 32-bit 부동 소수점 대신 4-bit로 모델의 가중치를 압축하여 메모리 사용량을 대폭 줄이고, 속도를 개선하는 방법입니다.
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # Normalized Float 4
bnb_4bit_use_double_quant=True, # 2중 양자화 적용
bnb_4bit_compute_dtype=torch.bfloat16 # bfloat16 사용 (일반적으로 안정적)
)
load_in_4bit=True는 모델을 4-bit 양자화하여 로딩하는 설정입니다. 4-bit 양자화는 모델의 메모리 크기를 크게 줄여주며, GPU나 TPU와 같은 하드웨어에서 효율적으로 동작합니다.
bnb_4bit_quant_type="nf4"는 4-bit 양자화를 위한 방식으로, Normalized Float 4 방식을 사용합니다. 이 방식은 더 높은 정밀도를 유지하면서 메모리를 절약할 수 있게 도와줍니다.
bnb_4bit_use_double_quant=True는 2중 양자화(double quantization)를 적용하여 성능을 향상시키는 방법입니다. 양자화의 정확도를 높여주지만, 추가적인 계산 비용이 들 수 있습니다.
bnb_4bit_compute_dtype=torch.bfloat16는 계산을 bfloat16 데이터 타입으로 설정하여, 양자화된 모델을 보다 안정적으로 처리합니다.
LoRA와 4-bit 양자화를 결합하여 모델을 최적화하면, 메모리 사용량을 절감하고 계산 성능을 크게 향상시킬 수 있습니다. 두 가지 최적화 기법을 동시에 적용하면, 대형 모델을 상대적으로 적은 리소스로 효과적으로 실행할 수 있게 됩니다.
model = AutoModelForCausalLM.from_pretrained(
BASE_MODEL,
quantization_config=bnb_config, # 4-bit 양자화 적용
device_map="auto"
)
lora_config = LoraConfig(
r=8, # Low-rank 차원
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], # LoRA 적용할 레이어 추가
lora_dropout=0.1,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
이 코드에서 모델은 먼저 4-bit 양자화가 적용된 상태로 로딩됩니다. 그 후, LoRA 설정을 적용하여 최적화가 완료된 모델을 만듭니다. 이렇게 하면 메모리 절약은 물론, 모델 훈련 속도와 추론 속도도 향상됩니다.
LoRA와 4-bit 양자화는 대규모 NLP 모델을 보다 효율적으로 다루기 위한 두 가지 강력한 기법입니다. LoRA는 모델의 파라미터 수를 줄여서 훈련 속도와 메모리 효율성을 높이고, 4-bit 양자화는 모델 크기를 줄여 계산 비용을 절감하는 데 유용합니다.
이 두 가지 기법을 결합하여 모델을 최적화하면, 제한된 리소스에서도 대규모 모델을 효과적으로 사용할 수 있습니다.
다음 시간에는 DeepSeek리뷰로 찾아 오도록 하겠습니다.