<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fine-Tuning on kenji.blog</title><link>http://kenji.blog/ko/categories/fine-tuning/</link><description>Recent content in Fine-Tuning on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ko</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ko/categories/fine-tuning/index.xml" rel="self" type="application/rss+xml"/><item><title>온프레미스 환경에서 TinyLLaMA를 가장 빠르게 튜닝하는 방법</title><link>http://kenji.blog/ko/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/ko/p/tinyllama-on-premises-fast-tuning-guide/</guid><description>&lt;img src="http://kenji.blog/p/tinyllama-on-premises-fast-tuning-guide/img/eyecatch.jpg" alt="Featured image of post 온프레미스 환경에서 TinyLLaMA를 가장 빠르게 튜닝하는 방법" />&lt;h2 id="1-시작하며-왜-지금-tinyllama와-온프레미스인가">1. 시작하며: 왜 지금, TinyLLaMA와 온프레미스인가?
&lt;/h2>&lt;p>대규모 언어 모델(LLM)의 진화는 무서운 속도로 진행되고 있지만, 그에 따라 모델의 파라미터 수도 수천억 규모로 계속 팽창하고 있습니다. GPT-4나 Claude 3와 같은 초거대 모델은 비할 데 없는 성능을 자랑하는 반면, 추론이나 학습에 드는 계산 비용, 그리고 외부 API를 이용할 때의 보안 및 데이터 프라이버시 우려가 기업에게 큰 장애물이 되고 있습니다. 특히 기밀성이 높은 사내 데이터나 개인정보를 다루는 업무에서는 클라우드상의 퍼블릭 LLM API로 데이터를 전송하는 것이 컴플라이언스(GDPR이나 APPI 등) 관점에서 허용되지 않는 경우가 많습니다.&lt;/p>
&lt;p>그래서 각광받고 있는 것이 **소규모 언어 모델(SLM: Small Language Models)**과 &lt;strong>온프레미스 환경에서의 로컬 운영&lt;/strong>입니다. 그중에서도 &amp;lsquo;&lt;strong>TinyLLaMA&lt;/strong>&amp;lsquo;는 불과 1.1B(11억) 파라미터라는 콤팩트한 크기이면서도 약 3조 토큰이라는 방대한 데이터 세트로 사전 학습되어, 동급 모델과 비교해 경이로운 성능을 발휘합니다.&lt;/p>
&lt;p>본 기사에서는 이 TinyLLaMA를 온프레미스 환경(로컬 서버나 워크스테이션)에서 자사 전용 태스크를 위해 &amp;lsquo;가장 빠르고 고효율&amp;rsquo;로 파인튜닝(미세 조정)하기 위한 완전한 가이드를 제공합니다. 수학적 배경부터 최신 최적화 기술, 그리고 구체적인 PyTorch 구현 코드까지 망라하여 해설해 나갈 것입니다.&lt;/p>
&lt;hr>
&lt;h2 id="2-tinyllama의-아키텍처와-특징">2. TinyLLaMA의 아키텍처와 특징
&lt;/h2>&lt;p>TinyLLaMA는 Meta사가 개발한 LLaMA(Large Language Model Meta AI) 아키텍처를 따르고 있습니다. 파라미터 수를 1.1B로 억제하면서도 LLaMA 2와 같은 기술 스택을 이용하고 있어 생태계 호환성이 매우 높은 것이 특징입니다.&lt;/p>
&lt;h3 id="주요-아키텍처-컴포넌트">주요 아키텍처 컴포넌트
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization):&lt;/strong>
기존의 LayerNorm 계산에서 평균 뺄셈을 생략하여 계산 효율을 향상시킨 정규화 기법입니다. 학습의 안정성을 유지하면서 처리량(throughput)을 향상시킵니다.&lt;/li>
&lt;li>&lt;strong>SwiGLU 활성화 함수:&lt;/strong>
피드 포워드 네트워크(FFN)에서 기존의 ReLU나 GELU 대신 SwiGLU를 채택했습니다. 이는 수학적으로 다음과 같이 표현됩니다.
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
여기서 $\otimes$는 요소별 곱(아다마르 곱)을 나타내며, Swish 함수는 $\text{Swish}(z) = z \cdot \sigma(\beta z)$ 입니다. 이로 인해 표현력이 크게 향상됩니다.&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding):&lt;/strong>
절대적 위치 인코딩과 상대적 위치 인코딩의 장점을 결합한 기법입니다. 시퀀스 길이가 확장되었을 때도 높은 일반화 성능을 가집니다.&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA):&lt;/strong>
Multi-Head Attention (MHA)와 Multi-Query Attention (MQA)의 중간적인 접근 방식으로, 키와 밸류의 헤드를 그룹화함으로써 메모리 대역폭을 절약하고 추론 속도를 획기적으로 향상시킵니다.&lt;/li>
&lt;/ol>
&lt;p>다음 Mermaid 다이어그램은 TinyLLaMA의 전반적인 데이터 흐름과 Transformer 블록 구조를 보여줍니다.&lt;/p>
&lt;div class="mermaid">graph TD
A["입력 텍스트"] --> B["토크나이저 (BPE)"]
B --> C["임베딩 레이어"]
C --> D["트랜스포머 블록 (TinyLLaMA용 22개 레이어)"]
D --> E["RMSNorm (최종)"]
E --> F["선형 투영 (어휘 크기)"]
F --> G["출력 확률 (Softmax)"]
subgraph "트랜스포머 블록 구조"
D1["입력 은닉 상태"] --> D2["RMSNorm"]
D2 --> D3["그룹화된 쿼리 어텐션 (GQA)"]
D3 --> D4["잔차 연결 (Residual Add)"]
D4 --> D5["RMSNorm"]
D5 --> D6["SwiGLU FFN"]
D6 --> D7["잔차 연결 (Residual Add)"]
D7 --> D8["다음 레이어로 출력"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-파인튜닝의-돌파구-lora와-qlora">3. 파인튜닝의 돌파구: LoRA와 QLoRA
&lt;/h2>&lt;p>온프레미스 환경에서 전체 파라미터의 파인튜닝을 수행하려면 1.1B 모델이라 하더라도 옵티마이저의 상태나 그래디언트를 유지하기 위해 수십 GB의 VRAM(비디오 메모리)을 소비합니다. 제한된 리소스로 효율적인 학습을 수행하기 위해 필수적인 것이 &lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong> 기법인 &amp;lsquo;&lt;strong>LoRA&lt;/strong>&amp;lsquo;와 그 양자화 확장인 &amp;lsquo;&lt;strong>QLoRA&lt;/strong>&amp;lsquo;입니다.&lt;/p>
&lt;h3 id="31-lora-low-rank-adaptation의-수학적-배경">3.1 LoRA (Low-Rank Adaptation)의 수학적 배경
&lt;/h3>&lt;p>LoRA는 사전 학습된 가중치 행렬을 고정(프리즈)하고, 그 가중치의 업데이트 양($\Delta W$)을 낮은 랭크를 가진 두 개의 작은 행렬의 곱으로 근사하는 기법입니다.&lt;/p>
&lt;p>사전 학습된 가중치를 $W_0 \in \mathbb{R}^{d \times k}$ 라고 합시다. 풀 파인튜닝에서는 $W_0$ 자체를 업데이트하여 $W_0 + \Delta W$ 로 만들지만, LoRA에서는 업데이트 행렬 $\Delta W$ 를 다음과 같이 분해합니다.&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>여기서 $B \in \mathbb{R}^{d \times r}$, $A \in \mathbb{R}^{r \times k}$ 이며, $r$은 랭크(Rank)라고 불리는 하이퍼파라미터로, $r \ll \min(d, k)$ 를 만족하는 매우 작은 값(보통 8, 16, 32 등)입니다.&lt;/p>
&lt;p>포워드 패스의 계산은 다음과 같습니다.&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>초기 상태에서 행렬 $A$는 정규 분포(가우스 분포)로 무작위 초기화되고, 행렬 $B$는 영행렬로 초기화됩니다. 이에 따라 학습 시작 시의 $\Delta W$는 0이 되어, 베이스 모델의 출력을 완전히 유지한 상태에서 학습을 시작할 수 있습니다.&lt;/p>
&lt;div class="mermaid">graph LR
X["입력 벡터 x"] --> W0["고정된 사전 학습 가중치 (W_0)"]
X --> A["학습 가능한 LoRA 행렬 A (r x k)"]
A --> B["학습 가능한 LoRA 행렬 B (d x r)"]
W0 --> Add["벡터 덧셈"]
B --> Add
Add --> Y["출력 벡터 h"]&lt;/div>
&lt;h3 id="32-qlora-quantized-lora의-혁신성">3.2 QLoRA (Quantized LoRA)의 혁신성
&lt;/h3>&lt;p>QLoRA는 LoRA의 접근 방식을 더욱 발전시켜 베이스 모델 $W_0$ 를 4-bit 정밀도(NormalFloat 4, NF4)로 양자화하여 메모리에 로드하는 기법입니다. 이를 통해 VRAM 소비량을 획기적으로 줄입니다.&lt;/p>
&lt;p>QLoRA에는 3가지 중요한 기술이 포함되어 있습니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>4-bit NormalFloat (NF4) 양자화:&lt;/strong> 정규 분포를 따르는 가중치에 최적화된 이론적으로 가장 이상적인 데이터 타입.&lt;/li>
&lt;li>&lt;strong>Double Quantization (이중 양자화):&lt;/strong> 양자화 상수(스케일 팩터) 자체도 양자화하여 메모리를 추가로 절약.&lt;/li>
&lt;li>&lt;strong>Paged Optimizers:&lt;/strong> NVIDIA의 통합 메모리 기능을 활용하여 VRAM이 부족할 때 옵티마이저의 상태를 CPU의 RAM으로 일시적으로 대피시키는 메커니즘.&lt;/li>
&lt;/ol>
&lt;p>이에 따라 보통 16GB~24GB의 VRAM이 필요한 튜닝이 소비자용 GPU(RTX 3060 12GB나 RTX 4070 등)에서도 여유롭게 실행 가능해집니다.&lt;/p>
&lt;hr>
&lt;h2 id="4-온프레미스-환경에서의-하드웨어-요구사항과-셋업">4. 온프레미스 환경에서의 하드웨어 요구사항과 셋업
&lt;/h2>&lt;p>TinyLLaMA (1.1B)를 QLoRA로 튜닝할 경우 하드웨어 요구사항을 매우 낮출 수 있습니다.&lt;/p>
&lt;h3 id="권장-하드웨어-사양">권장 하드웨어 사양
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU:&lt;/strong> NVIDIA RTX 3060 (12GB), RTX 3090/4090 (24GB), 또는 NVIDIA A10G/A100 등. VRAM은 최소 8GB만 있어도 동작하지만, 배치 크기를 확보하기 위해서는 12GB 이상을 권장합니다.&lt;/li>
&lt;li>&lt;strong>CPU:&lt;/strong> 8코어 이상의 모던 CPU (Intel Core i7/i9, AMD Ryzen 7/9)&lt;/li>
&lt;li>&lt;strong>RAM:&lt;/strong> 32GB 이상 (Paged Optimizers를 이용할 경우 VRAM에서의 대피소로서 중요)&lt;/li>
&lt;li>&lt;strong>스토리지:&lt;/strong> NVMe SSD (데이터 세트 로딩이나 모델 저장을 가속하기 위함)&lt;/li>
&lt;/ul>
&lt;h3 id="소프트웨어-환경-구축">소프트웨어 환경 구축
&lt;/h3>&lt;p>Ubuntu 22.04 LTS 환경을 가정한 셋업 절차입니다. Python 3.10 이상을 사용합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 가상 환경 생성 및 활성화&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python3 -m venv tinyllama_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">source&lt;/span> tinyllama_env/bin/activate
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># PyTorch 설치 (CUDA 12.1용)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 트랜스포머 관련 라이브러리 설치&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install transformers datasets peft trl accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="5-가장-빠른-튜닝을-위한-최적화-기술">5. 가장 빠른 튜닝을 위한 최적화 기술
&lt;/h2>&lt;p>단순히 스크립트를 돌리는 것뿐만 아니라, &amp;lsquo;가장 빠르게&amp;rsquo; 튜닝을 완료하기 위해서는 다음과 같은 최적화 기법을 조합해야 합니다.&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>표준적인 어텐션(Attention) 메커니즘은 시퀀스 길이 $N$ 에 대해 시간·공간 계산량이 $O(N^2)$ 가 됩니다. Flash Attention 2는 GPU의 SRAM과 HBM(High Bandwidth Memory) 사이의 메모리 접근을 최적화함으로써 계산량을 줄이지 않고도 I/O 병목을 해소하여 학습 속도를 수 배 끌어올리고 메모리 소비를 급감시킵니다.&lt;/p>
&lt;h3 id="52-gradient-checkpointing-그래디언트-체크포인트">5.2 Gradient Checkpointing (그래디언트 체크포인트)
&lt;/h3>&lt;p>포워드 패스에서 계산된 중간 활성화를 모두 VRAM에 저장하는 것이 아니라 일부만 저장하고, 백워드 패스에서 필요해졌을 때 다시 계산하는 기법입니다. 계산 시간은 약 20% 증가하지만 메모리 소비량을 획기적으로 줄일 수 있기 때문에, 결과적으로 더 큰 배치 크기를 설정할 수 있어 전체적인 처리량이 향상됩니다.&lt;/p>
&lt;h3 id="53-mixed-precision-training-혼합-정밀도-학습과-bfloat16">5.3 Mixed Precision Training (혼합 정밀도 학습)과 Bfloat16
&lt;/h3>&lt;p>GPU의 텐서 코어(Tensor Core)를 최대한 활용하기 위해 학습 시의 계산을 &lt;code>bfloat16&lt;/code> (Brain Floating Point)으로 수행합니다. &lt;code>float16&lt;/code> 과 비교하여 지수부의 비트 길이가 &lt;code>float32&lt;/code> 와 동일하기 때문에 오버플로·언더플로의 위험이 극히 낮아 학습이 안정됩니다.&lt;/p>
&lt;hr>
&lt;h2 id="6-실전-tinyllama의-qlora-파인튜닝-코드">6. 실전: TinyLLaMA의 QLoRA 파인튜닝 코드
&lt;/h2>&lt;p>그러면 위에서 언급한 모든 최적화를 포함한 가장 빠른 튜닝용 PyTorch 스크립트를 해설하겠습니다. 여기서는 Hugging Face의 &lt;code>trl&lt;/code> (Transformer Reinforcement Learning) 라이브러리의 &lt;code>SFTTrainer&lt;/code> 를 이용합니다.&lt;/p>
&lt;h3 id="61-데이터-세트-준비-및-모델-로드">6.1 데이터 세트 준비 및 모델 로드
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datasets&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">load_dataset&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TrainingArguments&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">trl&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. 모델과 토크나이저 지정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;TinyLlama/TinyLlama-1.1B-Chat-v1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. QLoRA용 4-bit 양자화 설정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bnb_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">load_in_4bit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_use_double_quant&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_quant_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;nf4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_compute_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span> &lt;span class="c1"># 계산은 bfloat16으로 수행&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. 모델 로드 (Flash Attention 2 활성화)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Loading model...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantization_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">bnb_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_flash_attention_2&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span> &lt;span class="c1"># 속도 극대화의 핵심&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. 토크나이저 로드&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">trust_remote_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pad_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">eos_token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">padding_side&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;right&amp;#34;&lt;/span> &lt;span class="c1"># fp16/bf16 트레이닝 시의 버그 회피를 위해 right로 설정&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-lora-어댑터-적용-및-데이터-세트-성형">6.2 LoRA 어댑터 적용 및 데이터 세트 성형
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. k-bit 학습 준비 및 그래디언트 체크포인트 활성화&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gradient_checkpointing_enable&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 6. LoRA 설정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">peft_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 랭크&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 스케일링 팩터&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_dropout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.05&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bias&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;none&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;CAUSAL_LM&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_modules&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;q_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;k_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;v_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;o_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;gate_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;up_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;down_proj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 모든 Linear 레이어를 타겟으로 하면 성능이 향상됨&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">peft_config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">print_trainable_parameters&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 출력 예시: trainable params: 14,286,848 || all params: 1,114,335,232 || trainable%: 1.282%&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 7. 데이터 세트 로드 (여기서는 예시로 일본어 Instruction 데이터 세트를 사용)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 실제로는 온프레미스의 프라이빗 JSONL 파일 등을 로드합니다.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">load_dataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kunishou/databricks-dolly-15k-ja&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">split&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;train&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">format_instruction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> ChatML 포맷이나 프롬프트 템플릿에 맞추어 문자열을 성형합니다.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_start|&amp;gt;user&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;instruction&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">sample&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;input&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;input&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_end|&amp;gt;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;|im_start|&amp;gt;assistant&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;output&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;lt;|im_end|&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataset&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">format_instruction&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="63-트레이닝-실행">6.3 트레이닝 실행
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 8. 트레이닝 인자 설정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">training_args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TrainingArguments&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-output&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">per_device_train_batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># VRAM에 여유가 있다면 올림&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gradient_accumulation_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 실질적인 배치 크기 = 8 * 2 = 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">optim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;paged_adamw_32bit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Paged Optimizer에 의한 VRAM 절약&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">save_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logging_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">learning_rate&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">2e-4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fp16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bf16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 혼합 정밀도 학습 (bfloat16)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_grad_norm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 테스트용으로 500 스텝. 실전에서는 에포크 수로 지정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">warmup_ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.03&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">group_by_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lr_scheduler_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 9. SFTTrainer를 이용한 학습 시작&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">train_dataset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">peft_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">peft_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dataset_text_field&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_seq_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 예상되는 입력 길이에 맞춰 조정&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">training_args&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Starting training...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">train&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 10. LoRA 어댑터 저장&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Training complete and model saved.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-성능-평가-및-트러블슈팅">7. 성능 평가 및 트러블슈팅
&lt;/h2>&lt;p>온프레미스 환경에서 학습을 돌릴 때 자주 직면하는 문제와 그 해결책입니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>OOM(Out Of Memory)이 발생한다:&lt;/strong>
&lt;ul>
&lt;li>&lt;code>per_device_train_batch_size&lt;/code> 를 &lt;code>1&lt;/code> 로 낮춥니다.&lt;/li>
&lt;li>&lt;code>gradient_accumulation_steps&lt;/code> 를 늘려 실질적인 배치 크기를 유지합니다.&lt;/li>
&lt;li>&lt;code>max_seq_length&lt;/code> 를 &lt;code>2048&lt;/code> 에서 &lt;code>1024&lt;/code> 나 &lt;code>512&lt;/code> 로 줄입니다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Loss가 떨어지지 않는다·발산한다:&lt;/strong>
&lt;ul>
&lt;li>학습률 (&lt;code>learning_rate&lt;/code>)이 너무 클 가능성이 있습니다. &lt;code>2e-4&lt;/code> 에서 &lt;code>5e-5&lt;/code> 정도로 낮춰보세요.&lt;/li>
&lt;li>Bfloat16이 아닌 Float16을 사용하고 있을 경우 그래디언트의 언더플로가 일어나고 있을 가능성이 있습니다. &lt;code>bf16=True&lt;/code> 를 확인하세요.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>추론 시 알 수 없는 문자열이 생성된다:&lt;/strong>
&lt;ul>
&lt;li>&lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> 가 올바르게 설정되어 있는지 확인하세요. 또한 데이터 세트의 포맷(&lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code> 등의 특수 토큰)이 베이스 모델의 사전 학습 때와 일치하는지 확인이 필요합니다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-튜닝-후-모델-배포-deployment">8. 튜닝 후 모델 배포 (Deployment)
&lt;/h2>&lt;p>튜닝이 완료되면 저장되는 것은 &amp;lsquo;베이스 모델 전체&amp;rsquo;가 아니라 수 MB~수십 MB의 &amp;lsquo;&lt;strong>LoRA 어댑터 (차이점 가중치)&lt;/strong>&amp;lsquo;뿐입니다. 추론을 고속으로 수행하기 위해서는 이 LoRA 가중치를 원래 베이스 모델에 병합(통합)하여 단일 모델로 저장해야 합니다.&lt;/p>
&lt;h3 id="모델-병합-스크립트">모델 병합 스크립트
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># FP16/BF16으로 모델과 어댑터 로드&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">torch_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output_dir&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 가중치를 병합하여 저장&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge_and_unload&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">safe_serialization&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Model merged and saved successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="vllm을-활용한-초고속-추론-서버-구축">vLLM을 활용한 초고속 추론 서버 구축
&lt;/h3>&lt;p>온프레미스 환경에서의 배포에 있어 추론 속도(Tokens per second)를 극대화하기 위해서는 Hugging Face의 표준 &lt;code>pipeline&lt;/code> 이 아니라 &lt;strong>vLLM&lt;/strong>이나 &lt;strong>TGI (Text Generation Inference)&lt;/strong> 의 사용을 강력히 권장합니다. vLLM은 PagedAttention 기술을 사용하여 GPU 메모리의 단편화를 방지하고 병렬 요청 처리 능력을 극적으로 향상시킵니다.&lt;/p>
&lt;p>다음 Mermaid 다이어그램은 학습부터 추론 서버 배포까지의 파이프라인을 보여줍니다.&lt;/p>
&lt;div class="mermaid">graph TD
A["원시 프라이빗 데이터"] --> B["전처리 및 포맷팅 (JSONL)"]
B --> C["QLoRA 파인튜닝 (SFTTrainer)"]
C --> D["LoRA 어댑터 가중치 (.safetensors)"]
D --> E["베이스 TinyLLaMA 1.1B와 병합"]
E --> F["병합된 모델"]
F --> G["vLLM 서버를 통해 배포"]
G --> H["API 엔드포인트 / UI (예: 챗봇)"]&lt;/div>
&lt;p>vLLM을 사용한 API 서버 실행은 다음 명령어 하나로 완료됩니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">python -m vllm.entrypoints.openai.api_server &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model ./tinyllama-merged &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --host 0.0.0.0 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --port &lt;span class="m">8000&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --max-model-len &lt;span class="m">2048&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dtype bfloat16
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>이것으로 OpenAI API 호환 엔드포인트가 온프레미스 환경에 구축되어, 안전하고 빠르게 로컬 AI를 활용할 수 있게 됩니다.&lt;/p>
&lt;hr>
&lt;h2 id="9-마무리">9. 마무리
&lt;/h2>&lt;p>본 기사에서는 1.1B라는 가벼운 파라미터 수임에도 불구하고 고성능인 &amp;lsquo;TinyLLaMA&amp;rsquo;를 대상으로 온프레미스 환경에서 가장 빠르고 메모리 효율적으로 파인튜닝을 수행하는 기법을 해설했습니다.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LoRA / QLoRA&lt;/strong> 를 통해 소비자용 GPU에서도 본격적인 LLM 튜닝이 가능해졌습니다.&lt;/li>
&lt;li>&lt;strong>Flash Attention 2&lt;/strong> 와 &lt;strong>Gradient Checkpointing&lt;/strong> 을 구사하여 학습 시간과 VRAM 소비를 극한까지 최적화했습니다.&lt;/li>
&lt;li>&lt;strong>vLLM&lt;/strong> 을 활용한 배포로 프로덕션 환경에서도 높은 처리량을 실현했습니다.&lt;/li>
&lt;/ul>
&lt;p>온프레미스에서의 로컬 LLM 운영은 데이터의 기밀성을 보호할 뿐만 아니라, 특정 도메인(법무, 의료, 사내 규정 등)에 특화된 전문 AI를 저비용으로 구축하기 위한 최강의 무기가 됩니다. 꼭 본 가이드를 참고하여 자사 전용의 TinyLLaMA를 육성해 보시기 바랍니다.&lt;/p></description></item></channel></rss>