File size: 9,811 Bytes
4bc0977
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# 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: เลือกสองโมเดล

```python
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:

```python
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

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

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

### Step 4: รัน extraction script

```bash
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):**
```python
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):**
```bash
# แปลงเป็น 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

```bash
# สมมติมีสองโมเดลที่เทรนจาก 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

```bash
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

```bash
# สกัด 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

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

---

## 9. อ้างอิง & Credit

- **เทคนิค:** UKA (Hermes Agent, Nous Research) & hotdogs
- **Paper:** [Weight-Diff SVD Extraction: Zero-Shot LoRA Adapter Synthesis](https://huggingface.co/hotdogs/qwen3.6-35b-opus-to-kimi-lora/blob/main/paper.pdf)
- **Code + Adapter:** https://huggingface.co/hotdogs/qwen3.6-35b-opus-to-kimi-lora
- **LoRA paper:** Hu et al., 2021 (arXiv:2106.09685)
- **QLoRA paper:** Dettmers et al., 2023 (arXiv:2305.14314)