> EulerForge > 튜토리얼 > 1. Dense LoRA

1. Dense LoRA

개요

dense_lora는 EulerForge에서 가장 기본적인 파인튜닝 전략입니다. 모델의 FFN(Feed-Forward Network) 및 어텐션 레이어에 있는 nn.LinearLoRALinear로 래핑하여, 원본 가중치는 동결(freeze)하고 소규모 저랭크(low-rank) 파라미터만 학습합니다.


사전 요구 사항


1. Where: 어디에 주입되는가?

BackboneAdapter가 모델 구조를 탐색하여 주입 대상을 찾습니다.

탐색 과정

  1. BackboneAdapter.find_transformer_layers(model) — 모든 트랜스포머 블록을 찾습니다.
  2. 각 블록 내에서 target_keywords에 매칭되는 nn.Linear 모듈을 탐색합니다.
  3. (선택) attn_lora.enabled: true이면 어텐션 프로젝션도 탐색합니다.

타겟 모듈

영역 타겟 키워드 대상 모듈
FFN gate_proj, up_proj, down_proj FFN 내부 Linear 레이어
Attention q_proj, v_proj 어텐션 프로젝션 Linear

관련 설정

backbone: qwen3                    # 백본 어댑터 선택 (qwen3/qwen3.5/llama3/gemma3/mixtral)

injection:
  target_keywords: [gate_proj, up_proj, down_proj]  # FFN 타겟
  start_layer: 0                   # 적용 시작 레이어 (0 = 처음부터)
  num_layers: 0                    # 적용 레이어 수 (0 = 전체)
  attn_lora:
    enabled: true                  # 어텐션 LoRA 활성화
    keywords: [q_proj, v_proj]     # 어텐션 타겟

start_layernum_layers로 적용 범위를 제어할 수 있습니다. 예를 들어 28개 레이어 모델에서 start_layer: 14, num_layers: 14로 설정하면 후반 14개 레이어에만 LoRA를 적용합니다.


2. What: 무엇이 주입되는가?

DenseLoRAInjection 클래스가 inject_dense_lora_inplace()를 호출하여 모델을 in-place로 수정합니다.

변환 과정

각 타겟 nn.LinearLoRALinear로 래핑됩니다:

변환 전: nn.Linear(in_features, out_features)

변환 후: LoRALinear
         ├── base_layer: nn.Linear (frozen, 원본 가중치)
         ├── lora_A: Parameter(r, in_features)    ← 학습 대상
         ├── lora_B: Parameter(out_features, r)    ← 학습 대상
         └── scaling: alpha / r

Forward 동작

[입력 x]
    ├── base_layer(x)           → base_out (원본 출력, 동결)
    │
    └── dropout(x)
        → x @ lora_A.T          → (batch, r)       저랭크 투영
        → result @ lora_B.T     → (batch, out)      복원
        → * scaling              → lora_out          스케일링

최종 출력 = base_out + lora_out

관련 설정

injection:
  strategy: dense_lora             # 전략 선택
  lora_r: 48                       # LoRA 랭크 (학습 파라미터 크기)
  lora_alpha: 96                   # 스케일링 팩터 (scaling = alpha/r)
  lora_dropout: 0.05               # LoRA 브랜치 드롭아웃

파라미터 가이드: - lora_r: 클수록 표현력 증가, 메모리/연산 비용도 증가. 일반적으로 16~64. - lora_alpha: 보통 lora_r의 2배로 설정 (scaling = 2.0). - lora_dropout: 과적합 방지. 0.0~0.1 범위 권장.


3. When: 언제 어떤 파라미터를 훈련하는가?

dense_lora는 가장 단순한 단일 페이즈 스케줄을 사용합니다.

페이즈 구성

training:
  phases:
    - step: 0
      trainable: ["lora", "attn_lora"]

스텝 0부터 훈련 끝까지 lora(FFN LoRA)와 attn_lora(어텐션 LoRA) 그룹만 학습합니다.

타임라인

Step 0 ──────────────────────────────────────> Step 5000
  │
  └── [lora + attn_lora 훈련]
      base_layer: frozen (동결)
      lora_A, lora_B: trainable (학습)

4. 전체 설정 파일 해설

configs/presets/qwen3.5_0.8b_dense_lora_sft.yml 전문:

# ── 모델 정보 ──
device: cuda:0                              # GPU 디바이스
backbone: qwen3                             # [Where] 백본 어댑터: Qwen3Adapter
model_name: Qwen/Qwen3.5-0.8B-Base           # HuggingFace 모델 ID

