hotdogs's picture
Upload METHOD.md with huggingface_hub
4bc0977 verified
|
raw
history blame
9.81 kB

Weight-Diff SVD Extraction: Universal Method

วิธีสร้าง LoRA Adapter จาก Weight Difference ของสองโมเดล

เทคนิคนี้ใช้ได้กับ ทุก LLM architecture ที่มี adapter สองตัวเทรนจาก base เดียวกัน ไม่ต้องใช้ GPU, ไม่ต้องใช้ training data, ใช้เวลาแค่ 1-3 นาทีบน CPU

   โมเดล A (merged LoRA)          โมเดล B (merged LoRA)
         │                                │
         └──────────┬─────────────────────┘
                    │ W_B - W_A = Δ
                    ▼
              Truncated SVD (rank r)
                    │
                    ▼
         LoRA Adapter A→B (7 MB)

1. เงื่อนไขที่ใช้ได้ (Requirements)

✅ ใช้ได้เมื่อ:

  • ทั้งสองโมเดลใช้ base architecture และ base weights เดียวกัน (commit hash เดียวกัน)
  • ทั้งสองโมเดลเทรนด้วย LoRA + merge (ไม่ใช่ full fine-tune)
  • tensor names ตรงกันทั้งสองโมเดล
  • มี RAM พอโหลดทีละ 2 tensors (~2-4 GB)

❌ ใช้ไม่ได้เมื่อ:

  • สถาปัตยกรรมต่างกัน (คนละ base model)
  • Full fine-tune (delta อาจมี rank สูงเกิน r=16)
  • config.json / tokenizer ถูกเปลี่ยนระหว่าง fine-tune
  • VRAM/RAM น้อยกว่า 4 GB

2. ขั้นตอนทีละสเต็ป

Step 1: เลือกสองโมเดล

MODEL_A = "lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled"   # ต้นทาง
MODEL_B = "lordx64/Qwen3.6-35B-A3B-Kimi-K2.6-Reasoning-Distilled"         # ปลายทาง

กฎ: โมเดลทั้งสองต้องมี tensor names เหมือนกัน และ config.json เหมือนกัน

Step 2: เลือก target modules

เลือกเฉพาะ linear layers ที่ต้องการ extract:

TARGET_MODULES = ["q_proj", "k_proj", "v_proj", "o_proj"]  # attention only
# หรือ
TARGET_MODULES = ["q_proj", "k_proj", "v_proj", "o_proj", 
                  "gate_proj", "up_proj", "down_proj"]      # attention + MLP

⚠️ สำคัญ: ข้าม 3D tensors (เช่น MoE expert layers [256, 2048, 512]) — ต้องใช้ per-slice SVD ซึ่งซับซ้อนกว่า

Step 3: เลือก LoRA rank

RANK = 16      # standard: ดีสมดุลระหว่างขนาดและคุณภาพ
RANK = 8       # minimal: เล็กลง เร็วขึ้น แต่ reconstruction error สูงกว่า
RANK = 32      # high quality: ใหญ่ขึ้น 2x, error น้อยกว่า ~4%

ทดสอบ: ใช้ reconstruction error test เพื่อเลือก rank ที่เหมาะสม

Step 4: รัน extraction script

python3 extract_lora_diff.py \
    --model_a lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled \
    --model_b lordx64/Qwen3.6-35B-A3B-Kimi-K2.6-Reasoning-Distilled \
    --output ./my-lora-adapter \
    --rank 16 \
    --target_modules q_proj,k_proj,v_proj,o_proj

Step 5: ใช้ adapter

Python (PEFT):

from peft import PeftModel
from transformers import AutoModelForCausalLM

base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.6-35B-A3B")
model = PeftModel.from_pretrained(base, "./my-lora-adapter")
# model ตอนนี้เป็น style B แล้ว!

llama.cpp (GGUF):

# แปลงเป็น GGUF ก่อน
python3 llama.cpp/convert_lora_to_gguf.py ./my-lora-adapter

# ใช้ infer
llama-cli -m base-Q6_K.gguf --lora my-lora-adapter.gguf -p "prompt"

3. คณิตศาสตร์เบื้องหลัง

ให้  M_A = W_base + Δ_A    (โมเดล A = base + LoRA A)
    M_B = W_base + Δ_B    (โมเดล B = base + LoRA B)

ความต่าง:  D = M_B - M_A = Δ_B - Δ_A    (base หายไป เหลือแต่ delta)

SVD:       D ≈ U_r · Σ_r · V_r^T        (rank-r approximation)

LoRA:      A = √Σ_r · V_r^T              (lora_A)
           B = U_r · √Σ_r                (lora_B)

