Upload 33 files
Browse files- README.md +101 -3
- conf/config.yaml +12 -0
- conf/init/default.yaml +7 -0
- conf/init/gradient.yaml +8 -0
- conf/init/kaiming.yaml +5 -0
- conf/init/qr.yaml +2 -0
- conf/init/svd.yaml +5 -0
- conf/model/llama.yaml +11 -0
- conf/model/llama3.yaml +11 -0
- conf/model/t5base.yaml +11 -0
- conf/model/t5large.yaml +11 -0
- conf/model/t5small.yaml +11 -0
- conf/model/t5xl.yaml +11 -0
- conf/model/tinyllama.yaml +11 -0
- conf/peft/adalora.yaml +10 -0
- conf/peft/all.yaml +11 -0
- conf/peft/all_w_emb.yaml +9 -0
- conf/peft/att.yaml +11 -0
- conf/peft/dora.yaml +10 -0
- conf/peft/full_ft.yaml +8 -0
- conf/peft/qv.yaml +9 -0
- conf/peft/qv_w_emb.yaml +9 -0
- data.py +488 -0
- eval_gsm8k.py +58 -0
- eval_humaneval.py +88 -0
- logTrainer.py +238 -0
- lora_plus.py +210 -0
- peft.zip +3 -0
- requirements.txt +149 -0
- run.sh +1 -0
- run_exp.py +705 -0
- split.py +136 -0
- utils.py +427 -0
README.md
CHANGED
|
@@ -1,3 +1,101 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CDKA: Component Designed Kronecker Adapters
|
| 2 |
+
|
| 3 |
+
Official PyTorch implementation of **Diving into Kronecker Adapters: Component Design Matters**.
|
| 4 |
+
|
| 5 |
+
CDKA is a parameter-efficient fine-tuning framework for large-scale models. It studies how the component design of Kronecker adapters affects adapter capacity and downstream performance. In particular, CDKA exposes the component dimensions and the number of Kronecker components as controllable hyperparameters:
|
| 6 |
+
|
| 7 |
+
$$
|
| 8 |
+
\Delta W = \sum_{i=1}^{r} B^{(i)} \otimes A^{(i)},
|
| 9 |
+
$$
|
| 10 |
+
|
| 11 |
+
where `r1`, `r2`, and `r` determine the shape and number of Kronecker components.
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
## Installation
|
| 15 |
+
|
| 16 |
+
### 1. Clone the repository
|
| 17 |
+
|
| 18 |
+
```bash
|
| 19 |
+
git clone https://github.com/rainstonee/CDKA.git
|
| 20 |
+
cd CDKA
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
### 2. Create a Python environment
|
| 24 |
+
|
| 25 |
+
```bash
|
| 26 |
+
conda create -n cdka python=3.10 -y
|
| 27 |
+
conda activate cdka
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
### 3. Install dependencies
|
| 31 |
+
|
| 32 |
+
```bash
|
| 33 |
+
pip install --upgrade pip
|
| 34 |
+
pip install -r requirements.txt
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
### 4. Install the modified PEFT package
|
| 38 |
+
|
| 39 |
+
This repository includes a modified PEFT implementation in `peft.zip`. The custom PEFT version is required because CDKA extends the standard LoRA configuration with Kronecker-adapter-specific arguments such as `r1`, `r2`, and `r`.
|
| 40 |
+
|
| 41 |
+
```bash
|
| 42 |
+
unzip peft.zip
|
| 43 |
+
pip install -e peft
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
## Training with CDKA
|
| 47 |
+
|
| 48 |
+
Run the example script:
|
| 49 |
+
|
| 50 |
+
```bash
|
| 51 |
+
bash run.sh
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
The default example runs the Llama-2-7B model on `meta_math` dataset with PEFT enabled and Kronecker adapter hyperparameters specified through Hydra overrides.
|
| 55 |
+
|
| 56 |
+
The script is equivalent to:
|
| 57 |
+
|
| 58 |
+
```bash
|
| 59 |
+
CUDA_VISIBLE_DEVICES=0 python run_exp.py \
|
| 60 |
+
+model=llama \
|
| 61 |
+
+peft=all \
|
| 62 |
+
+init=default \
|
| 63 |
+
+dataset_name=meta_math \
|
| 64 |
+
+seed=333 \
|
| 65 |
+
++peft.lora_r1=2 \
|
| 66 |
+
++peft.lora_r2=2 \
|
| 67 |
+
++peft.lora_r=8 \
|
| 68 |
+
++peft.lora_alpha=64
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
### Recommended default component configuration
|
| 72 |
+
|
| 73 |
+
For most CDKA experiments, we recommend starting with the following default component configuration:
|
| 74 |
+
|
| 75 |
+
```bash
|
| 76 |
+
++peft.lora_r1=2 \
|
| 77 |
+
++peft.lora_r2=8 \
|
| 78 |
+
++peft.lora_r=4 \
|
| 79 |
+
++peft.lora_alpha=64
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
This setting follows the main component-design principle of CDKA: use a small `r1`, a large `r2`, and a moderate number of Kronecker components `r`. In practice, this provides a balanced default configuration before task-specific tuning.
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
## Citation
|
| 86 |
+
|
| 87 |
+
If you find this repository useful, please cite:
|
| 88 |
+
|
| 89 |
+
```bibtex
|
| 90 |
+
@article{bai2026diving,
|
| 91 |
+
title={Diving into Kronecker Adapters: Component Design Matters},
|
| 92 |
+
author={Bai, Jiayu and Yu, Danchen and Liao, Zhenyu and Hou, TianQi and Zhou, Feng and Qiu, Robert C and Ling, Zenan},
|
| 93 |
+
journal={arXiv preprint arXiv:2602.01267},
|
| 94 |
+
year={2026}
|
| 95 |
+
}
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
## Acknowledgement
|
| 99 |
+
|
| 100 |
+
This codebase is built on [LoRA-GA](https://github.com/Outsider565/LoRA-GA). We thank the authors of LoRA-GA for releasing their implementation.
|
| 101 |
+
|
conf/config.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- _self_
|
| 3 |
+
# - model: llama
|
| 4 |
+
dry_run: False
|
| 5 |
+
wandb:
|
| 6 |
+
project: "glue_new"
|
| 7 |
+
name: null
|
| 8 |
+
hydra:
|
| 9 |
+
sweeper:
|
| 10 |
+
params:
|
| 11 |
+
++dataset_name: mnli
|
| 12 |
+
++seed: 0
|
conf/init/default.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mode: simple
|
| 2 |
+
lora_A: kaiming
|
| 3 |
+
lora_B: zeros
|
| 4 |
+
# lora_A: zeros
|
| 5 |
+
# lora_B: kaiming
|
| 6 |
+
# This is the default way to initialize the model parameters.
|
| 7 |
+
dtype: fp32
|
conf/init/gradient.yaml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mode: gradient
|
| 2 |
+
bsz: 1
|
| 3 |
+
iters: 8
|
| 4 |
+
direction: ArBr
|
| 5 |
+
max_length: 1024
|
| 6 |
+
dtype: fp32
|
| 7 |
+
scale: stable
|
| 8 |
+
stable_gamma: 16
|
conf/init/kaiming.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mode: simple
|
| 2 |
+
lora_A: kaiming
|
| 3 |
+
lora_B: kaiming
|
| 4 |
+
dtype: fp32
|
| 5 |
+
stable_gamma: 16
|
conf/init/qr.yaml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mode: qr
|
| 2 |
+
dtype: fp32
|
conf/init/svd.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mode: svd
|
| 2 |
+
weight: default
|
| 3 |
+
dtype: fp32
|
| 4 |
+
stable_gamma: 16
|
| 5 |
+
scale: default
|
conf/model/llama.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: llama/llama-2-7b-hf
|
| 2 |
+
type: CausalLM
|
| 3 |
+
epochs: 1
|
| 4 |
+
per_device_batch_size: 1
|
| 5 |
+
real_batch_size: 32
|
| 6 |
+
bf16: True
|
| 7 |
+
eval_epochs: 1
|
| 8 |
+
early_stopping_patience: 3
|
| 9 |
+
max_length: 1024
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 2e-4
|
conf/model/llama3.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: llama/llama-3.1-8b-hf
|
| 2 |
+
type: CausalLM
|
| 3 |
+
epochs: 1
|
| 4 |
+
per_device_batch_size: 1
|
| 5 |
+
real_batch_size: 64
|
| 6 |
+
bf16: True
|
| 7 |
+
eval_epochs: 1
|
| 8 |
+
early_stopping_patience: 3
|
| 9 |
+
max_length: 1024
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 2e-4
|
conf/model/t5base.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: t5-base
|
| 2 |
+
type: ConditionalGeneration
|
| 3 |
+
epochs: 1
|
| 4 |
+
per_device_batch_size: 32
|
| 5 |
+
real_batch_size: 32
|
| 6 |
+
bf16: False
|
| 7 |
+
eval_epochs: 1
|
| 8 |
+
early_stopping_patience: 5
|
| 9 |
+
max_length: 128
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 2e-3
|
conf/model/t5large.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: t5-large
|
| 2 |
+
type: ConditionalGeneration
|
| 3 |
+
epochs: 1
|
| 4 |
+
per_device_batch_size: 32
|
| 5 |
+
real_batch_size: 1
|
| 6 |
+
bf16: True
|
| 7 |
+
eval_epochs: 0.1
|
| 8 |
+
early_stopping_patience: 3
|
| 9 |
+
max_length: 128
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 5e-5
|
conf/model/t5small.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: t5-small
|
| 2 |
+
type: ConditionalGeneration
|
| 3 |
+
epochs: 1
|
| 4 |
+
per_device_batch_size: 32
|
| 5 |
+
real_batch_size: 32
|
| 6 |
+
bf16: True
|
| 7 |
+
eval_epochs: 0.1
|
| 8 |
+
early_stopping_patience: 3
|
| 9 |
+
max_length: 128
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 5e-5
|
conf/model/t5xl.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: google/flan-t5-xl
|
| 2 |
+
type: ConditionalGeneration
|
| 3 |
+
epochs: 5
|
| 4 |
+
per_device_batch_size: 1
|
| 5 |
+
real_batch_size: 32
|
| 6 |
+
bf16: True
|
| 7 |
+
eval_epochs: 1
|
| 8 |
+
early_stopping_patience: 3
|
| 9 |
+
max_length: 512
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 5e-5
|
conf/model/tinyllama.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T
|
| 2 |
+
type: CausalLM
|
| 3 |
+
epochs: 1
|
| 4 |
+
per_device_batch_size: 1
|
| 5 |
+
real_batch_size: 32
|
| 6 |
+
bf16: True
|
| 7 |
+
eval_epochs: 1
|
| 8 |
+
early_stopping_patience: 3
|
| 9 |
+
max_length: 512
|
| 10 |
+
logging_steps: 1
|
| 11 |
+
learning_rate: 1e-5
|
conf/peft/adalora.yaml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r: null
|
| 3 |
+
lora_relative_r: null
|
| 4 |
+
lora_target_modules: all
|
| 5 |
+
train_embeddings: false
|
| 6 |
+
use_rslora: false
|
| 7 |
+
use_loraplus: false
|
| 8 |
+
loraplus_lr_ratio: 16
|
| 9 |
+
lora_alpha: 16
|
| 10 |
+
adalora: true
|
conf/peft/all.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r1: null
|
| 3 |
+
lora_r2: null
|
| 4 |
+
lora_r: null
|
| 5 |
+
lora_relative_r: null
|
| 6 |
+
lora_target_modules: all
|
| 7 |
+
train_embeddings: false
|
| 8 |
+
use_rslora: True
|
| 9 |
+
use_loraplus: false
|
| 10 |
+
loraplus_lr_ratio: 16
|
| 11 |
+
lora_alpha: 64
|
conf/peft/all_w_emb.yaml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r: null
|
| 3 |
+
lora_relative_r: null
|
| 4 |
+
lora_target_modules: all
|
| 5 |
+
train_embeddings: true
|
| 6 |
+
use_rslora: false
|
| 7 |
+
use_loraplus: false
|
| 8 |
+
loraplus_lr_ratio: 16
|
| 9 |
+
lora_alpha: 16
|
conf/peft/att.yaml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r1: null
|
| 3 |
+
lora_r2: null
|
| 4 |
+
lora_r: null
|
| 5 |
+
lora_relative_r: null
|
| 6 |
+
lora_target_modules: [q_proj,k_proj,v_proj,o_proj]
|
| 7 |
+
train_embeddings: false
|
| 8 |
+
use_rslora: True
|
| 9 |
+
use_loraplus: false
|
| 10 |
+
loraplus_lr_ratio: 16
|
| 11 |
+
lora_alpha: 64
|
conf/peft/dora.yaml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r: null
|
| 3 |
+
lora_relative_r: null
|
| 4 |
+
lora_target_modules: all
|
| 5 |
+
train_embeddings: false
|
| 6 |
+
use_rslora: false
|
| 7 |
+
use_loraplus: false
|
| 8 |
+
loraplus_lr_ratio: 16
|
| 9 |
+
lora_alpha: 16
|
| 10 |
+
dora: true
|
conf/peft/full_ft.yaml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: false
|
| 2 |
+
lora_r: null
|
| 3 |
+
lora_relative_r: null
|
| 4 |
+
lora_target_modules: null
|
| 5 |
+
train_embeddings: false
|
| 6 |
+
use_rslora: false
|
| 7 |
+
use_loraplus: false
|
| 8 |
+
loraplus_lr_ratio: 16
|
conf/peft/qv.yaml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r: null
|
| 3 |
+
lora_relative_r: null
|
| 4 |
+
lora_target_modules: [q,v]
|
| 5 |
+
train_embeddings: false
|
| 6 |
+
use_rslora: false
|
| 7 |
+
use_loraplus: false
|
| 8 |
+
loraplus_lr_ratio: 16
|
| 9 |
+
lora_alpha: 16
|
conf/peft/qv_w_emb.yaml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use_peft: true
|
| 2 |
+
lora_r: null
|
| 3 |
+
lora_relative_r: null
|
| 4 |
+
lora_target_modules: [q,v]
|
| 5 |
+
train_embeddings: true
|
| 6 |
+
use_rslora: false
|
| 7 |
+
use_loraplus: false
|
| 8 |
+
loraplus_lr_ratio: 16
|
| 9 |
+
lora_alpha: 16
|
data.py
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datasets import load_dataset, Dataset
|
| 2 |
+
import typing as tp
|
| 3 |
+
import functools
|
| 4 |
+
import os
|
| 5 |
+
import pickle
|
| 6 |
+
import logging
|
| 7 |
+
import datasets
|
| 8 |
+
|
| 9 |
+
log = logging.getLogger(__name__)
|
| 10 |
+
|
| 11 |
+
def cache_to_disk(root_datadir):
|
| 12 |
+
def decorator_cache(func):
|
| 13 |
+
@functools.wraps(func)
|
| 14 |
+
def wrapper_cache(*args, **kwargs):
|
| 15 |
+
if not os.path.exists(root_datadir):
|
| 16 |
+
os.makedirs(root_datadir)
|
| 17 |
+
|
| 18 |
+
func_name = func.__name__.replace("/", "")
|
| 19 |
+
cache_file = os.path.join(root_datadir, f"{func_name}.pkl")
|
| 20 |
+
if os.path.exists(cache_file):
|
| 21 |
+
with open(cache_file, "rb") as f:
|
| 22 |
+
log.info(f"Loading cached data for {func.__name__}")
|
| 23 |
+
return pickle.load(f)
|
| 24 |
+
|
| 25 |
+
result = func(*args, **kwargs)
|
| 26 |
+
with open(cache_file, "wb") as f:
|
| 27 |
+
pickle.dump(result, f)
|
| 28 |
+
log.info(f"Cached data for {func.__name__}")
|
| 29 |
+
return result
|
| 30 |
+
|
| 31 |
+
return wrapper_cache
|
| 32 |
+
|
| 33 |
+
return decorator_cache
|
| 34 |
+
|
| 35 |
+
@cache_to_disk("data_cache")
|
| 36 |
+
def load_emo():
|
| 37 |
+
dataset = load_dataset("emo")
|
| 38 |
+
label_map = {0: "others", 1: "happy", 2: "sad", 3: "angry"}
|
| 39 |
+
instruction = "classify the emotion of the text: "
|
| 40 |
+
dataset = dataset.map(
|
| 41 |
+
lambda e: {
|
| 42 |
+
"x": f'{instruction}{e["text"]}\nresult: ',
|
| 43 |
+
"y": label_map[e["label"]],
|
| 44 |
+
}
|
| 45 |
+
)
|
| 46 |
+
train_set = dataset["train"]
|
| 47 |
+
test_set = dataset["test"]
|
| 48 |
+
return train_set, test_set, test_set
|
| 49 |
+
|
| 50 |
+
@cache_to_disk("data_cache")
|
| 51 |
+
def load_sst2():
|
| 52 |
+
dataset = load_dataset("glue", "sst2")
|
| 53 |
+
instruction = "classify the sentiment of the text: "
|
| 54 |
+
label_map = {0: "negative", 1: "positive", -1: "other"}
|
| 55 |
+
dataset = dataset.map(
|
| 56 |
+
lambda e: {
|
| 57 |
+
"x": f'{instruction}{e["sentence"]}\nresult: ',
|
| 58 |
+
"y": label_map[e["label"]],
|
| 59 |
+
}
|
| 60 |
+
)
|
| 61 |
+
train_set = dataset["train"]
|
| 62 |
+
validation_set = dataset["validation"]
|
| 63 |
+
return train_set, validation_set, validation_set
|
| 64 |
+
|
| 65 |
+
@cache_to_disk("data_cache")
|
| 66 |
+
def load_cola():
|
| 67 |
+
dataset = load_dataset("glue", "cola")
|
| 68 |
+
instruction = "classify the grammaticality of the text: "
|
| 69 |
+
label_map = {0: "unacceptable", 1: "acceptable", -1: "other"}
|
| 70 |
+
dataset = dataset.map(
|
| 71 |
+
lambda e: {
|
| 72 |
+
"x": f'{instruction}{e["sentence"]}\nresult: ',
|
| 73 |
+
"y": label_map[e["label"]],
|
| 74 |
+
}
|
| 75 |
+
)
|
| 76 |
+
train_set = dataset["train"]
|
| 77 |
+
validation_set = dataset["validation"]
|
| 78 |
+
return train_set, validation_set, validation_set
|
| 79 |
+
|
| 80 |
+
@cache_to_disk("data_cache")
|
| 81 |
+
def load_qqp():
|
| 82 |
+
dataset = load_dataset("glue", "qqp")
|
| 83 |
+
instruction = "classify the semantic similarity of the text: "
|
| 84 |
+
label_map = {0: "different", 1: "duplicate", -1: "other"}
|
| 85 |
+
dataset = dataset.map(
|
| 86 |
+
lambda e: {
|
| 87 |
+
"x": f'{instruction}{e["question1"]}\n{e["question2"]}\nresult: ',
|
| 88 |
+
"y": label_map[e["label"]],
|
| 89 |
+
}
|
| 90 |
+
)
|
| 91 |
+
train_set = dataset["train"]
|
| 92 |
+
validation_set = dataset["validation"]
|
| 93 |
+
return train_set, validation_set, validation_set
|
| 94 |
+
|
| 95 |
+
@cache_to_disk("data_cache")
|
| 96 |
+
def load_mrpc():
|
| 97 |
+
dataset = load_dataset("glue", "mrpc")
|
| 98 |
+
instruction = "classify the semantic similarity of the text: "
|
| 99 |
+
label_map = {0: "different", 1: "equivalent", -1: "other"}
|
| 100 |
+
dataset = dataset.map(
|
| 101 |
+
lambda e: {
|
| 102 |
+
"x": f'{instruction}{e["sentence1"]}\n{e["sentence2"]}\nresult: ',
|
| 103 |
+
"y": label_map[e["label"]],
|
| 104 |
+
}
|
| 105 |
+
)
|
| 106 |
+
train_set = dataset["train"]
|
| 107 |
+
validation_set = dataset["validation"]
|
| 108 |
+
return train_set, validation_set, validation_set
|
| 109 |
+
|
| 110 |
+
@cache_to_disk("data_cache")
|
| 111 |
+
def load_mnli():
|
| 112 |
+
dataset = load_dataset("glue", "mnli",download_mode="force_redownload")
|
| 113 |
+
instruction = "classify the semantic similarity of the text: "
|
| 114 |
+
label_map = {0: "entailment", 1: "neutral", 2: "contradiction", -1: "other"}
|
| 115 |
+
dataset = dataset.map(
|
| 116 |
+
lambda e: {
|
| 117 |
+
"x": f'{instruction}{e["premise"]}\n{e["hypothesis"]}\nresult: ',
|
| 118 |
+
"y": label_map[e["label"]],
|
| 119 |
+
}
|
| 120 |
+
)
|
| 121 |
+
train_set = dataset["train"]
|
| 122 |
+
validation_set = dataset["validation_matched"]
|
| 123 |
+
return train_set, validation_set, validation_set
|
| 124 |
+
|
| 125 |
+
@cache_to_disk("data_cache")
|
| 126 |
+
def load_squad():
|
| 127 |
+
dataset = load_dataset("rajpurkar/squad")
|
| 128 |
+
instruction = "answer the question: "
|
| 129 |
+
dataset = dataset.map(
|
| 130 |
+
lambda e: {
|
| 131 |
+
"x": f'{instruction}{e["question"]}\ncontext: {e["context"]}\nresult: ',
|
| 132 |
+
"y": ", ".join(e["answers"]["text"]),
|
| 133 |
+
}
|
| 134 |
+
)
|
| 135 |
+
train_set = dataset["train"]
|
| 136 |
+
validation_set = dataset["validation"]
|
| 137 |
+
return train_set, validation_set, validation_set
|
| 138 |
+
|
| 139 |
+
@cache_to_disk("data_cache")
|
| 140 |
+
def load_qnli():
|
| 141 |
+
dataset = load_dataset("glue", "qnli")
|
| 142 |
+
instruction = "classify the semantic similarity of the question and the sentence: "
|
| 143 |
+
label_map = {0: "entailment", 1: "not_entailment", -1: "other"}
|
| 144 |
+
dataset = dataset.map(
|
| 145 |
+
lambda e: {
|
| 146 |
+
"x": f'{instruction}{e["question"]}\n{e["sentence"]}\nresult: ',
|
| 147 |
+
"y": label_map[e["label"]],
|
| 148 |
+
}
|
| 149 |
+
)
|
| 150 |
+
train_set = dataset["train"]
|
| 151 |
+
validation_set = dataset["validation"]
|
| 152 |
+
test_set = dataset["test"]
|
| 153 |
+
return train_set, validation_set, test_set
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
template_with_input = '''### Instruction:
|
| 157 |
+
{instruction}
|
| 158 |
+
|
| 159 |
+
### Input:
|
| 160 |
+
{input}
|
| 161 |
+
|
| 162 |
+
### Response:
|
| 163 |
+
'''
|
| 164 |
+
|
| 165 |
+
template_wo_input = '''Below is an instruction that describes a task. Write a response that appropriately completes the request.
|
| 166 |
+
|
| 167 |
+
### Instruction:
|
| 168 |
+
{instruction}
|
| 169 |
+
|
| 170 |
+
### Response:
|
| 171 |
+
'''
|
| 172 |
+
|
| 173 |
+
@cache_to_disk("data_cache")
|
| 174 |
+
def load_alpaca():
|
| 175 |
+
dataset = load_dataset("tatsu-lab/alpaca")
|
| 176 |
+
def alpaca_preprocess(instruction, input, output):
|
| 177 |
+
if input == "":
|
| 178 |
+
x = template_wo_input.format(instruction=instruction)
|
| 179 |
+
else:
|
| 180 |
+
x = template_with_input.format(instruction=instruction, input=input)
|
| 181 |
+
return {"x": x, "y": output}
|
| 182 |
+
dataset = dataset.map(
|
| 183 |
+
lambda e: alpaca_preprocess(e["instruction"], e["input"], e["output"])
|
| 184 |
+
)
|
| 185 |
+
# we sample 10% of the training set as validation set
|
| 186 |
+
train_set = dataset["train"].train_test_split(test_size=0.1)['train']
|
| 187 |
+
validation_set = dataset["train"].train_test_split(test_size=0.1)['test']
|
| 188 |
+
return train_set, validation_set, validation_set
|
| 189 |
+
|
| 190 |
+
@cache_to_disk("data_cache")
|
| 191 |
+
def load_gsm8k():
|
| 192 |
+
dataset = load_dataset("gsm8k", "main")
|
| 193 |
+
#x = "Q: " + x[0] + "\n" + "A:"
|
| 194 |
+
dataset = dataset.map(
|
| 195 |
+
lambda e: {
|
| 196 |
+
"x": f'Q: {e["question"]}\nA: ',
|
| 197 |
+
"y": e["answer"],
|
| 198 |
+
}
|
| 199 |
+
)
|
| 200 |
+
train_set = dataset["train"]
|
| 201 |
+
validation_set = dataset["test"]
|
| 202 |
+
return train_set, validation_set, validation_set
|
| 203 |
+
|
| 204 |
+
@cache_to_disk("data_cache")
|
| 205 |
+
def load_alpaca_gpt4():
|
| 206 |
+
dataset = load_dataset("tatsu-lab/alpaca")
|
| 207 |
+
def alpaca_preprocess(instruction, input, output):
|
| 208 |
+
if input == "":
|
| 209 |
+
x = template_wo_input.format(instruction=instruction)
|
| 210 |
+
else:
|
| 211 |
+
x = template_with_input.format(instruction=instruction, input=input)
|
| 212 |
+
return {"x": x, "y": output}
|
| 213 |
+
dataset = dataset.map(
|
| 214 |
+
lambda e: alpaca_preprocess(e["instruction"], e["input"], e["output"])
|
| 215 |
+
)
|
| 216 |
+
# we sample 10% of the training set as validation set
|
| 217 |
+
train_set = dataset["train"].train_test_split(test_size=0.1)['train']
|
| 218 |
+
validation_set = dataset["train"].train_test_split(test_size=0.1)['test']
|
| 219 |
+
return train_set, validation_set, validation_set
|
| 220 |
+
|
| 221 |
+
@cache_to_disk("data_cache")
|
| 222 |
+
def load_flan():
|
| 223 |
+
dataset = load_dataset("Muennighoff/flan", split='train', streaming=True)
|
| 224 |
+
def preprocess(data):
|
| 225 |
+
return {
|
| 226 |
+
"x": template_wo_input.format(instruction=data['inputs']),
|
| 227 |
+
"y": data['targets'],
|
| 228 |
+
}
|
| 229 |
+
train_samples = []
|
| 230 |
+
eval_samples = []
|
| 231 |
+
count = 0
|
| 232 |
+
dataset.shuffle(buffer_size=5000, seed=42)
|
| 233 |
+
from tqdm import tqdm
|
| 234 |
+
for sample in tqdm(dataset, total=110000):
|
| 235 |
+
processed_sample = preprocess(sample)
|
| 236 |
+
if count < 100000: # First 100,000 samples for training
|
| 237 |
+
train_samples.append(processed_sample)
|
| 238 |
+
elif 100000 <= count < 110000: # Next 10,000 samples for evaluation
|
| 239 |
+
eval_samples.append(processed_sample)
|
| 240 |
+
elif count >= 110000: # Stop processing after collecting enough samples
|
| 241 |
+
break
|
| 242 |
+
count += 1
|
| 243 |
+
# convert to hf dataset
|
| 244 |
+
train_set = Dataset.from_list(train_samples)
|
| 245 |
+
eval_set = Dataset.from_list(eval_samples)
|
| 246 |
+
return train_set, eval_set, eval_set
|
| 247 |
+
|
| 248 |
+
@cache_to_disk("data_cache")
|
| 249 |
+
def load_meta_math(max_tokens=512):
|
| 250 |
+
dataset = load_dataset("meta-math/MetaMathQA", split='train')
|
| 251 |
+
from transformers import AutoTokenizer
|
| 252 |
+
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
|
| 253 |
+
def preprocess(data):
|
| 254 |
+
return {
|
| 255 |
+
"x": f'Q: {data["query"]}\nA: ',
|
| 256 |
+
"y": data["response"].split("\nThe answer is:")[0]
|
| 257 |
+
}
|
| 258 |
+
train_samples = []
|
| 259 |
+
eval_samples = []
|
| 260 |
+
count = 0
|
| 261 |
+
dataset.shuffle(seed=42)
|
| 262 |
+
from tqdm import tqdm
|
| 263 |
+
bar = tqdm(dataset, total=110000)
|
| 264 |
+
total = 0
|
| 265 |
+
ok = 0
|
| 266 |
+
for sample in dataset:
|
| 267 |
+
total += 1
|
| 268 |
+
temp = preprocess(sample)
|
| 269 |
+
if len(tokenizer(temp['x']+' '+temp['y'])['input_ids']) >= max_tokens or "GSM" not in sample["type"]:
|
| 270 |
+
continue
|
| 271 |
+
bar.update(1)
|
| 272 |
+
bar.set_description(f"ok: {ok}/{total}")
|
| 273 |
+
ok += 1
|
| 274 |
+
processed_sample = preprocess(sample)
|
| 275 |
+
if count < 100000: # First 100,000 samples for training
|
| 276 |
+
train_samples.append(processed_sample)
|
| 277 |
+
elif 100000 <= count < 110000: # Next 10,000 samples for evaluation
|
| 278 |
+
eval_samples.append(processed_sample)
|
| 279 |
+
elif count >= 110000: # Stop processing after collecting enough samples
|
| 280 |
+
break
|
| 281 |
+
count += 1
|
| 282 |
+
# convert to hf dataset
|
| 283 |
+
train_set = Dataset.from_list(train_samples)
|
| 284 |
+
eval_set = Dataset.from_list(eval_samples)
|
| 285 |
+
return train_set, eval_set, eval_set
|
| 286 |
+
|
| 287 |
+
@cache_to_disk("data_cache")
|
| 288 |
+
def load_flan_v2(max_tokens=512):
|
| 289 |
+
dataset = load_dataset("SirNeural/flan_v2", split='train', streaming=True)
|
| 290 |
+
from transformers import AutoTokenizer
|
| 291 |
+
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
|
| 292 |
+
def preprocess(data):
|
| 293 |
+
return {
|
| 294 |
+
"x": data['inputs'],
|
| 295 |
+
"y": data['targets'],
|
| 296 |
+
}
|
| 297 |
+
train_samples = []
|
| 298 |
+
eval_samples = []
|
| 299 |
+
count = 0
|
| 300 |
+
dataset.shuffle(buffer_size=5000, seed=42)
|
| 301 |
+
from tqdm import tqdm
|
| 302 |
+
bar = tqdm(dataset, total=110000)
|
| 303 |
+
total = 0
|
| 304 |
+
ok = 0
|
| 305 |
+
for sample in dataset:
|
| 306 |
+
total += 1
|
| 307 |
+
temp = preprocess(sample)
|
| 308 |
+
if len(tokenizer(temp['x']+' '+temp['y'])['input_ids']) >= max_tokens:
|
| 309 |
+
continue
|
| 310 |
+
bar.update(1)
|
| 311 |
+
bar.set_description(f"ok: {ok}/{total}")
|
| 312 |
+
ok += 1
|
| 313 |
+
processed_sample = preprocess(sample)
|
| 314 |
+
if count < 100000: # First 100,000 samples for training
|
| 315 |
+
train_samples.append(processed_sample)
|
| 316 |
+
elif 100000 <= count < 110000: # Next 10,000 samples for evaluation
|
| 317 |
+
eval_samples.append(processed_sample)
|
| 318 |
+
elif count >= 110000: # Stop processing after collecting enough samples
|
| 319 |
+
break
|
| 320 |
+
count += 1
|
| 321 |
+
# convert to hf dataset
|
| 322 |
+
train_set = Dataset.from_list(train_samples)
|
| 323 |
+
eval_set = Dataset.from_list(eval_samples)
|
| 324 |
+
return train_set, eval_set, eval_set
|
| 325 |
+
|
| 326 |
+
@cache_to_disk("data_cache")
|
| 327 |
+
def load_codefeedback(max_tokens=1024):
|
| 328 |
+
dataset = load_dataset("m-a-p/CodeFeedback-Filtered-Instruction", split='train')
|
| 329 |
+
from transformers import AutoTokenizer
|
| 330 |
+
tokenizer = AutoTokenizer.from_pretrained("llama/llama-2-7b-hf")
|
| 331 |
+
def preprocess(data):
|
| 332 |
+
y = data['answer']
|
| 333 |
+
y = "```".join(y.split("```")[:2]) + "```" # only keep the first code block
|
| 334 |
+
return {
|
| 335 |
+
"x": template_wo_input.format(
|
| 336 |
+
instruction=data['query']
|
| 337 |
+
),
|
| 338 |
+
"y": y,
|
| 339 |
+
}
|
| 340 |
+
train_samples = []
|
| 341 |
+
eval_samples = []
|
| 342 |
+
count = 0
|
| 343 |
+
dataset.shuffle(seed=42)
|
| 344 |
+
from tqdm import tqdm
|
| 345 |
+
bar = tqdm(dataset, total=110000)
|
| 346 |
+
total = 0
|
| 347 |
+
ok = 0
|
| 348 |
+
for sample in dataset:
|
| 349 |
+
total += 1
|
| 350 |
+
temp = preprocess(sample)
|
| 351 |
+
if "```" not in sample['answer']:
|
| 352 |
+
continue
|
| 353 |
+
if len(tokenizer(temp['x']+' '+temp['y'])['input_ids']) >= max_tokens:
|
| 354 |
+
continue
|
| 355 |
+
bar.update(1)
|
| 356 |
+
bar.set_description(f"ok: {ok}/{total}")
|
| 357 |
+
ok += 1
|
| 358 |
+
processed_sample = preprocess(sample)
|
| 359 |
+
if count < 100000:
|
| 360 |
+
train_samples.append(processed_sample)
|
| 361 |
+
elif 100000 <= count < 110000:
|
| 362 |
+
eval_samples.append(processed_sample)
|
| 363 |
+
elif count >= 110000: # Stop processing after collecting enough samples
|
| 364 |
+
break
|
| 365 |
+
count += 1
|
| 366 |
+
# convert to hf dataset
|
| 367 |
+
train_set = Dataset.from_list(train_samples)
|
| 368 |
+
eval_set = Dataset.from_list(eval_samples)
|
| 369 |
+
return train_set, eval_set, eval_set
|
| 370 |
+
|
| 371 |
+
@cache_to_disk("data_cache")
|
| 372 |
+
def load_wizardlm(max_tokens=1024):
|
| 373 |
+
dataset = load_dataset("silk-road/Wizard-LM-Chinese-instruct-evol", split='train')
|
| 374 |
+
from transformers import AutoTokenizer
|
| 375 |
+
tokenizer = AutoTokenizer.from_pretrained("llama/llama-2-7b-hf")
|
| 376 |
+
def preprocess(data):
|
| 377 |
+
y = data['output']
|
| 378 |
+
return {
|
| 379 |
+
"x": template_wo_input.format(
|
| 380 |
+
instruction=data['instruction']
|
| 381 |
+
),
|
| 382 |
+
"y": y,
|
| 383 |
+
}
|
| 384 |
+
train_samples = []
|
| 385 |
+
eval_samples = []
|
| 386 |
+
count = 0
|
| 387 |
+
dataset.shuffle(seed=42)
|
| 388 |
+
from tqdm import tqdm
|
| 389 |
+
bar = tqdm(dataset, total=70000)
|
| 390 |
+
total = 0
|
| 391 |
+
ok = 0
|
| 392 |
+
for sample in dataset:
|
| 393 |
+
total += 1
|
| 394 |
+
temp = preprocess(sample)
|
| 395 |
+
if "sorry" in temp['y'].lower() or "as an ai" in temp['y'].lower():
|
| 396 |
+
continue
|
| 397 |
+
if len(tokenizer(temp['x']+' '+temp['y'])['input_ids']) >= max_tokens:
|
| 398 |
+
continue
|
| 399 |
+
bar.update(1)
|
| 400 |
+
bar.set_description(f"ok: {ok}/{total}")
|
| 401 |
+
ok += 1
|
| 402 |
+
processed_sample = temp
|
| 403 |
+
if count < 52000:
|
| 404 |
+
train_samples.append(processed_sample)
|
| 405 |
+
elif 52000 <= count < 70000:
|
| 406 |
+
eval_samples.append(processed_sample)
|
| 407 |
+
elif count >= 70000: # Stop processing after collecting enough samples
|
| 408 |
+
break
|
| 409 |
+
count += 1
|
| 410 |
+
# convert to hf dataset
|
| 411 |
+
train_set = Dataset.from_list(train_samples)
|
| 412 |
+
eval_set = Dataset.from_list(eval_samples)
|
| 413 |
+
return train_set, eval_set, eval_set
|
| 414 |
+
|
| 415 |
+
|
| 416 |
+
@cache_to_disk("data_cache")
|
| 417 |
+
def load_common(max_tokens=1024):
|
| 418 |
+
# dataset = load_dataset("zwhe99/commonsense_170k", split='train')
|
| 419 |
+
dataset = load_dataset("json", data_files="commonsense_170k.json")['train']
|
| 420 |
+
from transformers import AutoTokenizer
|
| 421 |
+
tokenizer = AutoTokenizer.from_pretrained("llama/llama-2-7b-hf")
|
| 422 |
+
def preprocess(data):
|
| 423 |
+
y = data['output']
|
| 424 |
+
return {
|
| 425 |
+
"x": template_wo_input.format(
|
| 426 |
+
instruction=data['instruction']
|
| 427 |
+
),
|
| 428 |
+
"y": y,
|
| 429 |
+
}
|
| 430 |
+
i = 0
|
| 431 |
+
train_samples = []
|
| 432 |
+
eval_samples = []
|
| 433 |
+
for sample in dataset:
|
| 434 |
+
i += 1
|
| 435 |
+
temp = preprocess(sample)
|
| 436 |
+
# print(temp)
|
| 437 |
+
if len(tokenizer(temp['x']+' '+temp['y'])['input_ids']) >= max_tokens:
|
| 438 |
+
continue
|
| 439 |
+
processed_sample = temp
|
| 440 |
+
train_samples.append(processed_sample)
|
| 441 |
+
if i == 1:
|
| 442 |
+
eval_samples.append(processed_sample)
|
| 443 |
+
# convert to hf dataset
|
| 444 |
+
train_set = Dataset.from_list(train_samples)
|
| 445 |
+
eval_set = Dataset.from_list(eval_samples)
|
| 446 |
+
return train_set, eval_set, eval_set
|
| 447 |
+
|
| 448 |
+
DATASET_MAP = {
|
| 449 |
+
"sst2": load_sst2,
|
| 450 |
+
"cola": load_cola,
|
| 451 |
+
"qqp": load_qqp,
|
| 452 |
+
"mrpc": load_mrpc,
|
| 453 |
+
"mnli": load_mnli,
|
| 454 |
+
"emo": load_emo,
|
| 455 |
+
"squad": load_squad,
|
| 456 |
+
"alpaca": load_alpaca,
|
| 457 |
+
"qnli": load_qnli,
|
| 458 |
+
"gsm8k": load_gsm8k,
|
| 459 |
+
"alpaca_gpt4": load_alpaca_gpt4,
|
| 460 |
+
"flan": load_flan,
|
| 461 |
+
"flan_v2": load_flan_v2,
|
| 462 |
+
"meta_math": load_meta_math,
|
| 463 |
+
"codefeedback": load_codefeedback,
|
| 464 |
+
"wizard_lm": load_wizardlm,
|
| 465 |
+
"common": load_common,
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
if __name__ == "__main__":
|
| 470 |
+
# for dataset in [load_emo, load_sst2, load_cola, load_qqp, load_mrpc, load_mnli]:
|
| 471 |
+
# train_set, val_set, test_set = dataset()
|
| 472 |
+
# print(train_set[0])
|
| 473 |
+
# print(val_set[0])
|
| 474 |
+
# print(test_set[0])
|
| 475 |
+
# print()
|
| 476 |
+
# print(load_alpaca())
|
| 477 |
+
# for name, dataset in DATASET_MAP.items():
|
| 478 |
+
# train_set, val_set, test_set = dataset()
|
| 479 |
+
# print(name)
|
| 480 |
+
# print(train_set[0])
|
| 481 |
+
# print(val_set[0])
|
| 482 |
+
# print(test_set[0])
|
| 483 |
+
# print()
|
| 484 |
+
x, r, _ = load_common()
|
| 485 |
+
print(x[0]['x'])
|
| 486 |
+
print(x[0]['y'])
|
| 487 |
+
print(len(x))
|
| 488 |
+
print(len(r))
|
eval_gsm8k.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from data import load_gsm8k
|
| 2 |
+
from utils import model_inference, initialize_text_to_text_model
|
| 3 |
+
from fire import Fire
|
| 4 |
+
import re
|
| 5 |
+
import os
|
| 6 |
+
from tqdm import tqdm
|
| 7 |
+
from peft import PeftModel
|
| 8 |
+
|
| 9 |
+
def extract_num(text):
|
| 10 |
+
# Regex pattern to find the number following '####'
|
| 11 |
+
pattern = r'####\s*(\d+)'
|
| 12 |
+
# Using re.search to find the first match
|
| 13 |
+
match = re.search(pattern, text)
|
| 14 |
+
if match:
|
| 15 |
+
result = match.group(1)
|
| 16 |
+
print(text)
|
| 17 |
+
else:
|
| 18 |
+
print(text)
|
| 19 |
+
result = ""
|
| 20 |
+
try:
|
| 21 |
+
return int(result.replace(",", ""))
|
| 22 |
+
except:
|
| 23 |
+
print(f"'{result}' can't be converted")
|
| 24 |
+
return 0
|
| 25 |
+
|
| 26 |
+
def main(model_name = "llama/llama-2-7b-hf"):
|
| 27 |
+
_, _, test_set = load_gsm8k()
|
| 28 |
+
model_type = "CausalLM"
|
| 29 |
+
model, tokenizer = initialize_text_to_text_model(
|
| 30 |
+
model_name, model_type, True, flash_attention=True
|
| 31 |
+
)
|
| 32 |
+
model = PeftModel.from_pretrained(model, "checkpoint_dir")
|
| 33 |
+
model.generation_config.pad_token_id = tokenizer.pad_token_id
|
| 34 |
+
all = 0
|
| 35 |
+
correct = 0
|
| 36 |
+
t = tqdm(test_set)
|
| 37 |
+
for example in t:
|
| 38 |
+
# print(example['x'])
|
| 39 |
+
pred_text = model_inference(model, tokenizer, example['x'], model_type, max_target_length=512)
|
| 40 |
+
gt = extract_num(example["y"])
|
| 41 |
+
pred = extract_num(pred_text)
|
| 42 |
+
correct += int(gt == pred)
|
| 43 |
+
all += 1
|
| 44 |
+
t.set_description(f"Accuracy: {correct / all * 100:02f}%")
|
| 45 |
+
|
| 46 |
+
print("Acc:", correct / all)
|
| 47 |
+
# append to gsm8k_results.txt (create if not exists)
|
| 48 |
+
if not os.path.exists("gsm8k_results.txt"):
|
| 49 |
+
with open("gsm8k_results.txt", "w") as f:
|
| 50 |
+
f.write("Model Acc\n")
|
| 51 |
+
with open("gsm8k_results.txt", "a") as f:
|
| 52 |
+
f.write(f"{model_name} {correct / all}\n")
|
| 53 |
+
|
| 54 |
+
if __name__ == "__main__":
|
| 55 |
+
Fire(main)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
|
eval_humaneval.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from human_eval.data import write_jsonl, read_problems
|
| 2 |
+
from fire import Fire
|
| 3 |
+
from tqdm import trange, tqdm
|
| 4 |
+
from utils import initialize_text_to_text_model, model_inference
|
| 5 |
+
import re
|
| 6 |
+
import os
|
| 7 |
+
from human_eval.evaluation import evaluate_functional_correctness
|
| 8 |
+
from peft import PeftModel
|
| 9 |
+
|
| 10 |
+
ALPACA_PREFIX_TEMPLATE_MD = """Below is an instruction that describes a task.\n Write a response that appropriately completes the request.
|
| 11 |
+
|
| 12 |
+
### Instruction:
|
| 13 |
+
Complete the following Python code:
|
| 14 |
+
Notes: respond with the entire complete function definition
|
| 15 |
+
do not add any comments, be as concise in your code as possible
|
| 16 |
+
use only built-in libraries, assume no additional imports other than those provided (if any)
|
| 17 |
+
use ` ` (4 spaces) for each level of indentation
|
| 18 |
+
|
| 19 |
+
code:
|
| 20 |
+
```python
|
| 21 |
+
{PROMPT}
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
### Response:
|
| 25 |
+
```python
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
def post_process(text):
|
| 29 |
+
text = text.replace("```", "")
|
| 30 |
+
text = text.replace("\t", " ")
|
| 31 |
+
text = re.sub(r'(""".*?"""|\'\'\'.*?\'\'\')', '', text, flags=re.DOTALL)
|
| 32 |
+
text = "\n".join([ll.rstrip() for ll in text.splitlines() if ll.strip()])
|
| 33 |
+
lines = text.split("\n")
|
| 34 |
+
spaces_for_each_line = []
|
| 35 |
+
for line in lines:
|
| 36 |
+
match = re.match(r'^( *)', line)
|
| 37 |
+
if match:
|
| 38 |
+
leading_spaces = len(match.group(1))
|
| 39 |
+
spaces_for_each_line.append(leading_spaces)
|
| 40 |
+
try:
|
| 41 |
+
def_line = [i for i, line in enumerate(lines) if "def" in line][0]
|
| 42 |
+
def_line_space = spaces_for_each_line[def_line]
|
| 43 |
+
except:
|
| 44 |
+
print("No def line found")
|
| 45 |
+
print(text)
|
| 46 |
+
def_line_space = 0
|
| 47 |
+
rank_unique_spaces = sorted(list(set(spaces_for_each_line)))
|
| 48 |
+
indentation_level = {}
|
| 49 |
+
i = 0
|
| 50 |
+
for space in rank_unique_spaces:
|
| 51 |
+
if space <= def_line_space:
|
| 52 |
+
indentation_level[space] = 0
|
| 53 |
+
else:
|
| 54 |
+
i += 1
|
| 55 |
+
indentation_level[space] = i
|
| 56 |
+
new_lines = []
|
| 57 |
+
for line, space in zip(lines, spaces_for_each_line):
|
| 58 |
+
new_lines.append(" " * indentation_level[space] + line.lstrip())
|
| 59 |
+
return "\n".join(new_lines)
|
| 60 |
+
|
| 61 |
+
def generate_one_completion(model, tokenizer, model_type, prompt, template=True):
|
| 62 |
+
if template:
|
| 63 |
+
prompt_in = ALPACA_PREFIX_TEMPLATE_MD.format(PROMPT=prompt)
|
| 64 |
+
pred_text = model_inference(model, tokenizer, prompt_in, model_type, max_target_length=512)
|
| 65 |
+
post_pred = post_process(pred_text)
|
| 66 |
+
return post_pred
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def humaneval(model, tokenizer, save_dir, model_type = "CausalLM", model_name="llama/llama-2-7b-hf"):
|
| 72 |
+
|
| 73 |
+
import os
|
| 74 |
+
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
| 75 |
+
|
| 76 |
+
problems = read_problems()
|
| 77 |
+
num_samples_per_task = 1
|
| 78 |
+
samples = [
|
| 79 |
+
dict(task_id=task_id, completion=generate_one_completion(model, tokenizer, model_type, problems[task_id]["prompt"]))
|
| 80 |
+
for task_id in tqdm(problems, desc="Tasks")
|
| 81 |
+
for _ in range(num_samples_per_task)
|
| 82 |
+
]
|
| 83 |
+
|
| 84 |
+
target_name = os.path.join(save_dir, f"{model_name.replace('/', '_')}_humaneval_samples.jsonl")
|
| 85 |
+
write_jsonl(target_name, samples)
|
| 86 |
+
results = evaluate_functional_correctness(target_name, [1])
|
| 87 |
+
print(results)
|
| 88 |
+
|
logTrainer.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass, field
|
| 2 |
+
from functools import reduce
|
| 3 |
+
from typing import Callable, Dict, List, Optional, Tuple, Union, Any
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
import torch
|
| 7 |
+
import wandb
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
from torch.utils.data import Dataset
|
| 10 |
+
|
| 11 |
+
from transformers import Trainer, Seq2SeqTrainingArguments
|
| 12 |
+
from transformers.data.data_collator import DataCollator
|
| 13 |
+
from transformers.pytorch_utils import ALL_LAYERNORM_LAYERS
|
| 14 |
+
from transformers.trainer import (
|
| 15 |
+
EvalPrediction,
|
| 16 |
+
PreTrainedModel,
|
| 17 |
+
PreTrainedTokenizerBase,
|
| 18 |
+
TrainerCallback,
|
| 19 |
+
)
|
| 20 |
+
from transformers.trainer_pt_utils import get_parameter_names
|
| 21 |
+
from transformers.utils import is_sagemaker_mp_enabled, logging
|
| 22 |
+
from peft.tuners.lora.layer import Linear as LoraLinear
|
| 23 |
+
|
| 24 |
+
# include_keywords = ["block.0", "block.4"]
|
| 25 |
+
include_keywords = ["encoder.block.2","encoder.block.3","encoder.block.4"] # for T5
|
| 26 |
+
# include_keywords = ["layers.27", "layers.6"] # for Llama
|
| 27 |
+
do_log = False
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def get_forward_hook(name):
|
| 31 |
+
def hook(module, input, output):
|
| 32 |
+
wandb.log(
|
| 33 |
+
{
|
| 34 |
+
f"{name}/input_mean": input[0].mean().item(),
|
| 35 |
+
f"{name}/input_std": input[0].std().item(),
|
| 36 |
+
f"{name}/output_mean": output.mean().item(),
|
| 37 |
+
f"{name}/output_std": output.std().item(),
|
| 38 |
+
},
|
| 39 |
+
commit=False,
|
| 40 |
+
)
|
| 41 |
+
return hook
|
| 42 |
+
|
| 43 |
+
class LogTrainer(Trainer):
|
| 44 |
+
def __init__(
|
| 45 |
+
self,
|
| 46 |
+
model: Union[PreTrainedModel, nn.Module] = None,
|
| 47 |
+
args: Seq2SeqTrainingArguments = None,
|
| 48 |
+
data_collator: Optional[DataCollator] = None,
|
| 49 |
+
train_dataset: Optional[Dataset] = None,
|
| 50 |
+
eval_dataset: Optional[Union[Dataset, Dict[str, Dataset]]] = None,
|
| 51 |
+
tokenizer: Optional[PreTrainedTokenizerBase] = None,
|
| 52 |
+
model_init: Optional[Callable[[], PreTrainedModel]] = None,
|
| 53 |
+
compute_metrics: Optional[Callable[[EvalPrediction], Dict]] = None,
|
| 54 |
+
callbacks: Optional[List[TrainerCallback]] = None,
|
| 55 |
+
optimizers: Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = (
|
| 56 |
+
None,
|
| 57 |
+
None,
|
| 58 |
+
),
|
| 59 |
+
preprocess_logits_for_metrics: Optional[
|
| 60 |
+
Callable[[torch.Tensor, torch.Tensor], torch.Tensor]
|
| 61 |
+
] = None,
|
| 62 |
+
):
|
| 63 |
+
super().__init__(
|
| 64 |
+
model,
|
| 65 |
+
args,
|
| 66 |
+
data_collator,
|
| 67 |
+
train_dataset,
|
| 68 |
+
eval_dataset,
|
| 69 |
+
tokenizer,
|
| 70 |
+
model_init,
|
| 71 |
+
compute_metrics,
|
| 72 |
+
callbacks,
|
| 73 |
+
optimizers,
|
| 74 |
+
preprocess_logits_for_metrics,
|
| 75 |
+
)
|
| 76 |
+
self.is_peft = "PeftModel" in type(model).__name__
|
| 77 |
+
if self.is_peft:
|
| 78 |
+
for name, module in model.named_modules():
|
| 79 |
+
if isinstance(module, LoraLinear):
|
| 80 |
+
self.scaling = module.scaling["default"]
|
| 81 |
+
break
|
| 82 |
+
self.orig_A = None
|
| 83 |
+
self.orig_B = None
|
| 84 |
+
self.orig_W = None
|
| 85 |
+
self.gradient_accumulation_counter = 0
|
| 86 |
+
|
| 87 |
+
def training_step(
|
| 88 |
+
self, model: nn.Module, inputs: Dict[str, Union[torch.Tensor, Any]]
|
| 89 |
+
) -> torch.Tensor:
|
| 90 |
+
if not do_log:
|
| 91 |
+
return super().training_step(model, inputs)
|
| 92 |
+
if self.is_peft:
|
| 93 |
+
if self.orig_A is None:
|
| 94 |
+
self.orig_A = {}
|
| 95 |
+
self.orig_B = {}
|
| 96 |
+
for name, param in model.named_parameters():
|
| 97 |
+
if param.requires_grad and any(
|
| 98 |
+
[kw in name for kw in include_keywords]
|
| 99 |
+
):
|
| 100 |
+
if "lora_A" in name:
|
| 101 |
+
self.orig_A[name.split("lora_A.")[0]] = (
|
| 102 |
+
param.detach().clone()
|
| 103 |
+
)
|
| 104 |
+
elif "lora_B" in name:
|
| 105 |
+
self.orig_B[name.split("lora_B.")[0]] = (
|
| 106 |
+
param.detach().clone()
|
| 107 |
+
)
|
| 108 |
+
for name, module in model.named_modules():
|
| 109 |
+
if any([kw in name for kw in include_keywords]) and isinstance(module, LoraLinear):
|
| 110 |
+
breakpoint()
|
| 111 |
+
hook = get_forward_hook(name)
|
| 112 |
+
module.register_forward_hook(hook)
|
| 113 |
+
else:
|
| 114 |
+
if self.orig_W is None:
|
| 115 |
+
self.orig_W = {}
|
| 116 |
+
for name, param in model.named_parameters():
|
| 117 |
+
if param.requires_grad and any(
|
| 118 |
+
[kw in name for kw in include_keywords]
|
| 119 |
+
):
|
| 120 |
+
self.orig_W[name] = param.detach().clone()
|
| 121 |
+
|
| 122 |
+
model.train()
|
| 123 |
+
inputs = self._prepare_inputs(inputs)
|
| 124 |
+
|
| 125 |
+
with self.compute_loss_context_manager():
|
| 126 |
+
loss = self.compute_loss(model, inputs)
|
| 127 |
+
|
| 128 |
+
if self.args.n_gpu > 1:
|
| 129 |
+
loss = loss.mean() # mean() to average on multi-gpu parallel training
|
| 130 |
+
|
| 131 |
+
self.accelerator.backward(loss)
|
| 132 |
+
with torch.no_grad():
|
| 133 |
+
if (
|
| 134 |
+
self.gradient_accumulation_counter
|
| 135 |
+
% self.args.gradient_accumulation_steps
|
| 136 |
+
== self.args.gradient_accumulation_steps - 1
|
| 137 |
+
):
|
| 138 |
+
if self.is_peft:
|
| 139 |
+
A_dict = {}
|
| 140 |
+
B_dict = {}
|
| 141 |
+
for name, param in model.named_parameters():
|
| 142 |
+
if param.requires_grad and any(
|
| 143 |
+
[kw in name for kw in include_keywords]
|
| 144 |
+
):
|
| 145 |
+
if "lora_A" in name:
|
| 146 |
+
A_dict[name.split("lora_A.")[0]] = param
|
| 147 |
+
elif "lora_B" in name:
|
| 148 |
+
B_dict[name.split("lora_B.")[0]] = param
|
| 149 |
+
assert (
|
| 150 |
+
len(A_dict)
|
| 151 |
+
== len(self.orig_A)
|
| 152 |
+
== len(B_dict)
|
| 153 |
+
== len(self.orig_B)
|
| 154 |
+
), (
|
| 155 |
+
len(A_dict),
|
| 156 |
+
len(self.orig_A),
|
| 157 |
+
len(B_dict),
|
| 158 |
+
len(self.orig_B),
|
| 159 |
+
)
|
| 160 |
+
for key in A_dict.keys():
|
| 161 |
+
A = A_dict[key]
|
| 162 |
+
B = B_dict[key]
|
| 163 |
+
lora_r = A.shape[0]
|
| 164 |
+
A_grad = A_dict[key].grad
|
| 165 |
+
B_grad = B_dict[key].grad
|
| 166 |
+
A_0 = self.orig_A[key]
|
| 167 |
+
B_0 = self.orig_B[key]
|
| 168 |
+
A_diff = A - A_0
|
| 169 |
+
B_diff = B - B_0
|
| 170 |
+
BA = torch.matmul(B, A)
|
| 171 |
+
BA_0 = torch.matmul(B_0, A_0)
|
| 172 |
+
BA_diff = BA - BA_0
|
| 173 |
+
BA_diff_norm = torch.norm(BA_diff).item()
|
| 174 |
+
A_diff_norm = torch.norm(A_diff).item()
|
| 175 |
+
B_diff_norm = torch.norm(B_diff).item()
|
| 176 |
+
A_norm = torch.norm(A).item()
|
| 177 |
+
B_norm = torch.norm(B).item()
|
| 178 |
+
A_grad_norm = torch.norm(A_grad).item()
|
| 179 |
+
B_grad_norm = torch.norm(B_grad).item()
|
| 180 |
+
# BA_singular_values = torch.svd(BA_diff.float(), compute_uv=False).S[:lora_r]
|
| 181 |
+
BA_singular_values = torch.svd_lowrank(
|
| 182 |
+
BA_diff.float(), q=2 * lora_r
|
| 183 |
+
)[1][:lora_r]
|
| 184 |
+
top_1_ratio = (
|
| 185 |
+
BA_singular_values[0] / BA_singular_values.sum()
|
| 186 |
+
).item()
|
| 187 |
+
top_4_ratio = (
|
| 188 |
+
BA_singular_values[:4].sum() / BA_singular_values.sum()
|
| 189 |
+
).item()
|
| 190 |
+
wandb.log(
|
| 191 |
+
{
|
| 192 |
+
f"A_norm/{key}": A_norm,
|
| 193 |
+
f"B_norm/{key}": B_norm,
|
| 194 |
+
f"A_grad_norm/{key}": A_grad_norm,
|
| 195 |
+
f"B_grad_norm/{key}": B_grad_norm,
|
| 196 |
+
f"A_diff_norm/{key}": A_diff_norm,
|
| 197 |
+
f"B_diff_norm/{key}": B_diff_norm,
|
| 198 |
+
f"BA_diff_norm/{key}": BA_diff_norm,
|
| 199 |
+
f"scaled_BA_diff_norm/{key}": self.scaling
|
| 200 |
+
* BA_diff_norm,
|
| 201 |
+
f"BA_top_1_ratio/{key}": top_1_ratio,
|
| 202 |
+
f"BA_top_4_ratio/{key}": top_4_ratio,
|
| 203 |
+
"train/global_step": self.state.global_step,
|
| 204 |
+
}
|
| 205 |
+
)
|
| 206 |
+
else:
|
| 207 |
+
W_dict = {}
|
| 208 |
+
for name, param in model.named_parameters():
|
| 209 |
+
if (
|
| 210 |
+
param.requires_grad
|
| 211 |
+
and any([kw in name for kw in include_keywords])
|
| 212 |
+
and len(param.shape) == 2
|
| 213 |
+
):
|
| 214 |
+
W_dict[name] = param
|
| 215 |
+
for key in W_dict.keys():
|
| 216 |
+
W = W_dict[key]
|
| 217 |
+
W_grad = W.grad
|
| 218 |
+
W_0 = self.orig_W[key]
|
| 219 |
+
W_diff = W - W_0
|
| 220 |
+
W_diff_norm = torch.norm(W_diff).item()
|
| 221 |
+
W_norm = torch.norm(W).item()
|
| 222 |
+
W_grad_norm = torch.norm(W_grad).item()
|
| 223 |
+
U, S, V = torch.svd(W_diff.float())
|
| 224 |
+
top_1_ratio = S[0] / S.sum()
|
| 225 |
+
top_4_ratio = S[:4].sum() / S.sum()
|
| 226 |
+
wandb.log(
|
| 227 |
+
{
|
| 228 |
+
f"W_norm/{key}": W_norm,
|
| 229 |
+
f"W_grad_norm/{key}": W_grad_norm,
|
| 230 |
+
f"W_diff_norm/{key}": W_diff_norm,
|
| 231 |
+
"train/global_step": self.state.global_step,
|
| 232 |
+
f"W_top_1_ratio/{key}": top_1_ratio.item(),
|
| 233 |
+
f"W_top_4_ratio/{key}": top_4_ratio.item(),
|
| 234 |
+
}
|
| 235 |
+
)
|
| 236 |
+
self.gradient_accumulation_counter += 1
|
| 237 |
+
|
| 238 |
+
return loss.detach() / self.args.gradient_accumulation_steps
|
lora_plus.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass, field
|
| 2 |
+
from functools import reduce
|
| 3 |
+
from typing import Callable, Dict, List, Optional, Tuple, Union
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
from torch.utils.data import Dataset
|
| 8 |
+
|
| 9 |
+
from peft.tuners import lora
|
| 10 |
+
from transformers import Trainer, Seq2SeqTrainingArguments
|
| 11 |
+
from transformers.data.data_collator import DataCollator
|
| 12 |
+
from transformers.pytorch_utils import ALL_LAYERNORM_LAYERS
|
| 13 |
+
from transformers.trainer import (EvalPrediction, PreTrainedModel,
|
| 14 |
+
PreTrainedTokenizerBase, TrainerCallback)
|
| 15 |
+
from transformers.trainer_pt_utils import get_parameter_names
|
| 16 |
+
from transformers.utils import is_sagemaker_mp_enabled, logging
|
| 17 |
+
from logTrainer import LogTrainer
|
| 18 |
+
|
| 19 |
+
logger = logging.get_logger(__name__)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@dataclass
|
| 23 |
+
class LoraPlusTrainingArguments(Seq2SeqTrainingArguments):
|
| 24 |
+
loraplus_lr_ratio: Optional[float] = field(
|
| 25 |
+
default=None, metadata={"help": "loraplus learning rate ratio lr_B / lr_A."}
|
| 26 |
+
)
|
| 27 |
+
loraplus_lr_embedding: Optional[float] = field(
|
| 28 |
+
default=1e-6,
|
| 29 |
+
metadata={"help": "loraplus learning rate for lora embedding layers."},
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def get_module(name, opt_model):
|
| 34 |
+
"""
|
| 35 |
+
Retrieve a module from a model using its parameter name.
|
| 36 |
+
Args:
|
| 37 |
+
name (str): Full name of the parameter, typically including module path.
|
| 38 |
+
opt_model (torch.nn.Module): The model from which to retrieve the module.
|
| 39 |
+
|
| 40 |
+
Returns:
|
| 41 |
+
Module corresponding to the given name.
|
| 42 |
+
"""
|
| 43 |
+
parent_idx = 2 if "lora" in name else 1
|
| 44 |
+
module_names = name.split(sep=".")[:-parent_idx]
|
| 45 |
+
module = reduce(getattr, module_names, opt_model)
|
| 46 |
+
return module
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def create_loraplus_optimizer(
|
| 50 |
+
opt_model,
|
| 51 |
+
optimizer_cls,
|
| 52 |
+
optimizer_kwargs,
|
| 53 |
+
loraplus_lr_ratio,
|
| 54 |
+
loraplus_lr_embedding=None,
|
| 55 |
+
):
|
| 56 |
+
"""
|
| 57 |
+
Creates an optimizer for the given model, applying LoRA-specific learning rate adjustments to different parameter groups.
|
| 58 |
+
|
| 59 |
+
Args:
|
| 60 |
+
opt_model (torch.nn.Module): The model for which the optimizer is being created.
|
| 61 |
+
optimizer_cls (class): The class of the optimizer to be used (e.g., torch.optim.Adam).
|
| 62 |
+
optimizer_kwargs (dict): A dictionary of keyword arguments for the optimizer's initialization.
|
| 63 |
+
loraplus_lr_ratio (float): The learning rate ratio to be applied to LoRA parameters.
|
| 64 |
+
loraplus_lr_embedding (float, optional): A specific learning rate for embedding parameters, with a default value if not provided.
|
| 65 |
+
|
| 66 |
+
Returns:
|
| 67 |
+
An instance of the specified optimizer class configured with the model's parameters organized into groups with custom learning rates.
|
| 68 |
+
"""
|
| 69 |
+
|
| 70 |
+
assert loraplus_lr_ratio is not None, "loraplus_lr_ratio must be provided."
|
| 71 |
+
|
| 72 |
+
if loraplus_lr_embedding is None:
|
| 73 |
+
loraplus_lr_embedding = 1e-6
|
| 74 |
+
|
| 75 |
+
decay_parameters = get_parameter_names(opt_model, ALL_LAYERNORM_LAYERS)
|
| 76 |
+
decay_parameters = [name for name in decay_parameters if "bias" not in name]
|
| 77 |
+
param_groups = {
|
| 78 |
+
"groupA": {},
|
| 79 |
+
"groupB": {},
|
| 80 |
+
"groupB_no_decay": {},
|
| 81 |
+
"embedding": {},
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
for name, param in opt_model.named_parameters():
|
| 85 |
+
if not param.requires_grad:
|
| 86 |
+
continue
|
| 87 |
+
|
| 88 |
+
module = get_module(name, opt_model)
|
| 89 |
+
if isinstance(module, lora.Embedding):
|
| 90 |
+
param_groups["embedding"][name] = param
|
| 91 |
+
elif "lora_B" in name or param.ndim == 1:
|
| 92 |
+
if name in decay_parameters:
|
| 93 |
+
param_groups["groupB"][name] = param
|
| 94 |
+
else:
|
| 95 |
+
param_groups["groupB_no_decay"][name] = param
|
| 96 |
+
else:
|
| 97 |
+
param_groups["groupA"][name] = param
|
| 98 |
+
|
| 99 |
+
assigned_param_groups = ""
|
| 100 |
+
for group in param_groups:
|
| 101 |
+
assigned_param_groups += f"{group}\n {list(param_groups[group].keys())}\n\n"
|
| 102 |
+
logger.debug(assigned_param_groups)
|
| 103 |
+
|
| 104 |
+
lr = optimizer_kwargs["lr"]
|
| 105 |
+
weight_decay = optimizer_kwargs.get("weight_decay", 0.0)
|
| 106 |
+
|
| 107 |
+
optimizer_grouped_parameters = [
|
| 108 |
+
{
|
| 109 |
+
"params": list(param_groups["groupA"].values()),
|
| 110 |
+
"weight_decay": weight_decay,
|
| 111 |
+
"lr": lr,
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"params": list(param_groups["embedding"].values()),
|
| 115 |
+
"weight_decay": weight_decay,
|
| 116 |
+
"lr": loraplus_lr_embedding,
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"params": list(param_groups["groupB"].values()),
|
| 120 |
+
"weight_decay": weight_decay,
|
| 121 |
+
"lr": lr * loraplus_lr_ratio,
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"params": list(param_groups["groupB_no_decay"].values()),
|
| 125 |
+
"weight_decay": 0.0,
|
| 126 |
+
"lr": lr * loraplus_lr_ratio,
|
| 127 |
+
},
|
| 128 |
+
]
|
| 129 |
+
|
| 130 |
+
optimizer = optimizer_cls(optimizer_grouped_parameters, **optimizer_kwargs)
|
| 131 |
+
if optimizer_cls.__name__ == "Adam8bit":
|
| 132 |
+
import bitsandbytes
|
| 133 |
+
|
| 134 |
+
manager = bitsandbytes.optim.GlobalOptimManager.get_instance()
|
| 135 |
+
|
| 136 |
+
skipped = 0
|
| 137 |
+
for module in opt_model.modules():
|
| 138 |
+
if isinstance(module, nn.Embedding):
|
| 139 |
+
skipped += sum(
|
| 140 |
+
{p.data_ptr(): p.numel() for p in module.parameters()}.values()
|
| 141 |
+
)
|
| 142 |
+
logger.info(f"skipped {module}: {skipped/2**20}M params")
|
| 143 |
+
manager.register_module_override(module, "weight", {"optim_bits": 32})
|
| 144 |
+
logger.debug(f"bitsandbytes: will optimize {module} in fp32")
|
| 145 |
+
logger.info(f"skipped: {skipped/2**20}M params")
|
| 146 |
+
|
| 147 |
+
return optimizer
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class LoraPlusTrainer(LogTrainer):
|
| 151 |
+
def __init__(
|
| 152 |
+
self,
|
| 153 |
+
model: Union[PreTrainedModel, nn.Module] = None,
|
| 154 |
+
args: LoraPlusTrainingArguments = None,
|
| 155 |
+
data_collator: Optional[DataCollator] = None,
|
| 156 |
+
train_dataset: Optional[Dataset] = None,
|
| 157 |
+
eval_dataset: Optional[Union[Dataset, Dict[str, Dataset]]] = None,
|
| 158 |
+
tokenizer: Optional[PreTrainedTokenizerBase] = None,
|
| 159 |
+
model_init: Optional[Callable[[], PreTrainedModel]] = None,
|
| 160 |
+
compute_metrics: Optional[Callable[[EvalPrediction], Dict]] = None,
|
| 161 |
+
callbacks: Optional[List[TrainerCallback]] = None,
|
| 162 |
+
optimizers: Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = (
|
| 163 |
+
None,
|
| 164 |
+
None,
|
| 165 |
+
),
|
| 166 |
+
preprocess_logits_for_metrics: Optional[
|
| 167 |
+
Callable[[torch.Tensor, torch.Tensor], torch.Tensor]
|
| 168 |
+
] = None,
|
| 169 |
+
):
|
| 170 |
+
assert isinstance(
|
| 171 |
+
args, LoraPlusTrainingArguments
|
| 172 |
+
), "args must be of type LoraPlusTrainingArguments"
|
| 173 |
+
super().__init__(
|
| 174 |
+
model,
|
| 175 |
+
args,
|
| 176 |
+
data_collator,
|
| 177 |
+
train_dataset,
|
| 178 |
+
eval_dataset,
|
| 179 |
+
tokenizer,
|
| 180 |
+
model_init,
|
| 181 |
+
compute_metrics,
|
| 182 |
+
callbacks,
|
| 183 |
+
optimizers,
|
| 184 |
+
preprocess_logits_for_metrics,
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
def create_optimizer(self):
|
| 188 |
+
"""
|
| 189 |
+
Overrides the method to create an optimizer with LoRA+ specific adjustments.
|
| 190 |
+
"""
|
| 191 |
+
if self.args.loraplus_lr_ratio is None:
|
| 192 |
+
return super().create_optimizer()
|
| 193 |
+
|
| 194 |
+
opt_model = self.model_wrapped if is_sagemaker_mp_enabled() else self.model
|
| 195 |
+
if self.optimizer is None:
|
| 196 |
+
optimizer_cls, optimizer_kwargs = Trainer.get_optimizer_cls_and_kwargs(
|
| 197 |
+
self.args
|
| 198 |
+
)
|
| 199 |
+
|
| 200 |
+
loraplus_lr_ratio = getattr(self.args, "loraplus_lr_ratio", None)
|
| 201 |
+
loraplus_lr_embedding = getattr(self.args, "loraplus_lr_embedding", None)
|
| 202 |
+
self.optimizer = create_loraplus_optimizer(
|
| 203 |
+
opt_model,
|
| 204 |
+
optimizer_cls,
|
| 205 |
+
optimizer_kwargs,
|
| 206 |
+
loraplus_lr_ratio,
|
| 207 |
+
loraplus_lr_embedding,
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
return self.optimizer
|
peft.zip
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3a2008a24660d3a4e89498528727c16cad435e3549cae135ad3ca25afdcebefd
|
| 3 |
+
size 6737683
|
requirements.txt
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
accelerate==0.30.1
|
| 2 |
+
aiohttp==3.9.5
|
| 3 |
+
aiosignal==1.3.1
|
| 4 |
+
annotated-types==0.6.0
|
| 5 |
+
anthropic==0.25.8
|
| 6 |
+
antlr4-python3-runtime==4.9.3
|
| 7 |
+
anyio==4.3.0
|
| 8 |
+
asttokens==2.4.1
|
| 9 |
+
attrs==23.2.0
|
| 10 |
+
cachetools==5.3.3
|
| 11 |
+
calflops==0.2.9
|
| 12 |
+
certifi==2024.2.2
|
| 13 |
+
charset-normalizer==3.3.2
|
| 14 |
+
click==8.1.7
|
| 15 |
+
comm==0.2.2
|
| 16 |
+
datasets==2.19.1
|
| 17 |
+
debugpy==1.8.1
|
| 18 |
+
decorator==5.1.1
|
| 19 |
+
dill==0.3.8
|
| 20 |
+
distro==1.9.0
|
| 21 |
+
dnspython==2.6.1
|
| 22 |
+
docker-pycreds==0.4.0
|
| 23 |
+
einops==0.8.0
|
| 24 |
+
email_validator==2.1.1
|
| 25 |
+
executing==2.0.1
|
| 26 |
+
fastapi==0.111.0
|
| 27 |
+
fastapi-cli==0.0.3
|
| 28 |
+
filelock==3.14.0
|
| 29 |
+
fire==0.6.0
|
| 30 |
+
flash-attn==2.5.8
|
| 31 |
+
frozenlist==1.4.1
|
| 32 |
+
fsspec==2024.3.1
|
| 33 |
+
gitdb==4.0.11
|
| 34 |
+
GitPython==3.1.43
|
| 35 |
+
h11==0.14.0
|
| 36 |
+
httpcore==1.0.5
|
| 37 |
+
httptools==0.6.1
|
| 38 |
+
httpx==0.27.0
|
| 39 |
+
huggingface-hub==0.23.0
|
| 40 |
+
hydra-core==1.3.2
|
| 41 |
+
idna==3.7
|
| 42 |
+
ipykernel==6.29.4
|
| 43 |
+
ipython==8.24.0
|
| 44 |
+
jedi==0.19.1
|
| 45 |
+
Jinja2==3.1.4
|
| 46 |
+
jsonschema==4.22.0
|
| 47 |
+
jsonschema-specifications==2023.12.1
|
| 48 |
+
jupyter_client==8.6.1
|
| 49 |
+
jupyter_core==5.7.2
|
| 50 |
+
markdown-it-py==3.0.0
|
| 51 |
+
markdown2==2.4.13
|
| 52 |
+
MarkupSafe==2.1.5
|
| 53 |
+
matplotlib-inline==0.1.7
|
| 54 |
+
mdurl==0.1.2
|
| 55 |
+
mpmath==1.3.0
|
| 56 |
+
msgpack==1.0.8
|
| 57 |
+
multidict==6.0.5
|
| 58 |
+
multiprocess==0.70.16
|
| 59 |
+
nest-asyncio==1.6.0
|
| 60 |
+
networkx==3.3
|
| 61 |
+
nh3==0.2.17
|
| 62 |
+
ninja==1.11.1.1
|
| 63 |
+
numpy==1.26.4
|
| 64 |
+
nvidia-cublas-cu12==12.1.3.1
|
| 65 |
+
nvidia-cuda-cupti-cu12==12.1.105
|
| 66 |
+
nvidia-cuda-nvrtc-cu12==12.1.105
|
| 67 |
+
nvidia-cuda-runtime-cu12==12.1.105
|
| 68 |
+
nvidia-cudnn-cu12==8.9.2.26
|
| 69 |
+
nvidia-cufft-cu12==11.0.2.54
|
| 70 |
+
nvidia-curand-cu12==10.3.2.106
|
| 71 |
+
nvidia-cusolver-cu12==11.4.5.107
|
| 72 |
+
nvidia-cusparse-cu12==12.1.0.106
|
| 73 |
+
nvidia-ml-py==12.535.161
|
| 74 |
+
nvidia-nccl-cu12==2.20.5
|
| 75 |
+
nvidia-nvjitlink-cu12==12.4.127
|
| 76 |
+
nvidia-nvtx-cu12==12.1.105
|
| 77 |
+
nvitop==1.3.2
|
| 78 |
+
omegaconf==2.3.0
|
| 79 |
+
openai==0.28.1
|
| 80 |
+
orjson==3.10.3
|
| 81 |
+
packaging==24.0
|
| 82 |
+
pandas==2.2.2
|
| 83 |
+
parso==0.8.4
|
| 84 |
+
peft==0.10.0
|
| 85 |
+
pexpect==4.9.0
|
| 86 |
+
pillow==10.3.0
|
| 87 |
+
platformdirs==4.2.1
|
| 88 |
+
prompt-toolkit==3.0.43
|
| 89 |
+
protobuf==4.25.3
|
| 90 |
+
psutil==5.9.8
|
| 91 |
+
ptyprocess==0.7.0
|
| 92 |
+
pure-eval==0.2.2
|
| 93 |
+
pyarrow==16.0.0
|
| 94 |
+
pyarrow-hotfix==0.6
|
| 95 |
+
pydantic==2.7.1
|
| 96 |
+
pydantic_core==2.18.2
|
| 97 |
+
Pygments==2.18.0
|
| 98 |
+
python-dateutil==2.9.0.post0
|
| 99 |
+
python-dotenv==1.0.1
|
| 100 |
+
python-multipart==0.0.9
|
| 101 |
+
pytz==2024.1
|
| 102 |
+
PyYAML==6.0.1
|
| 103 |
+
pyzmq==26.0.3
|
| 104 |
+
ray==2.21.0
|
| 105 |
+
referencing==0.35.1
|
| 106 |
+
regex==2024.5.10
|
| 107 |
+
requests==2.31.0
|
| 108 |
+
rich==13.7.1
|
| 109 |
+
rpds-py==0.18.1
|
| 110 |
+
safetensors==0.4.3
|
| 111 |
+
scipy==1.13.0
|
| 112 |
+
sentencepiece==0.2.0
|
| 113 |
+
sentry-sdk==2.1.1
|
| 114 |
+
setproctitle==1.3.3
|
| 115 |
+
shellingham==1.5.4
|
| 116 |
+
shortuuid==1.0.13
|
| 117 |
+
six==1.16.0
|
| 118 |
+
smmap==5.0.1
|
| 119 |
+
sniffio==1.3.1
|
| 120 |
+
stack-data==0.6.3
|
| 121 |
+
starlette==0.37.2
|
| 122 |
+
svgwrite==1.4.3
|
| 123 |
+
sympy==1.12
|
| 124 |
+
termcolor==2.4.0
|
| 125 |
+
tiktoken==0.6.0
|
| 126 |
+
tokenizers==0.19.1
|
| 127 |
+
torch==2.3.0
|
| 128 |
+
torchaudio==2.3.0
|
| 129 |
+
torchprofile==0.0.4
|
| 130 |
+
torchvision==0.18.0
|
| 131 |
+
tornado==6.4
|
| 132 |
+
tqdm==4.66.4
|
| 133 |
+
traitlets==5.14.3
|
| 134 |
+
transformers==4.44.0
|
| 135 |
+
triton==2.3.0
|
| 136 |
+
typer==0.12.3
|
| 137 |
+
typing_extensions==4.11.0
|
| 138 |
+
tzdata==2024.1
|
| 139 |
+
ujson==5.9.0
|
| 140 |
+
urllib3==2.2.1
|
| 141 |
+
uvicorn==0.29.0
|
| 142 |
+
uvloop==0.19.0
|
| 143 |
+
wandb==0.17.0
|
| 144 |
+
watchfiles==0.21.0
|
| 145 |
+
wavedrom==2.0.3.post3
|
| 146 |
+
wcwidth==0.2.13
|
| 147 |
+
websockets==12.0
|
| 148 |
+
xxhash==3.4.1
|
| 149 |
+
yarl==1.9.4
|
run.sh
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
CUDA_VISIBLE_DEVICES=0 python run_exp.py +model=llama +peft=all ++peft.lora_r1=2 ++peft.lora_r2=2 ++peft.lora_r=8 ++peft.lora_alpha=64 +dataset_name=meta_math +init=default +seed=333
|
run_exp.py
ADDED
|
@@ -0,0 +1,705 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from peft import get_peft_model, LoraConfig, AdaLoraConfig, TaskType
|
| 2 |
+
import os
|
| 3 |
+
import hydra
|
| 4 |
+
from omegaconf import DictConfig, OmegaConf
|
| 5 |
+
from utils import (
|
| 6 |
+
train_text_to_text_model,
|
| 7 |
+
model_inference,
|
| 8 |
+
initialize_text_to_text_model,
|
| 9 |
+
transform_dataset,
|
| 10 |
+
merge_llama,
|
| 11 |
+
)
|
| 12 |
+
import json
|
| 13 |
+
import math
|
| 14 |
+
from datasets import load_dataset
|
| 15 |
+
import wandb
|
| 16 |
+
from data import *
|
| 17 |
+
from typing import List
|
| 18 |
+
import torch
|
| 19 |
+
from copy import deepcopy
|
| 20 |
+
import logging
|
| 21 |
+
from tqdm import tqdm, trange
|
| 22 |
+
from typing import Tuple, List, Dict
|
| 23 |
+
from peft.tuners.lora.layer import Linear as LoraLinear
|
| 24 |
+
from split import rebuild
|
| 25 |
+
import re
|
| 26 |
+
import itertools
|
| 27 |
+
import matplotlib.pyplot as plt
|
| 28 |
+
from commonsense_evaluate import common_evaluate
|
| 29 |
+
from eval_humaneval import humaneval
|
| 30 |
+
# from eval_mtbench import evaluate_mtbench_from_model
|
| 31 |
+
log = logging.getLogger(__name__)
|
| 32 |
+
|
| 33 |
+
s = 0
|
| 34 |
+
|
| 35 |
+
def kron(A, B):
|
| 36 |
+
return (A[:, None, :, None] * B[None, :, None, :]).reshape(A.shape[0] * B.shape[0], A.shape[1] * B.shape[1])
|
| 37 |
+
|
| 38 |
+
def modified_gram_schmidt(W, eps=1e-12):
|
| 39 |
+
"""
|
| 40 |
+
Modified Gram–Schmidt QR
|
| 41 |
+
W: (m, n)
|
| 42 |
+
Returns:
|
| 43 |
+
Q: (m, n)
|
| 44 |
+
R: (n, n)
|
| 45 |
+
"""
|
| 46 |
+
m, n = W.shape
|
| 47 |
+
Q = W.clone()
|
| 48 |
+
R = torch.zeros(n, n, device=W.device, dtype=W.dtype)
|
| 49 |
+
|
| 50 |
+
for i in range(n):
|
| 51 |
+
R[i, i] = torch.norm(Q[:, i])
|
| 52 |
+
if R[i, i] < eps:
|
| 53 |
+
raise RuntimeError("Linearly dependent columns")
|
| 54 |
+
|
| 55 |
+
Q[:, i] = Q[:, i] / R[i, i]
|
| 56 |
+
|
| 57 |
+
for j in range(i + 1, n):
|
| 58 |
+
R[i, j] = torch.dot(Q[:, i], Q[:, j])
|
| 59 |
+
Q[:, j] = Q[:, j] - R[i, j] * Q[:, i]
|
| 60 |
+
|
| 61 |
+
return Q, R
|
| 62 |
+
|
| 63 |
+
def seed_everything(seed: int):
|
| 64 |
+
import random, os
|
| 65 |
+
import numpy as np
|
| 66 |
+
import torch
|
| 67 |
+
|
| 68 |
+
random.seed(seed)
|
| 69 |
+
os.environ["PYTHONHASHSEED"] = str(seed)
|
| 70 |
+
np.random.seed(seed)
|
| 71 |
+
torch.manual_seed(seed)
|
| 72 |
+
torch.cuda.manual_seed(seed)
|
| 73 |
+
torch.backends.cudnn.deterministic = True
|
| 74 |
+
torch.backends.cudnn.benchmark = True
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def find_all_linear_modules(model) -> List[str]:
|
| 78 |
+
r"""
|
| 79 |
+
Finds all available modules to apply lora.
|
| 80 |
+
"""
|
| 81 |
+
linear_cls = torch.nn.Linear
|
| 82 |
+
|
| 83 |
+
output_layer_names = ["lm_head", "embed_tokens"]
|
| 84 |
+
|
| 85 |
+
module_names = set()
|
| 86 |
+
for name, module in model.named_modules():
|
| 87 |
+
if isinstance(module, linear_cls) and not any(
|
| 88 |
+
[output_layer in name for output_layer in output_layer_names]
|
| 89 |
+
):
|
| 90 |
+
module_names.add(name.split(".")[-1])
|
| 91 |
+
return list(module_names)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def find_hidden_state_size(model):
|
| 95 |
+
for name, module in model.named_modules():
|
| 96 |
+
if isinstance(module, torch.nn.Linear):
|
| 97 |
+
return min(module.weight.shape)
|
| 98 |
+
return None
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def calculate_gain(
|
| 102 |
+
nonlinearity, param
|
| 103 |
+
) -> float:
|
| 104 |
+
linear_fns = [
|
| 105 |
+
"linear",
|
| 106 |
+
"conv1d",
|
| 107 |
+
"conv2d",
|
| 108 |
+
"conv3d",
|
| 109 |
+
"conv_transpose1d",
|
| 110 |
+
"conv_transpose2d",
|
| 111 |
+
"conv_transpose3d",
|
| 112 |
+
]
|
| 113 |
+
if nonlinearity in linear_fns or nonlinearity == "sigmoid":
|
| 114 |
+
return 1
|
| 115 |
+
elif nonlinearity == "tanh":
|
| 116 |
+
return 5.0 / 3
|
| 117 |
+
elif nonlinearity == "relu":
|
| 118 |
+
return math.sqrt(2.0)
|
| 119 |
+
elif nonlinearity == "leaky_relu":
|
| 120 |
+
if param is None:
|
| 121 |
+
negative_slope = 0.01
|
| 122 |
+
elif (
|
| 123 |
+
not isinstance(param, bool)
|
| 124 |
+
and isinstance(param, int)
|
| 125 |
+
or isinstance(param, float)
|
| 126 |
+
):
|
| 127 |
+
# True/False are instances of int, hence check above
|
| 128 |
+
negative_slope = param
|
| 129 |
+
else:
|
| 130 |
+
raise ValueError(f"negative_slope {param} not a valid number")
|
| 131 |
+
return math.sqrt(2.0 / (1 + negative_slope**2))
|
| 132 |
+
elif nonlinearity == "selu":
|
| 133 |
+
return (
|
| 134 |
+
3.0 / 4
|
| 135 |
+
) # Value found empirically (https://github.com/pytorch/pytorch/pull/50664)
|
| 136 |
+
else:
|
| 137 |
+
raise ValueError(f"Unsupported nonlinearity {nonlinearity}")
|
| 138 |
+
|
| 139 |
+
def kaimings(weight, a=math.sqrt(5), fan=4096):
|
| 140 |
+
nonlinearity = "leaky_relu"
|
| 141 |
+
generator = None
|
| 142 |
+
gain = calculate_gain(nonlinearity, a)
|
| 143 |
+
std = gain / math.sqrt(fan)
|
| 144 |
+
bound = math.sqrt(3.0) * std # Calculate uniform bounds from standard deviation
|
| 145 |
+
with torch.no_grad():
|
| 146 |
+
return weight.uniform_(-bound, bound, generator=generator)
|
| 147 |
+
|
| 148 |
+
@torch.no_grad()
|
| 149 |
+
def reinit_lora_modules(name, module, init_config, **kwargs):
|
| 150 |
+
r"""
|
| 151 |
+
Reinitialize the lora model with the given configuration.
|
| 152 |
+
"""
|
| 153 |
+
lora_r1 = kwargs["lora_r1"]
|
| 154 |
+
lora_r2 = kwargs["lora_r2"]
|
| 155 |
+
lora_r = kwargs["lora_r"]
|
| 156 |
+
# lora_r1 = min(module.lora_A.default.weight.shape)
|
| 157 |
+
# lora_r2 = min(module.lora_B.default.weight.shape)
|
| 158 |
+
a_dim = max(module.lora_A.default.weight.shape)
|
| 159 |
+
b_dim = max(module.lora_B.default.weight.shape)
|
| 160 |
+
if init_config.mode == "simple":
|
| 161 |
+
match init_config.lora_A:
|
| 162 |
+
case "gaussian":
|
| 163 |
+
torch.nn.init.normal_(
|
| 164 |
+
module.lora_A.default.weight, mean=0.0, std=init_config.lora_A_std
|
| 165 |
+
)
|
| 166 |
+
case "kaiming":
|
| 167 |
+
# https://github.com/microsoft/LoRA/blob/a0a92e0f26c067cf94747bdbf1ce73793fa44d19/loralib/layers.py#L124
|
| 168 |
+
torch.nn.init.kaiming_uniform_(module.lora_A.default.weight, a=math.sqrt(5))
|
| 169 |
+
case "kaimings":
|
| 170 |
+
kaimings(module.lora_A.default.weight, a=math.sqrt(5), fan=module.weight.size(1))
|
| 171 |
+
case "fan_out_kaiming":
|
| 172 |
+
torch.nn.init.kaiming_normal_(
|
| 173 |
+
module.lora_A.default.weight, mode="fan_out"
|
| 174 |
+
)
|
| 175 |
+
case "xavier":
|
| 176 |
+
torch.nn.init.xavier_normal_(module.lora_A.default.weight)
|
| 177 |
+
case "zeros":
|
| 178 |
+
torch.nn.init.zeros_(module.lora_A.default.weight)
|
| 179 |
+
case "unit":
|
| 180 |
+
torch.nn.init.normal_(
|
| 181 |
+
module.lora_A.default.weight, mean=0.0, std=1.0 / (a_dim**0.5)
|
| 182 |
+
)
|
| 183 |
+
case "orthogonal":
|
| 184 |
+
torch.nn.init.orthogonal_(module.lora_A.default.weight)
|
| 185 |
+
case _:
|
| 186 |
+
raise ValueError(f"Unknown lora_A initialization: {init_config.lora_A}")
|
| 187 |
+
match init_config.lora_B:
|
| 188 |
+
case "gaussian":
|
| 189 |
+
torch.nn.init.normal_(
|
| 190 |
+
module.lora_B.default.weight, mean=0.0, std=init_config.lora_B_std
|
| 191 |
+
)
|
| 192 |
+
case "kaiming":
|
| 193 |
+
torch.nn.init.kaiming_normal_(module.lora_B.default.weight.T, a=math.sqrt(5))
|
| 194 |
+
case "fan_out_kaiming":
|
| 195 |
+
torch.nn.init.kaiming_normal_(
|
| 196 |
+
module.lora_B.default.weight, mode="fan_out"
|
| 197 |
+
)
|
| 198 |
+
case "xavier":
|
| 199 |
+
torch.nn.init.xavier_normal_(module.lora_B.default.weight)
|
| 200 |
+
case "zeros":
|
| 201 |
+
torch.nn.init.zeros_(module.lora_B.default.weight)
|
| 202 |
+
case "unit":
|
| 203 |
+
torch.nn.init.normal_(
|
| 204 |
+
module.lora_B.default.weight, mean=0.0, std=1.0 / (b_dim**0.5)
|
| 205 |
+
)
|
| 206 |
+
case "orthogonal":
|
| 207 |
+
torch.nn.init.orthogonal_(module.lora_B.default.weight)
|
| 208 |
+
case _:
|
| 209 |
+
raise ValueError(f"Unknown lora_B initialization: {init_config.lora_B}")
|
| 210 |
+
if init_config.get("scale", "") == "stable":
|
| 211 |
+
gamma = init_config.stable_gamma
|
| 212 |
+
#module.lora_B.default.weight.data *= (m**0.25) / gamma**0.5
|
| 213 |
+
#module.lora_A.default.weight.data *= (n**0.25) / gamma**0.5
|
| 214 |
+
#module.lora_B.default.weight.data *= (m**0.25)
|
| 215 |
+
#module.lora_A.default.weight.data *= (n**0.25)
|
| 216 |
+
module.lora_B.default.weight.data *= 1
|
| 217 |
+
module.lora_A.default.weight.data *= 1
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
elif init_config.mode == "svd":
|
| 221 |
+
U, S, V = torch.svd_lowrank(module.weight.float(), q=4 * lora_r, niter=4)
|
| 222 |
+
V = V.T
|
| 223 |
+
m, n = module.weight.shape
|
| 224 |
+
if init_config.scale == "default":
|
| 225 |
+
S = S / module.scaling["default"]
|
| 226 |
+
module.lora_B.default.weight = torch.nn.Parameter(
|
| 227 |
+
(U[:, :lora_r] * torch.sqrt(S[:lora_r])).contiguous()
|
| 228 |
+
)
|
| 229 |
+
module.lora_A.default.weight = torch.nn.Parameter(
|
| 230 |
+
(V[:lora_r, :].T * torch.sqrt(S[:lora_r])).T.contiguous()
|
| 231 |
+
)
|
| 232 |
+
elif init_config.scale == "stable":
|
| 233 |
+
gamma = init_config.stable_gamma
|
| 234 |
+
module.lora_B.default.weight = torch.nn.Parameter(
|
| 235 |
+
(U[:, :lora_r] * (m**0.25) / gamma**0.5).contiguous()
|
| 236 |
+
)
|
| 237 |
+
module.lora_A.default.weight = torch.nn.Parameter(
|
| 238 |
+
(V[:lora_r, :] * (n**0.25) / gamma**0.5).contiguous()
|
| 239 |
+
)
|
| 240 |
+
elif init_config.scale == "unit":
|
| 241 |
+
module.lora_B.default.weight = torch.nn.Parameter(
|
| 242 |
+
(U[:, :lora_r]).contiguous()
|
| 243 |
+
)
|
| 244 |
+
module.lora_A.default.weight = torch.nn.Parameter(
|
| 245 |
+
(V[:lora_r, :]).contiguous()
|
| 246 |
+
)
|
| 247 |
+
elif init_config.scale == "normalized":
|
| 248 |
+
S_sum = S[:lora_r].sum()
|
| 249 |
+
module.lora_B.default.weight = torch.nn.Parameter(
|
| 250 |
+
(U[:, :lora_r] * torch.sqrt(S[:lora_r])/torch.sqrt(S_sum)*lora_r**0.5).contiguous()
|
| 251 |
+
)
|
| 252 |
+
module.lora_A.default.weight = torch.nn.Parameter(
|
| 253 |
+
(V[:lora_r, :].T * torch.sqrt(S[:lora_r])/torch.sqrt(S_sum)*lora_r**0.5).T.contiguous()
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
elif init_config.mode == "qr":
|
| 257 |
+
W = module.weight.float()
|
| 258 |
+
k,d = W.shape
|
| 259 |
+
Q, R = torch.linalg.qr(W, mode="reduced")
|
| 260 |
+
diag = torch.sign(torch.diag(R))
|
| 261 |
+
diag[diag == 0] = 1.0
|
| 262 |
+
|
| 263 |
+
D = torch.diag(diag)
|
| 264 |
+
|
| 265 |
+
Q = Q @ D
|
| 266 |
+
R = D @ R
|
| 267 |
+
print(torch.min(torch.diag(R)))
|
| 268 |
+
lambda_vals = torch.abs(torch.diag(R))
|
| 269 |
+
perm = torch.argsort(lambda_vals, descending=True)
|
| 270 |
+
|
| 271 |
+
I1 = perm[:lora_r2]
|
| 272 |
+
I2 = perm[lora_r2:lora_r1+lora_r2]
|
| 273 |
+
Q1 = Q[:, I1] # (m, r_high)
|
| 274 |
+
R1 = R[I1]
|
| 275 |
+
Q2 = Q[:, I2]
|
| 276 |
+
R2 = R[I2]
|
| 277 |
+
B = Q1[:k // lora_r1] @ R1[:, :lora_r2]
|
| 278 |
+
A = (Q2[:d // lora_r2] @ R2[:, :lora_r1]).T
|
| 279 |
+
module.lora_B.default.weight = torch.nn.Parameter(B.contiguous().to(module.lora_B.default.weight.device))
|
| 280 |
+
module.lora_A.default.weight = torch.nn.Parameter(A.contiguous().to(module.lora_A.default.weight.device))
|
| 281 |
+
|
| 282 |
+
elif init_config.mode == "gradient":
|
| 283 |
+
named_grad = kwargs["named_grads"]
|
| 284 |
+
grad_name = ".".join(name.split(".")[2:]) + ".weight"
|
| 285 |
+
grads = named_grad[grad_name]
|
| 286 |
+
# print(grads.shape)
|
| 287 |
+
if lora_r1 == 1 and lora_r2 == 1:
|
| 288 |
+
U, S, V = torch.svd_lowrank(-grads.cuda().float(), q=512, niter=16)
|
| 289 |
+
else:
|
| 290 |
+
U, S, V = torch.svd_lowrank(rebuild(-grads.float(),lora_r1, lora_r2), q=4*lora_r, niter=16)
|
| 291 |
+
V = V.T
|
| 292 |
+
# set direction
|
| 293 |
+
if init_config.direction == "ArBr":
|
| 294 |
+
if lora_r1 == 1 and lora_r2 == 1:
|
| 295 |
+
B = U[:, :lora_r] @ torch.diag(torch.sqrt(S[:lora_r])) / torch.sqrt(S[0]) / 128.0 **0.5
|
| 296 |
+
A = torch.diag(torch.sqrt(S[:lora_r])) @ V[:lora_r, :] / torch.sqrt(S[0]) / 128.0 **0.5
|
| 297 |
+
module.lora_B.default.weight = torch.nn.Parameter(B.contiguous().to(module.lora_B.default.weight.device))
|
| 298 |
+
module.lora_A.default.weight = torch.nn.Parameter(A.contiguous().to(module.lora_A.default.weight.device))
|
| 299 |
+
else:
|
| 300 |
+
for i in range(lora_r):
|
| 301 |
+
B = (S[i] / S[0] / 1024)**0.5 * V[i, :].reshape([lora_r2, grads.shape[0]//lora_r1]).T
|
| 302 |
+
A = (S[i] / S[0] / 1024)**0.5 * U[:, i].reshape([grads.shape[1]//lora_r2,lora_r1]).T
|
| 303 |
+
module.lora_A.default.weight[i::lora_r] = torch.nn.Parameter(A.contiguous().to(module.lora_A.default.weight.device))
|
| 304 |
+
module.lora_B.default.weight[:,i::lora_r] = torch.nn.Parameter(B.contiguous().to(module.lora_B.default.weight.device))
|
| 305 |
+
elif init_config.direction == "A2rBr":
|
| 306 |
+
B = U[:, :lora_r]
|
| 307 |
+
A = V[lora_r : 2 * lora_r, :]
|
| 308 |
+
elif init_config.direction == "ArB2r":
|
| 309 |
+
B = U[:, lora_r : 2 * lora_r]
|
| 310 |
+
A = V[:lora_r, :]
|
| 311 |
+
scaling_factor = module.scaling["default"]
|
| 312 |
+
if init_config.scale == "gd":
|
| 313 |
+
A = A / scaling_factor
|
| 314 |
+
B = B / scaling_factor
|
| 315 |
+
elif init_config.scale == "unit":
|
| 316 |
+
# Because A,B is orthogonal, do not need to scale
|
| 317 |
+
pass
|
| 318 |
+
elif init_config.scale == "stable":
|
| 319 |
+
m, n = grads.shape # m: feature_out, n: feature_in
|
| 320 |
+
# the scale of output is only related to the feature_out
|
| 321 |
+
gamma = init_config.stable_gamma
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
elif init_config.scale == "weightS":
|
| 325 |
+
_, S, _ = torch.svd_lowrank(module.weight.float(), q=4 * lora_r, niter=4)
|
| 326 |
+
S = S / module.scaling["default"]
|
| 327 |
+
avg_s = torch.sqrt(S[:lora_r]).mean().to(A.device)
|
| 328 |
+
B = B * avg_s
|
| 329 |
+
A = A * avg_s
|
| 330 |
+
# module.lora_B.default.weight = torch.nn.Parameter(B.contiguous().to(module.lora_B.default.weight.device))
|
| 331 |
+
# module.lora_A.default.weight = torch.nn.Parameter(A.contiguous().to(module.lora_A.default.weight.device))
|
| 332 |
+
|
| 333 |
+
with torch.no_grad():
|
| 334 |
+
# consider dtype not in init_config
|
| 335 |
+
if "dtype" not in init_config:
|
| 336 |
+
pass
|
| 337 |
+
elif init_config.dtype == "bf16":
|
| 338 |
+
module.lora_A.default.weight.data = module.lora_A.default.weight.data.to(
|
| 339 |
+
torch.bfloat16
|
| 340 |
+
)
|
| 341 |
+
module.lora_B.default.weight.data = module.lora_B.default.weight.data.to(
|
| 342 |
+
torch.bfloat16
|
| 343 |
+
)
|
| 344 |
+
elif init_config.dtype == "fp32":
|
| 345 |
+
module.lora_A.default.weight.data = module.lora_A.default.weight.data.to(
|
| 346 |
+
torch.float32
|
| 347 |
+
)
|
| 348 |
+
module.lora_B.default.weight.data = module.lora_B.default.weight.data.to(
|
| 349 |
+
torch.float32
|
| 350 |
+
)
|
| 351 |
+
# If lora_A@lora_B is not zero, then we need to subtract lora_A@lora_B from the original weight matrix
|
| 352 |
+
if init_config.mode == "qr":
|
| 353 |
+
offset = (kron(module.lora_B.default.weight.contiguous(),module.lora_A.default.weight.contiguous())).to(
|
| 354 |
+
module.weight.data.device
|
| 355 |
+
)
|
| 356 |
+
else:
|
| 357 |
+
offset = 0
|
| 358 |
+
# offset = (module.lora_B.default.weight @ module.lora_A.default.weight).to(
|
| 359 |
+
# module.weight.data.device
|
| 360 |
+
# )
|
| 361 |
+
|
| 362 |
+
scaling_factor = module.scaling["default"]
|
| 363 |
+
offset *= scaling_factor
|
| 364 |
+
if "norm_clip" in init_config and init_config.norm_clip:
|
| 365 |
+
# for numerical stability, offset's largest value must be less then weight's largest value
|
| 366 |
+
ratio = torch.max(torch.abs(module.weight.data)) / torch.max(
|
| 367 |
+
torch.abs(offset)
|
| 368 |
+
)
|
| 369 |
+
if ratio < 1:
|
| 370 |
+
offset *= ratio
|
| 371 |
+
module.lora_A.default.weight.data *= ratio**0.5
|
| 372 |
+
module.lora_B.default.weight.data *= ratio**0.5
|
| 373 |
+
log.warning(f"Clipping offset by {ratio}")
|
| 374 |
+
try:
|
| 375 |
+
module.weight.data -= offset
|
| 376 |
+
except:
|
| 377 |
+
breakpoint()
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
def reinit_lora(model, init_config, **kwargs):
|
| 381 |
+
r"""
|
| 382 |
+
Reinitialize the lora model with the given configuration.
|
| 383 |
+
"""
|
| 384 |
+
for name, module in tqdm(
|
| 385 |
+
model.named_modules(),
|
| 386 |
+
desc="Reinitializing Lora",
|
| 387 |
+
total=len(list(model.named_modules())),
|
| 388 |
+
):
|
| 389 |
+
if isinstance(module, LoraLinear):
|
| 390 |
+
reinit_lora_modules(name, module, init_config, **kwargs)
|
| 391 |
+
|
| 392 |
+
return model
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
def get_record_gradient_hook(model, record_dict):
|
| 396 |
+
def record_gradient_hook(grad):
|
| 397 |
+
for n, p in model.named_parameters():
|
| 398 |
+
if p.requires_grad and p.grad is not None:
|
| 399 |
+
if n not in record_dict:
|
| 400 |
+
record_dict[n] = p.grad.cpu()
|
| 401 |
+
else:
|
| 402 |
+
record_dict[n] += p.grad.cpu()
|
| 403 |
+
p.grad = None
|
| 404 |
+
return grad
|
| 405 |
+
|
| 406 |
+
return record_gradient_hook
|
| 407 |
+
|
| 408 |
+
|
| 409 |
+
def estimate_gradient(
|
| 410 |
+
model, dataset, batch_size: int = 4
|
| 411 |
+
) -> Dict[str, List[torch.Tensor]]:
|
| 412 |
+
r"""
|
| 413 |
+
Estimate the gradient of the model on the given dataset
|
| 414 |
+
"""
|
| 415 |
+
log.info("Estimating gradient")
|
| 416 |
+
model.train()
|
| 417 |
+
named_grads = {}
|
| 418 |
+
hooks = []
|
| 419 |
+
for name, param in model.named_parameters():
|
| 420 |
+
hook = param.register_hook(get_record_gradient_hook(model, named_grads))
|
| 421 |
+
hooks.append(hook)
|
| 422 |
+
dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size)
|
| 423 |
+
num = 0
|
| 424 |
+
for batch in tqdm(dataloader, desc="Estimating gradient"):
|
| 425 |
+
num += 1
|
| 426 |
+
batch = {k: v.to(model.device) for k, v in batch.items()}
|
| 427 |
+
outputs = model(**batch)
|
| 428 |
+
outputs.loss.backward()
|
| 429 |
+
get_record_gradient_hook(model, named_grads)(None) # get gradient of last layer
|
| 430 |
+
# make sure the gradient is cleared
|
| 431 |
+
for n, p in model.named_parameters():
|
| 432 |
+
if p.grad is not None:
|
| 433 |
+
p.grad = None
|
| 434 |
+
for n, g in named_grads.items():
|
| 435 |
+
named_grads[n] /= num
|
| 436 |
+
for hook in hooks:
|
| 437 |
+
hook.remove()
|
| 438 |
+
torch.cuda.empty_cache()
|
| 439 |
+
return named_grads
|
| 440 |
+
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
def extract_num(text):
|
| 447 |
+
# Regex pattern to find the number following '####'
|
| 448 |
+
pattern = r'####\s*(\d+)'
|
| 449 |
+
# Using re.search to find the first match
|
| 450 |
+
match = re.search(pattern, text)
|
| 451 |
+
if match:
|
| 452 |
+
result = match.group(1)
|
| 453 |
+
print(text)
|
| 454 |
+
else:
|
| 455 |
+
print(text)
|
| 456 |
+
result = ""
|
| 457 |
+
try:
|
| 458 |
+
return int(result.replace(",", ""))
|
| 459 |
+
except:
|
| 460 |
+
print(f"'{result}' can't be converted")
|
| 461 |
+
return 0
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
def eval_gsm8k(model,tokenizer,model_type, test_set):
|
| 465 |
+
all = 0
|
| 466 |
+
correct = 0
|
| 467 |
+
t = tqdm(test_set)
|
| 468 |
+
for example in t:
|
| 469 |
+
# print(example['x'])
|
| 470 |
+
pred_text = model_inference(model, tokenizer, example['x'], model_type, max_target_length=512)
|
| 471 |
+
gt = extract_num(example["y"])
|
| 472 |
+
pred = extract_num(pred_text)
|
| 473 |
+
correct += int(gt == pred)
|
| 474 |
+
all += 1
|
| 475 |
+
t.set_description(f"Accuracy: {correct / all * 100:02f}%")
|
| 476 |
+
|
| 477 |
+
print("Acc:", correct / all)
|
| 478 |
+
# append to gsm8k_results.txt (create if not exists)
|
| 479 |
+
if not os.path.exists("gsm8k_results.txt"):
|
| 480 |
+
with open("gsm8k_results.txt", "w") as f:
|
| 481 |
+
f.write("Model Acc\n")
|
| 482 |
+
with open("gsm8k_results.txt", "a") as f:
|
| 483 |
+
f.write(f"{model_name} {correct / all}\n")
|
| 484 |
+
|
| 485 |
+
@hydra.main(version_base="1.2", config_path="conf", config_name="config")
|
| 486 |
+
def run_exp(cfg: DictConfig):
|
| 487 |
+
log.info(OmegaConf.to_yaml(cfg))
|
| 488 |
+
seed_everything(cfg.seed)
|
| 489 |
+
model_name = cfg.model.name
|
| 490 |
+
model_type = cfg.model.type
|
| 491 |
+
dataset_name = cfg.dataset_name
|
| 492 |
+
dataset_func = DATASET_MAP[dataset_name]
|
| 493 |
+
use_peft = cfg.peft.use_peft
|
| 494 |
+
if_use_rslora = cfg.peft.use_rslora
|
| 495 |
+
lora_r = cfg.peft.lora_r
|
| 496 |
+
lora_r1 = cfg.peft.lora_r1
|
| 497 |
+
lora_r2 = cfg.peft.lora_r2
|
| 498 |
+
lora_relative_r = cfg.peft.lora_relative_r
|
| 499 |
+
lora_target_modules = cfg.peft.lora_target_modules
|
| 500 |
+
train_embeddings = cfg.peft.train_embeddings
|
| 501 |
+
if cfg.dry_run:
|
| 502 |
+
return
|
| 503 |
+
if use_peft:
|
| 504 |
+
lora_r = cfg.peft.lora_r
|
| 505 |
+
lora_r1 = cfg.peft.lora_r1
|
| 506 |
+
lora_r2 = cfg.peft.lora_r2
|
| 507 |
+
lora_alpha = cfg.peft.lora_alpha
|
| 508 |
+
lora_relative_r = None
|
| 509 |
+
init = cfg.init.mode
|
| 510 |
+
else:
|
| 511 |
+
lora_r = None
|
| 512 |
+
lora_target_modules = None
|
| 513 |
+
lora_relative_r = None
|
| 514 |
+
train_embeddings = True
|
| 515 |
+
config = {
|
| 516 |
+
"model_name": model_name,
|
| 517 |
+
"dataset_name": dataset_name,
|
| 518 |
+
"use_peft": use_peft,
|
| 519 |
+
"lora_r1": lora_r1,
|
| 520 |
+
"lora_r2": lora_r2,
|
| 521 |
+
"lora_r": lora_r,
|
| 522 |
+
"lora_alpha": lora_alpha,
|
| 523 |
+
"init": init,
|
| 524 |
+
"lora_target_modules": str(lora_target_modules),
|
| 525 |
+
"lora_relative_r": lora_relative_r,
|
| 526 |
+
"train_embeddings": train_embeddings,
|
| 527 |
+
}
|
| 528 |
+
if cfg.wandb.name:
|
| 529 |
+
name = cfg.wandb.name
|
| 530 |
+
else:
|
| 531 |
+
name = "_".join([f"{k}={v}" for k, v in config.items()])
|
| 532 |
+
cfg.wandb.project += "_" + cfg.dataset_name
|
| 533 |
+
wandb.init(
|
| 534 |
+
project=cfg.wandb.project,
|
| 535 |
+
name=name,
|
| 536 |
+
config=config,
|
| 537 |
+
)
|
| 538 |
+
train_set, val_set, eval_set = dataset_func()
|
| 539 |
+
model, tokenizer = initialize_text_to_text_model(
|
| 540 |
+
model_name, model_type, cfg.model.bf16, cfg.peft.use_peft, flash_attention=True
|
| 541 |
+
)
|
| 542 |
+
additional_kwargs = {}
|
| 543 |
+
if use_peft and cfg.init.mode == "gradient":
|
| 544 |
+
if isinstance(train_set, list):
|
| 545 |
+
temp_set = train_set[: cfg.init.bsz * cfg.init.iters]
|
| 546 |
+
else:
|
| 547 |
+
temp_set = train_set.select(range(cfg.init.bsz * cfg.init.iters))
|
| 548 |
+
transform_dataset(
|
| 549 |
+
model_type=model_type,
|
| 550 |
+
dataset=temp_set,
|
| 551 |
+
tokenizer=tokenizer,
|
| 552 |
+
max_length=cfg.init.max_length,
|
| 553 |
+
)
|
| 554 |
+
# named_grads = estimate_layer_inputs(model, temp_set, cfg.init.bsz)
|
| 555 |
+
named_grads = estimate_gradient(model, temp_set, cfg.init.bsz)
|
| 556 |
+
additional_kwargs["named_grads"] = named_grads
|
| 557 |
+
|
| 558 |
+
additional_kwargs["lora_r1"] = lora_r1
|
| 559 |
+
additional_kwargs["lora_r"] = lora_r
|
| 560 |
+
additional_kwargs["lora_r2"] = lora_r2
|
| 561 |
+
|
| 562 |
+
if lora_target_modules == "all":
|
| 563 |
+
lora_target_modules = find_all_linear_modules(model)
|
| 564 |
+
else:
|
| 565 |
+
lora_target_modules = list(lora_target_modules) if lora_target_modules else []
|
| 566 |
+
if lora_relative_r is not None:
|
| 567 |
+
hidden_size = find_hidden_state_size(model)
|
| 568 |
+
lora_r = int(hidden_size * lora_relative_r)
|
| 569 |
+
log.info(f"lora_r is set to {hidden_size} * {lora_relative_r} = {lora_r}")
|
| 570 |
+
if use_peft and cfg.peft.get("dora", False):
|
| 571 |
+
log.info("Using Dora")
|
| 572 |
+
peft_config = LoraConfig(
|
| 573 |
+
r1=lora_r1,
|
| 574 |
+
r2=lora_r2,
|
| 575 |
+
lora_alpha=cfg.peft.lora_alpha,
|
| 576 |
+
target_modules=lora_target_modules,
|
| 577 |
+
use_rslora=if_use_rslora,
|
| 578 |
+
use_dora=True,
|
| 579 |
+
)
|
| 580 |
+
orig_model_params = sum(p.numel() for p in model.parameters())
|
| 581 |
+
model = get_peft_model(model, peft_config)
|
| 582 |
+
trainable_params, all_param = model.get_nb_trainable_parameters()
|
| 583 |
+
rate = {
|
| 584 |
+
"trainable_params": trainable_params,
|
| 585 |
+
"orig_params": orig_model_params,
|
| 586 |
+
"all_params": all_param,
|
| 587 |
+
"trainable_ratio": trainable_params / all_param,
|
| 588 |
+
"param_ratio": trainable_params / orig_model_params,
|
| 589 |
+
}
|
| 590 |
+
elif use_peft and cfg.peft.get("adalora", False):
|
| 591 |
+
log.info("Using AdaLora")
|
| 592 |
+
peft_config = AdaLoraConfig(
|
| 593 |
+
task_type=TaskType.CAUSAL_LM,
|
| 594 |
+
target_r=lora_r,
|
| 595 |
+
lora_alpha=cfg.peft.lora_alpha,
|
| 596 |
+
target_modules=lora_target_modules,
|
| 597 |
+
total_step=int(len(train_set)/cfg.model.real_batch_size)*cfg.model.epochs,
|
| 598 |
+
)
|
| 599 |
+
orig_model_params = sum(p.numel() for p in model.parameters())
|
| 600 |
+
model = get_peft_model(model, peft_config)
|
| 601 |
+
trainable_params, all_param = model.get_nb_trainable_parameters()
|
| 602 |
+
rate = {
|
| 603 |
+
"trainable_params": trainable_params,
|
| 604 |
+
"orig_params": orig_model_params,
|
| 605 |
+
"all_params": all_param,
|
| 606 |
+
"trainable_ratio": trainable_params / all_param,
|
| 607 |
+
"param_ratio": trainable_params / orig_model_params,
|
| 608 |
+
}
|
| 609 |
+
elif use_peft:
|
| 610 |
+
peft_config = LoraConfig(
|
| 611 |
+
r1=lora_r1,
|
| 612 |
+
r2=lora_r2,
|
| 613 |
+
r= lora_r,
|
| 614 |
+
lora_alpha=cfg.peft.lora_alpha,
|
| 615 |
+
target_modules=lora_target_modules,
|
| 616 |
+
use_rslora=if_use_rslora,
|
| 617 |
+
)
|
| 618 |
+
orig_model_params = sum(p.numel() for p in model.parameters())
|
| 619 |
+
model = get_peft_model(model, peft_config)
|
| 620 |
+
reinit_lora(model, cfg.init, **additional_kwargs)
|
| 621 |
+
if train_embeddings:
|
| 622 |
+
model.lm_head.weight.requires_grad = True
|
| 623 |
+
trainable_params, all_param = model.get_nb_trainable_parameters()
|
| 624 |
+
rate = {
|
| 625 |
+
"trainable_params": trainable_params,
|
| 626 |
+
"orig_params": orig_model_params,
|
| 627 |
+
"all_params": all_param,
|
| 628 |
+
"trainable_ratio": trainable_params / all_param,
|
| 629 |
+
"param_ratio": trainable_params / orig_model_params,
|
| 630 |
+
}
|
| 631 |
+
save_dir = os.path.join(
|
| 632 |
+
"results", f"{cfg.wandb.project}/{name}/{cfg.seed}", "orig_checkpoint"
|
| 633 |
+
)
|
| 634 |
+
model.save_pretrained(save_dir)
|
| 635 |
+
adapter_config = json.load(open(os.path.join(save_dir, "adapter_config.json")))
|
| 636 |
+
adapter_config["lora_alpha"] = -adapter_config["lora_alpha"]
|
| 637 |
+
json.dump(
|
| 638 |
+
adapter_config, open(os.path.join(save_dir, "adapter_config.json"), "w")
|
| 639 |
+
)
|
| 640 |
+
else:
|
| 641 |
+
# full finetune
|
| 642 |
+
all_param = sum(p.numel() for p in model.parameters())
|
| 643 |
+
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
|
| 644 |
+
rate = {
|
| 645 |
+
"trainable_params": trainable_params,
|
| 646 |
+
"orig_params": all_param,
|
| 647 |
+
"all_params": all_param,
|
| 648 |
+
"trainable_ratio": trainable_params / all_param,
|
| 649 |
+
"param_ratio": 1,
|
| 650 |
+
}
|
| 651 |
+
log.info(rate)
|
| 652 |
+
wandb.summary.update(rate)
|
| 653 |
+
training_loop = train_text_to_text_model
|
| 654 |
+
global s
|
| 655 |
+
print(s)
|
| 656 |
+
|
| 657 |
+
model = training_loop(
|
| 658 |
+
f"{cfg.wandb.project}/{name}",
|
| 659 |
+
train_set,
|
| 660 |
+
val_set,
|
| 661 |
+
model,
|
| 662 |
+
tokenizer,
|
| 663 |
+
model_type,
|
| 664 |
+
num_train_epochs=cfg.model.epochs,
|
| 665 |
+
per_device_batch_size=cfg.model.per_device_batch_size,
|
| 666 |
+
real_batch_size=cfg.model.real_batch_size,
|
| 667 |
+
bf16=cfg.model.bf16,
|
| 668 |
+
eval_epochs=cfg.model.eval_epochs,
|
| 669 |
+
early_stopping_patience=cfg.model.early_stopping_patience,
|
| 670 |
+
max_length=cfg.model.max_length,
|
| 671 |
+
logging_steps=cfg.model.logging_steps,
|
| 672 |
+
use_loraplus=cfg.peft.use_loraplus,
|
| 673 |
+
loraplus_lr_ratio=cfg.peft.loraplus_lr_ratio,
|
| 674 |
+
learning_rate=cfg.model.learning_rate,
|
| 675 |
+
# deepspeed=(
|
| 676 |
+
# "z3_offload_all_bf16.json" if cfg.peft == False else None
|
| 677 |
+
# ),
|
| 678 |
+
gradient_checkpointing=cfg.get("gradient_checkpointing", False),
|
| 679 |
+
seed=cfg.seed,
|
| 680 |
+
)
|
| 681 |
+
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
save_dir = os.path.join(
|
| 685 |
+
"results", f"{cfg.wandb.project}/{name}/{cfg.seed}"
|
| 686 |
+
)
|
| 687 |
+
if not use_peft:
|
| 688 |
+
model.save_pretrained(save_dir)
|
| 689 |
+
tokenizer.save_pretrained(save_dir)
|
| 690 |
+
else:
|
| 691 |
+
# merge_llama(os.path.join("results", f"{cfg.wandb.project}/{name}/{cfg.seed}"))
|
| 692 |
+
pass
|
| 693 |
+
log.info(f"Saving model to {save_dir}")
|
| 694 |
+
if dataset_name == 'meta_math':
|
| 695 |
+
train_set, val_set, eval_set = load_gsm8k()
|
| 696 |
+
model.generation_config.pad_token_id = tokenizer.pad_token_id
|
| 697 |
+
eval_gsm8k(model,tokenizer,model_type,eval_set)
|
| 698 |
+
if dataset_name == 'codefeedback':
|
| 699 |
+
model.generation_config.pad_token_id = tokenizer.pad_token_id
|
| 700 |
+
humaneval(model,tokenizer,save_dir, model_type)
|
| 701 |
+
wandb.finish()
|
| 702 |
+
|
| 703 |
+
|
| 704 |
+
if __name__ == "__main__":
|
| 705 |
+
run_exp()
|
split.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from typing import List, Tuple
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
# def vec(K):
|
| 6 |
+
# return K.T.flatten().reshape(-1, 1)
|
| 7 |
+
|
| 8 |
+
# def rebuild(K, r1, r2):
|
| 9 |
+
# """
|
| 10 |
+
# Implements the R(K) operation from the image.
|
| 11 |
+
# K: input matrix (k x d)
|
| 12 |
+
# r1: block height
|
| 13 |
+
# r2: number of block columns
|
| 14 |
+
# """
|
| 15 |
+
# k, d = K.shape
|
| 16 |
+
# num_block_rows = k // r1
|
| 17 |
+
# num_block_cols = r2
|
| 18 |
+
# bw = d // r2 # block width
|
| 19 |
+
|
| 20 |
+
# blocks = []
|
| 21 |
+
# # R(K) stacks vec(Ki,j) as columns.
|
| 22 |
+
# # The image shows column-major order through the blocks.
|
| 23 |
+
# for j in range(num_block_cols):
|
| 24 |
+
# for i in range(num_block_rows):
|
| 25 |
+
# # Extract block Ki,j
|
| 26 |
+
# Ki_j = K[i*r1:(i+1)*r1, j*bw:(j+1)*bw]
|
| 27 |
+
# # Vectorize (column-major) and add to list
|
| 28 |
+
# blocks.append(vec(Ki_j))
|
| 29 |
+
|
| 30 |
+
# return torch.hstack(blocks)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def rebuild(K, r1, r2):
|
| 34 |
+
k, d = K.shape
|
| 35 |
+
Br = k // r1 # number of block rows
|
| 36 |
+
bw = d // r2 # block width
|
| 37 |
+
|
| 38 |
+
# Step 1: reshape to (Br, r1, r2, bw)
|
| 39 |
+
K_view = K.view(Br, r1, r2, bw)
|
| 40 |
+
|
| 41 |
+
# Step 2: we want to vectorize each (r1, bw) block in COLUMN-MAJOR order.
|
| 42 |
+
# That is equivalent to transposing the block and flattening in row-major.
|
| 43 |
+
# So we permute to (Br, r2, bw, r1) and then flatten last two dims.
|
| 44 |
+
|
| 45 |
+
# But better: move r1 and bw to end, then transpose those two
|
| 46 |
+
# Actually: to get column-major flatten of (r1, bw), we can do:
|
| 47 |
+
# block.transpose(-2, -1).contiguous().view(-1)
|
| 48 |
+
# So let's transpose the last two dims of the block
|
| 49 |
+
|
| 50 |
+
# Current: (Br, r1, r2, bw) → we want to treat (r1, bw) as block → transpose to (bw, r1)
|
| 51 |
+
# So permute to (Br, r2, bw, r1)
|
| 52 |
+
K_transposed_blocks = K_view.permute(0, 2, 3, 1) # (Br, r2, bw, r1)
|
| 53 |
+
|
| 54 |
+
# Now flatten the last two dims (bw, r1) → (bw * r1,) → this is column-major of original block
|
| 55 |
+
vecs = K_transposed_blocks.reshape(Br, r2, bw * r1) # (Br, r2, vec_len)
|
| 56 |
+
|
| 57 |
+
# Now, we have vecs[i, j] = vectorized block (i,j)
|
| 58 |
+
# But we want to output columns in order: j=0: i=0,1,...,Br-1; j=1: i=0,...
|
| 59 |
+
# So we need to **transpose the first two dimensions** and then **flatten in row-major**
|
| 60 |
+
|
| 61 |
+
# Transpose to (r2, Br, vec_len)
|
| 62 |
+
vecs = vecs.permute(1, 0, 2) # (r2, Br, vec_len)
|
| 63 |
+
|
| 64 |
+
# Now flatten first two dims: (r2*Br, vec_len), then transpose to (vec_len, r2*Br)
|
| 65 |
+
result = vecs.reshape(r2 * Br, -1).t()
|
| 66 |
+
|
| 67 |
+
return result
|
| 68 |
+
|
| 69 |
+
# def rebuild(grad, block_size: [int, int]):
|
| 70 |
+
# new_matrix_rows = []
|
| 71 |
+
# if grad.dim() == 2: # 只处理二维梯度(矩阵)
|
| 72 |
+
# # 获取梯度矩阵的尺寸
|
| 73 |
+
# rows, cols = grad.size()
|
| 74 |
+
# # 遍历分块
|
| 75 |
+
# for j in range(0, cols, block_size[1]):
|
| 76 |
+
# for i in range(0, rows, block_size[0]):
|
| 77 |
+
# # 获取当前块
|
| 78 |
+
# block = grad[i:i + block_size[0], j:j + block_size[1]]
|
| 79 |
+
# # 如果块的大小不足,填充零
|
| 80 |
+
# if block.size(0) < block_size[0] or block.size(1) < block_size[1]:
|
| 81 |
+
# padding = (
|
| 82 |
+
# 0, block_size[1] - block.size(1), # 列填充
|
| 83 |
+
# 0, block_size[0] - block.size(0) # 行填充
|
| 84 |
+
# )
|
| 85 |
+
# block = torch.nn.functional.pad(block, padding, "constant", 0)
|
| 86 |
+
# # 向量化并添加到新矩阵的行中
|
| 87 |
+
# new_matrix_rows.append(block.T.flatten())
|
| 88 |
+
|
| 89 |
+
# # 将所有行堆叠成一个新矩阵
|
| 90 |
+
# if new_matrix_rows: # 如果有数据
|
| 91 |
+
# new_gad = torch.stack(new_matrix_rows)
|
| 92 |
+
# else:
|
| 93 |
+
# new_gad = torch.empty(0) # 如果没有梯度数据,返回空矩阵
|
| 94 |
+
|
| 95 |
+
# return new_gad
|
| 96 |
+
|
| 97 |
+
# if __name__ == "__main__":
|
| 98 |
+
# # 定义一个简单的模型
|
| 99 |
+
# class SimpleModel(torch.nn.Module):
|
| 100 |
+
# def __init__(self):
|
| 101 |
+
# super(SimpleModel, self).__init__()
|
| 102 |
+
# self.fc1 = torch.nn.Linear(10, 20)
|
| 103 |
+
# self.fc2 = torch.nn.Linear(20, 10)
|
| 104 |
+
|
| 105 |
+
# def forward(self, x):
|
| 106 |
+
# x = self.fc1(x)
|
| 107 |
+
# x = self.fc2(x)
|
| 108 |
+
# return x
|
| 109 |
+
|
| 110 |
+
# # 初始化模型和损失函数
|
| 111 |
+
# model = SimpleModel()
|
| 112 |
+
# criterion = torch.nn.MSELoss()
|
| 113 |
+
# optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
|
| 114 |
+
|
| 115 |
+
# # 模拟输入数据
|
| 116 |
+
# inputs = torch.randn(5, 10) # batch_size=5, input_size=10
|
| 117 |
+
# targets = torch.randn(5, 10) # batch_size=5, output_size=10
|
| 118 |
+
|
| 119 |
+
# # 前向传播
|
| 120 |
+
# outputs = model(inputs)
|
| 121 |
+
# loss = criterion(outputs, targets)
|
| 122 |
+
|
| 123 |
+
# # 反向传播计算梯度
|
| 124 |
+
# loss.backward()
|
| 125 |
+
|
| 126 |
+
# # 调用函数将梯度分块并构造新矩阵
|
| 127 |
+
# for param in model.parameters():
|
| 128 |
+
# if param.grad is not None: # 检查是否有梯度
|
| 129 |
+
# grad = param.grad # 获取梯度
|
| 130 |
+
# print("旧矩阵的内容:\n", grad)
|
| 131 |
+
# print("新矩阵的形状:", grad.shape)
|
| 132 |
+
# block_size = (2, 2) # 分块大小为 2x2
|
| 133 |
+
# new_matrix = rebuild(grad, block_size)
|
| 134 |
+
# print("新矩阵��形状:", new_matrix.shape)
|
| 135 |
+
# print("新矩阵的内容:\n", new_matrix)
|
| 136 |
+
|
utils.py
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import os
|
| 3 |
+
import typing as tp
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pandas as pd
|
| 6 |
+
from tqdm import tqdm
|
| 7 |
+
from transformers import (
|
| 8 |
+
AutoTokenizer,
|
| 9 |
+
AutoModelForCausalLM,
|
| 10 |
+
AutoModelForSeq2SeqLM,
|
| 11 |
+
Seq2SeqTrainingArguments,
|
| 12 |
+
Seq2SeqTrainer,
|
| 13 |
+
EarlyStoppingCallback,
|
| 14 |
+
TrainerCallback,
|
| 15 |
+
TrainerControl,
|
| 16 |
+
TrainerState,
|
| 17 |
+
)
|
| 18 |
+
from transformers.trainer_utils import PredictionOutput
|
| 19 |
+
from datasets import Dataset, load_dataset
|
| 20 |
+
from torch.utils.data import DataLoader
|
| 21 |
+
from transformers import AdamW, get_linear_schedule_with_warmup
|
| 22 |
+
from lora_plus import LoraPlusTrainingArguments, LoraPlusTrainer
|
| 23 |
+
from logTrainer import LogTrainer
|
| 24 |
+
import logging
|
| 25 |
+
import wandb
|
| 26 |
+
from peft import PeftModel
|
| 27 |
+
from data import load_alpaca
|
| 28 |
+
|
| 29 |
+
log = logging.getLogger(__name__)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def causalLMEncode(example, tokenizer, max_length=-1, ignore_masked_token=True):
|
| 33 |
+
is_list_input = isinstance(example["x"], list)
|
| 34 |
+
# Combine text and add EOS token
|
| 35 |
+
combined_text = (
|
| 36 |
+
[
|
| 37 |
+
x + " " + y + tokenizer.eos_token
|
| 38 |
+
for (x, y) in zip(example["x"], example["y"])
|
| 39 |
+
]
|
| 40 |
+
if is_list_input
|
| 41 |
+
else example["x"] + " " + example["y"] + tokenizer.eos_token
|
| 42 |
+
)
|
| 43 |
+
# Tokenize combined text
|
| 44 |
+
encodings = tokenizer(
|
| 45 |
+
combined_text,
|
| 46 |
+
return_tensors="pt",
|
| 47 |
+
padding=True,
|
| 48 |
+
truncation=True,
|
| 49 |
+
max_length=max_length if max_length != -1 else None,
|
| 50 |
+
)
|
| 51 |
+
# Calculate input text length in tokens
|
| 52 |
+
input_text_length = (
|
| 53 |
+
[
|
| 54 |
+
len(tokenizer(example["x"][i], return_tensors="pt")["input_ids"][0])
|
| 55 |
+
for i in range(len(example["x"]))
|
| 56 |
+
]
|
| 57 |
+
if is_list_input
|
| 58 |
+
else len(tokenizer(example["x"], return_tensors="pt")["input_ids"][0])
|
| 59 |
+
)
|
| 60 |
+
if input_text_length[0] >= max_length:
|
| 61 |
+
log.warning(
|
| 62 |
+
f"Input text length >= max_length: {input_text_length} >= {max_length}. "
|
| 63 |
+
"Consider increasing max_length to avoid truncation."
|
| 64 |
+
)
|
| 65 |
+
# Create labels
|
| 66 |
+
labels = encodings["input_ids"].clone()
|
| 67 |
+
if is_list_input:
|
| 68 |
+
for i, l in enumerate(input_text_length):
|
| 69 |
+
labels[i, :l] = -100
|
| 70 |
+
else:
|
| 71 |
+
labels[0, :input_text_length] = -100
|
| 72 |
+
if ignore_masked_token:
|
| 73 |
+
labels[encodings["attention_mask"] == 0] = -100
|
| 74 |
+
# Update example dictionary
|
| 75 |
+
results = {
|
| 76 |
+
"input_ids": encodings["input_ids"],
|
| 77 |
+
"attention_mask": encodings["attention_mask"],
|
| 78 |
+
"labels": labels,
|
| 79 |
+
# "input_text_length": input_text_length,
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
return results
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def SeqToSeqEncode(example, tokenizer, max_length=None, ignore_masked_token=False):
|
| 86 |
+
inputs = tokenizer(
|
| 87 |
+
example["x"],
|
| 88 |
+
return_tensors="pt",
|
| 89 |
+
padding=True,
|
| 90 |
+
truncation=True,
|
| 91 |
+
max_length=max_length,
|
| 92 |
+
)
|
| 93 |
+
outputs = tokenizer(
|
| 94 |
+
example["y"],
|
| 95 |
+
return_tensors="pt",
|
| 96 |
+
padding=True,
|
| 97 |
+
truncation=True,
|
| 98 |
+
max_length=max_length,
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
results = {
|
| 102 |
+
"input_ids": inputs["input_ids"],
|
| 103 |
+
"attention_mask": inputs["attention_mask"],
|
| 104 |
+
"labels": outputs["input_ids"],
|
| 105 |
+
"decoder_attention_mask": outputs["attention_mask"],
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
if ignore_masked_token:
|
| 109 |
+
results["labels"][outputs["attention_mask"] == 0] = -100
|
| 110 |
+
|
| 111 |
+
return results
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def preprocess_dataset(
|
| 115 |
+
dataset: tp.Union[Dataset, tp.List[tp.Tuple[str, str]], tp.List[tp.Dict[str, str]]]
|
| 116 |
+
) -> Dataset:
|
| 117 |
+
if isinstance(dataset, list) and isinstance(dataset[0], tuple):
|
| 118 |
+
dataset = Dataset.from_pandas(pd.DataFrame(dataset, columns=["x", "y"]))
|
| 119 |
+
elif isinstance(dataset, list) and isinstance(dataset[0], dict):
|
| 120 |
+
dataset = Dataset.from_dict(
|
| 121 |
+
{k: [dic[k] for dic in dataset] for k in dataset[0]}
|
| 122 |
+
)
|
| 123 |
+
elif isinstance(dataset, dict):
|
| 124 |
+
dataset = Dataset.from_dict(dataset)
|
| 125 |
+
elif isinstance(dataset, Dataset):
|
| 126 |
+
pass
|
| 127 |
+
else:
|
| 128 |
+
raise ValueError("Wrong format")
|
| 129 |
+
return dataset
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def initialize_text_to_text_model(
|
| 133 |
+
model_name: str,
|
| 134 |
+
model_type: str,
|
| 135 |
+
bf16: bool,
|
| 136 |
+
use_peft: bool = True,
|
| 137 |
+
tokenizer: str = None,
|
| 138 |
+
flash_attention: bool = False,
|
| 139 |
+
):
|
| 140 |
+
if model_type == "CausalLM":
|
| 141 |
+
if flash_attention:
|
| 142 |
+
log.info("Using flash attention 2")
|
| 143 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 144 |
+
model_name,
|
| 145 |
+
trust_remote_code=True,
|
| 146 |
+
torch_dtype=torch.bfloat16 if bf16 else torch.float32,
|
| 147 |
+
device_map="auto" if use_peft else None,
|
| 148 |
+
attn_implementation="flash_attention_2",
|
| 149 |
+
)
|
| 150 |
+
else:
|
| 151 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 152 |
+
model_name,
|
| 153 |
+
trust_remote_code=True,
|
| 154 |
+
torch_dtype=torch.bfloat16 if bf16 else torch.float32,
|
| 155 |
+
device_map="auto" if use_peft else None,
|
| 156 |
+
)
|
| 157 |
+
elif model_type == "ConditionalGeneration":
|
| 158 |
+
model = AutoModelForSeq2SeqLM.from_pretrained(
|
| 159 |
+
model_name,
|
| 160 |
+
torch_dtype=torch.bfloat16 if bf16 else torch.float32,
|
| 161 |
+
device_map="auto" if use_peft else None,
|
| 162 |
+
)
|
| 163 |
+
if tokenizer:
|
| 164 |
+
tokenizer = AutoTokenizer.from_pretrained(tokenizer)
|
| 165 |
+
else:
|
| 166 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 167 |
+
if tokenizer.eos_token is None:
|
| 168 |
+
tokenizer.add_special_tokens({"eos_token": "<|endoftext|>"})
|
| 169 |
+
model.resize_token_embeddings(len(tokenizer))
|
| 170 |
+
if tokenizer.pad_token is None:
|
| 171 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 172 |
+
return model, tokenizer
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def compute_metrics(p: PredictionOutput):
|
| 176 |
+
predictions = p.predictions
|
| 177 |
+
label_ids = p.label_ids # shape (batch_size, seq_len)
|
| 178 |
+
if False:
|
| 179 |
+
# Hard metric: the model must output exactly the same as the target
|
| 180 |
+
# This should be the default evaluation metric for most tasks
|
| 181 |
+
pred = np.argmax(predictions[0], axis=-1)
|
| 182 |
+
num_correct = sum([np.array_equal(pred[i], label_ids[i]) for i in range(len(pred))])
|
| 183 |
+
accuracy = num_correct / len(pred)
|
| 184 |
+
else:
|
| 185 |
+
# Soft metric: we limit the output space to the target space
|
| 186 |
+
# i.e. the model classify the one with higher prob in positive and negative
|
| 187 |
+
# **Use it in cola and mrpc, because it's too hard for vanilla lora**
|
| 188 |
+
# Only suit for the binary classification with each label of 1 token
|
| 189 |
+
label_ids = label_ids[:, 0] # remove the eos token
|
| 190 |
+
unique_labels = np.unique(label_ids)
|
| 191 |
+
flipped_labels = np.ones_like(label_ids) * unique_labels.sum() - label_ids
|
| 192 |
+
predictions = predictions[0][:, 0, :] # remove the eos token # seq_len, tokens
|
| 193 |
+
label_prob = predictions[np.arange(len(predictions)), label_ids]
|
| 194 |
+
flipped_label_prob = predictions[np.arange(len(predictions)), flipped_labels]
|
| 195 |
+
num_correct = sum(label_prob > flipped_label_prob)
|
| 196 |
+
accuracy = num_correct / len(label_prob)
|
| 197 |
+
|
| 198 |
+
return {"accuracy": accuracy}
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def transform_dataset(model_type, tokenizer, dataset, max_length):
|
| 202 |
+
if model_type == "CausalLM":
|
| 203 |
+
dataset.set_transform(lambda x: causalLMEncode(x, tokenizer, max_length))
|
| 204 |
+
elif model_type == "ConditionalGeneration":
|
| 205 |
+
dataset.set_transform(lambda x: SeqToSeqEncode(x, tokenizer, max_length))
|
| 206 |
+
else:
|
| 207 |
+
raise ValueError("Wrong model type")
|
| 208 |
+
return dataset
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def train_text_to_text_model(
|
| 212 |
+
run_name: str,
|
| 213 |
+
train_dataset: Dataset,
|
| 214 |
+
valid_dataset: Dataset,
|
| 215 |
+
model: torch.nn.Module,
|
| 216 |
+
tokenizer: AutoTokenizer,
|
| 217 |
+
model_type: str,
|
| 218 |
+
per_device_batch_size: int = 1,
|
| 219 |
+
real_batch_size: int = 32,
|
| 220 |
+
max_length: int = None,
|
| 221 |
+
**kwargs,
|
| 222 |
+
) -> torch.nn.Module:
|
| 223 |
+
# Preprocess the dataset
|
| 224 |
+
train_dataset = preprocess_dataset(train_dataset)
|
| 225 |
+
valid_dataset = preprocess_dataset(valid_dataset)
|
| 226 |
+
|
| 227 |
+
assert (
|
| 228 |
+
real_batch_size % per_device_batch_size == 0
|
| 229 |
+
), "real_batch_size must be divisible by per_device_batch_size"
|
| 230 |
+
accu_step = real_batch_size // per_device_batch_size
|
| 231 |
+
|
| 232 |
+
train_dataset, valid_dataset = transform_dataset(
|
| 233 |
+
model_type, tokenizer, train_dataset, max_length
|
| 234 |
+
), transform_dataset(model_type, tokenizer, valid_dataset, max_length)
|
| 235 |
+
|
| 236 |
+
eval_steps = (
|
| 237 |
+
int(len(train_dataset) * kwargs.get("eval_epochs", 1)) // real_batch_size
|
| 238 |
+
)
|
| 239 |
+
# Special for lorqplus
|
| 240 |
+
use_loraplus = kwargs.get("use_loraplus", False)
|
| 241 |
+
TrainingArgumentsClass = (
|
| 242 |
+
LoraPlusTrainingArguments if use_loraplus else Seq2SeqTrainingArguments
|
| 243 |
+
)
|
| 244 |
+
TrainerClass = LoraPlusTrainer if use_loraplus else LogTrainer
|
| 245 |
+
if use_loraplus:
|
| 246 |
+
additional_kwargs = {
|
| 247 |
+
"loraplus_lr_ratio": kwargs.get("loraplus_lr_ratio", 1.0),
|
| 248 |
+
}
|
| 249 |
+
log.info(
|
| 250 |
+
f"Begin training using LoraPlusTrainer with additional kwargs: {additional_kwargs}"
|
| 251 |
+
)
|
| 252 |
+
else:
|
| 253 |
+
additional_kwargs = {}
|
| 254 |
+
log.info("Begin training using Seq2SeqTrainer")
|
| 255 |
+
|
| 256 |
+
# Training arguments
|
| 257 |
+
output_dir = f"./results/{run_name}/{kwargs.get('seed')}"
|
| 258 |
+
training_args = TrainingArgumentsClass(
|
| 259 |
+
output_dir=output_dir, # output directory
|
| 260 |
+
num_train_epochs=kwargs.get(
|
| 261 |
+
"num_train_epochs", 3
|
| 262 |
+
), # total number of training epochs
|
| 263 |
+
per_device_train_batch_size=per_device_batch_size,
|
| 264 |
+
per_device_eval_batch_size=per_device_batch_size,
|
| 265 |
+
gradient_accumulation_steps=accu_step,
|
| 266 |
+
logging_dir="./logs", # directory for storing logs
|
| 267 |
+
logging_steps=kwargs.get("logging_steps", 10), # when to print log
|
| 268 |
+
bf16=kwargs.get("bf16", False),
|
| 269 |
+
gradient_checkpointing=kwargs.get("gradient_checkpointing", False),
|
| 270 |
+
optim=kwargs.get("optim", "adamw_torch"),
|
| 271 |
+
evaluation_strategy="no",
|
| 272 |
+
eval_steps=eval_steps,
|
| 273 |
+
save_steps=eval_steps,
|
| 274 |
+
save_strategy="steps",
|
| 275 |
+
save_total_limit=1, # No need for saving
|
| 276 |
+
load_best_model_at_end=False,
|
| 277 |
+
metric_for_best_model=kwargs.get("metric_for_best_model", "eval_loss"),
|
| 278 |
+
greater_is_better=kwargs.get("greater_is_better", False),
|
| 279 |
+
do_eval=False,
|
| 280 |
+
learning_rate=kwargs.get("learning_rate", 5e-5),
|
| 281 |
+
remove_unused_columns=False, # We tokenize the dataset on the fly
|
| 282 |
+
eval_accumulation_steps=kwargs.get("eval_accumulation_steps", real_batch_size),
|
| 283 |
+
label_names=[
|
| 284 |
+
"labels"
|
| 285 |
+
], # Peft are not compatible with HF's default label names yet
|
| 286 |
+
# Ref: https://discuss.huggingface.co/t/eval-with-trainer-not-running-with-peft-lora-model/53286
|
| 287 |
+
# weight_decay = 0, # No weight decay
|
| 288 |
+
weight_decay = 5e-4,
|
| 289 |
+
warmup_ratio = 0.03,
|
| 290 |
+
lr_scheduler_type = "cosine",
|
| 291 |
+
seed = kwargs.get("seed", 42),
|
| 292 |
+
**additional_kwargs,
|
| 293 |
+
)
|
| 294 |
+
|
| 295 |
+
trainer = TrainerClass(
|
| 296 |
+
model=model,
|
| 297 |
+
args=training_args,
|
| 298 |
+
train_dataset=train_dataset,
|
| 299 |
+
eval_dataset=valid_dataset,
|
| 300 |
+
compute_metrics=compute_metrics if "llama" not in run_name else None,
|
| 301 |
+
# callbacks=[
|
| 302 |
+
# EarlyStoppingCallback(
|
| 303 |
+
# early_stopping_patience=kwargs.get("early_stopping_patience", 1)
|
| 304 |
+
# ),
|
| 305 |
+
# ],
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
trainer.train()
|
| 309 |
+
# eval_results = trainer.evaluate()
|
| 310 |
+
# eval_accuracy = eval_results.get("eval_accuracy", 0)
|
| 311 |
+
# print(f"FINAL_EVAL_ACCURACY: {eval_accuracy:.4f}")
|
| 312 |
+
return model
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
def model_inference(
|
| 316 |
+
model: torch.nn.Module,
|
| 317 |
+
tokenizer: AutoTokenizer,
|
| 318 |
+
input_text: str,
|
| 319 |
+
model_type: str,
|
| 320 |
+
max_source_length: str = 768,
|
| 321 |
+
max_target_length: str = 256,
|
| 322 |
+
):
|
| 323 |
+
if model_type == "CausalLM":
|
| 324 |
+
inputs = tokenizer(
|
| 325 |
+
input_text + " ",
|
| 326 |
+
return_tensors="pt",
|
| 327 |
+
max_length=max_source_length,
|
| 328 |
+
truncation=True,
|
| 329 |
+
return_token_type_ids=False,
|
| 330 |
+
)
|
| 331 |
+
inputs = {k: v.cuda() for k, v in inputs.items()}
|
| 332 |
+
with torch.no_grad():
|
| 333 |
+
outputs = model.generate(
|
| 334 |
+
**inputs,
|
| 335 |
+
return_dict_in_generate=True,
|
| 336 |
+
output_scores=False,
|
| 337 |
+
max_new_tokens=max_target_length,
|
| 338 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 339 |
+
top_p=0.95,
|
| 340 |
+
temperature=0.8,
|
| 341 |
+
)
|
| 342 |
+
pred_text = tokenizer.decode(
|
| 343 |
+
outputs.sequences[0][len(inputs["input_ids"][0]) :],
|
| 344 |
+
skip_special_tokens=True,
|
| 345 |
+
)
|
| 346 |
+
elif model_type == "ConditionalGeneration":
|
| 347 |
+
inputs = tokenizer(input_text, return_tensors="pt").to("cuda")
|
| 348 |
+
with torch.no_grad():
|
| 349 |
+
outputs = model.generate(**inputs, max_new_tokens=max_target_length)
|
| 350 |
+
pred_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 351 |
+
|
| 352 |
+
return pred_text
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def load_peft_model(model, peft_path: str):
|
| 356 |
+
peft_paths = [f"{peft_path}/{i}" for i in os.listdir(peft_path) if "merge" not in i]
|
| 357 |
+
for peft_path in peft_paths:
|
| 358 |
+
print(f"loading and merging from {peft_path}")
|
| 359 |
+
model: PeftModel = PeftModel.from_pretrained(model, peft_path)
|
| 360 |
+
model = model.merge_and_unload()
|
| 361 |
+
return model
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
def test_train():
|
| 365 |
+
# Example usage using emo dataset
|
| 366 |
+
dataset = load_dataset("emo")
|
| 367 |
+
label_map = {0: "others", 1: "happy", 2: "sad", 3: "angry"}
|
| 368 |
+
dataset = dataset.map(lambda e: {"x": e["text"], "y": label_map[e["label"]]})
|
| 369 |
+
train_set = dataset["train"]
|
| 370 |
+
test_set = dataset["test"]
|
| 371 |
+
|
| 372 |
+
model_name = "t5-small"
|
| 373 |
+
model_type = "ConditionalGeneration"
|
| 374 |
+
model, tokenizer = initialize_text_to_text_model(model_name, model_type)
|
| 375 |
+
|
| 376 |
+
model = train_text_to_text_model(
|
| 377 |
+
train_set,
|
| 378 |
+
test_set,
|
| 379 |
+
model,
|
| 380 |
+
tokenizer,
|
| 381 |
+
model_type,
|
| 382 |
+
num_train_epochs=1,
|
| 383 |
+
per_device_batch_size=64,
|
| 384 |
+
real_batch_size=64,
|
| 385 |
+
)
|
| 386 |
+
# Use the model for inference in the testset, print the first 10 examples
|
| 387 |
+
for i in range(10):
|
| 388 |
+
print("Input:", test_set[i]["x"])
|
| 389 |
+
print("Target:", test_set[i]["y"])
|
| 390 |
+
print(
|
| 391 |
+
"Prediction:",
|
| 392 |
+
model_inference(model, tokenizer, test_set[i]["x"], model_type),
|
| 393 |
+
)
|
| 394 |
+
print()
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
def test_llama_alpaca():
|
| 398 |
+
model_name = "meta-llama/Llama-2-7b-hf"
|
| 399 |
+
model_type = "CausalLM"
|
| 400 |
+
peft_path = "results/llama-alpaca_alpaca/gradient-ArB2r-adam/0"
|
| 401 |
+
model, tokenizer = initialize_text_to_text_model(model_name, model_type, True)
|
| 402 |
+
model = load_peft_model(model, peft_path)
|
| 403 |
+
_, _, test_set = load_alpaca()
|
| 404 |
+
for i in range(10):
|
| 405 |
+
print("Input:", test_set[i]["x"])
|
| 406 |
+
# print("Target:", test_set[i]["y"])
|
| 407 |
+
print(
|
| 408 |
+
"Prediction:",
|
| 409 |
+
model_inference(model, tokenizer, test_set[i]["x"], model_type),
|
| 410 |
+
)
|
| 411 |
+
print()
|
| 412 |
+
|
| 413 |
+
|
| 414 |
+
def merge_llama(peft_path):
|
| 415 |
+
model_name = "meta-llama/Llama-2-7b-hf"
|
| 416 |
+
model_type = "CausalLM"
|
| 417 |
+
model, tokenizer = initialize_text_to_text_model(model_name, model_type, True)
|
| 418 |
+
model = load_peft_model(model, peft_path)
|
| 419 |
+
print("Save model to ", os.path.join(peft_path, "merged_checkpoint"))
|
| 420 |
+
model.save_pretrained(os.path.join(peft_path, "merged_checkpoint"))
|
| 421 |
+
tokenizer.save_pretrained(os.path.join(peft_path, "merged_checkpoint"))
|
| 422 |
+
del model, tokenizer
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
if __name__ == "__main__":
|
| 426 |
+
merge_llama("results/llama-alpaca_alpaca/default/0")
|
| 427 |
+
# merge_llama("results/llama-alpaca_alpaca/gradient-ArB2r-adam/0")
|