# ── 인젝션 설정 ──
injection:
  strategy: dense_lora                      # [What] Dense LoRA 전략
  lora_r: 48                                # [What] LoRA 랭크
  lora_alpha: 96                            # [What] 스케일링 팩터 (96/48 = 2.0)
  lora_dropout: 0.05                        # [What] LoRA 드롭아웃
  target_keywords: [gate_proj, up_proj, down_proj]  # [Where] FFN 타겟 키워드
  start_layer: 0                            # [Where] 시작 레이어
  num_layers: 0                             # [Where] 0 = 전체 레이어
  attn_lora:                                # [Where] 어텐션 LoRA
    enabled: true
    keywords: [q_proj, v_proj]

# ── 훈련 설정 ──
training:
  type: sft                                 # SFT (Supervised Fine-Tuning)
  phases:                                   # [When] 페이즈 스케줄
    - step: 0
      trainable: ["lora", "attn_lora"]      # 스텝 0부터 LoRA만 훈련
  lr: 1.0e-5                                # 학습률
  weight_decay: 0.01                        # 가중치 감쇠
  warmup_steps: 200                         # 학습률 워밍업 스텝
  max_train_steps: 5000                     # 최대 훈련 스텝
  batch_size: 4                             # 배치 크기
  grad_accum_steps: 4                       # 그래디언트 축적 스텝 (유효 배치 = 4*4 = 16)
  max_grad_norm: 1.0                        # 그래디언트 클리핑
  log_steps: 50                             # 로그 출력 간격
  save_steps: 1000                          # 체크포인트 저장 간격
  val_steps: 500                            # 검증 간격

5. 실행하기

기본 실행

eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
    --set data.format=raw \
    --set data.task=sft \
    --set data.path=data/sft_10k_raw.jsonl \
    --set data.max_length=512

설정 오버라이드

eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
    --set data.format=raw \
    --set data.task=sft \
    --set data.path=data/sft_10k_raw.jsonl \
    --set data.max_length=512 \
    --set training.lr=2e-5 \
    --set injection.lora_r=32 \
    --set training.max_train_steps=10000

설정 검증만

eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
    --validate-only

프리플라이트 검사

모델을 로드하고 인젝션을 적용한 뒤, 페이즈 그룹별 파라미터 수를 확인합니다. 훈련은 수행하지 않습니다.

eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
    --preflight

디버그 모드

eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
    --debug \
    --debug-trainable-names \
    --debug-every 10 \
    --set data.format=raw \
    --set data.task=sft \
    --set data.path=data/sft_10k_raw.jsonl \
    --set data.max_length=512

6. 체크포인트 저장 구조

훈련 완료 시 체크포인트에는 base weight + LoRA 파라미터가 저장됩니다.

체크포인트 구조:
├── layer.N.mlp.gate_proj.base_layer.weight   ← 원본 weight (freeze 상태)
├── layer.N.mlp.gate_proj.lora_A              ← LoRA 학습 파라미터
├── layer.N.mlp.gate_proj.lora_B              ← LoRA 학습 파라미터
├── layer.N.mlp.up_proj.base_layer.weight
├── layer.N.mlp.up_proj.lora_A
├── layer.N.mlp.up_proj.lora_B
├── ...
└── (attn_lora 활성화 시 q_proj, v_proj도 동일 패턴)

Bench 로딩

eulerforge bench에서 dense_lora 체크포인트를 로드하면:

  1. LoRA를 base에 병합: merged = base_w + (lora_B @ lora_A) * (alpha / r)
  2. 결과는 dense 모델 (LoRA 없는 표준 모델)
  3. 별도의 MoE 구조 없이 일반 HF 모델로 추론

7. 디버깅 및 트러블슈팅

증상 원인 해결
"No trainable parameters" target_keywords가 모델의 실제 레이어 이름과 불일치 --debug-trainable-names로 파라미터 이름 확인
"LoRA layers will act as Identity" lora_r: 0으로 설정됨 lora_r을 1 이상으로 설정
OOM (메모리 부족) 모델 크기 대비 VRAM 부족 model.load_precision.mode: int4 추가 (4bit QLoRA), batch_size 감소, lora_r 감소
"dense_lora typically has no router params" 경고 페이즈에 router 그룹 포함 trainable에서 router 제거

다음 단계