Forward:   h = W_0·x + B·A·x             (standard LoRA forward)

ทำไมถึงเวิร์ค:

  • ทั้ง A และ B เทรนด้วย LoRA rank=r → ผลต่างก็มี rank ≤ 2r
  • SVD ที่ rank=r สามารถ reconstruct delta ได้เกือบสมบูรณ์ (91-95% energy)
  • ไม่ต้องใช้ training เพราะเป็นการ "แยกองค์ประกอบ" ทางคณิตศาสตร์ล้วนๆ

4. ตัวอย่าง: ใช้กับโมเดลอื่น

Llama 3.1 8B — style transfer

# สมมติมีสองโมเดลที่เทรนจาก Llama-3.1-8B เดียวกัน
MODEL_A = "user/llama3.1-8b-formal-style"      # สไตล์ทางการ
MODEL_B = "user/llama3.1-8b-casual-style"       # สไตล์กันเอง

python3 extract_lora_diff.py \
    --model_a user/llama3.1-8b-formal-style \
    --model_b user/llama3.1-8b-casual-style \
    --output ./llama-formal-to-casual \
    --rank 16 \
    --target_modules q_proj,k_proj,v_proj,o_proj

Mistral 7B — domain adaptation

MODEL_A = "mistralai/Mistral-7B-Instruct-v0.3"           # general
MODEL_B = "user/Mistral-7B-medical-finetuned"            # medical domain

python3 extract_lora_diff.py \
    --model_a mistralai/Mistral-7B-Instruct-v0.3 \
    --model_b user/Mistral-7B-medical-finetuned \
    --output ./mistral-medical-lora \
    --rank 16 \
    --target_modules q_proj,k_proj,v_proj,o_proj,gate_proj,up_proj,down_proj

Qwen2.5 72B — safety unlearning

# สกัด refusal delta ระหว่างรุ่นปลอดภัยกับรุ่นดิบ
MODEL_A = "Qwen/Qwen2.5-72B-Instruct"                   # มี safety
MODEL_B = "user/Qwen2.5-72B-uncensored"                 # ไม่มี safety

python3 extract_lora_diff.py \
    --model_a Qwen/Qwen2.5-72B-Instruct \
    --model_b user/Qwen2.5-72B-uncensored \
    --output ./qwen-safety-removal-lora \
    --rank 16

5. ปรับแต่ง Parameters

Parameter Default คำอธิบาย
--rank 16 LoRA rank. สูง = ใหญ่ + คุณภาพดี. ต่ำ = เล็ก + เร็ว
--target_modules q,k,v,o_proj modules ที่จะ extract. เพิ่ม gate/up/down ได้
--alpha 32 LoRA alpha (scaling factor). มักตั้งเป็น 2× rank
--skip_3d True ข้าม 3D tensors อัตโนมัติ (MoE experts)
--output_format peft peft หรือ gguf หรือ both

6. Troubleshooting

ปัญหา สาเหตุ วิธีแก้
KeyError: tensor name mismatch โมเดลคนละ base ใช้โมเดลที่เทรนจาก base เดียวกัน
CUDA out of memory โหลดทั้งโมเดล ใช้ tensor-by-tensor mode (default)
ValueError: non contiguous tensor SVD output ไม่ contiguous .contiguous() ก่อน save
GGUF conversion failed tensor names ไม่ตรง PEFT ใช้ .lora_A.default, GGUF ใช้ .lora_A.weight — ต้อง rename
Rank too high for tensor tensor มิติเล็กกว่า rank ลด rank หรือข้าม tensor นั้น

7. ข้อจำกัด

  1. Attention-only bias: การใช้เฉพาะ attention layers อาจพลาดการเปลี่ยนแปลงใน FFN/MLP layers
  2. Low-rank assumption: ใช้ได้ดีกับ LoRA-merged models แต่ full fine-tune อาจมี delta rank สูงกว่านี้
  3. No quality guarantee: ตัว adapter เป็น mathematical reconstruction — ไม่มีการการันตีว่าคุณภาพเทียบเท่ากับการเทรนตรงๆ
  4. Single-style transfer: สกัดได้เฉพาะความต่างระหว่าง 2 สไตล์ — ถ้าอยากเปลี่ยนระหว่าง 3+ สไตล์ ต้องทำ adapter หลายอัน

8. สคริปต์ Extraction

# extract_lora_diff.py — 193 lines
# ดาวน์โหลดได้จาก HuggingFace repo:
# https://huggingface.co/hotdogs/qwen3.6-35b-opus-to-kimi-lora

9. อ้างอิง & Credit