Commit ·
01906b8
1
Parent(s): 739227f
Upload 2 files
Browse files- merge.bash +7 -0
- my_merge_lora.py +151 -0
merge.bash
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
python3 my_merge_lora.py\
|
| 2 |
+
--base_model ~/autodl-tmp/RWKV-4-Raven-7B-v11-Eng49%-Chn49%-Jpn1%-Other1%-20230430-ctx8192.pth\
|
| 3 |
+
--lora_load ~/RWKV_Train/save_7B_128/rwkv-12.pth\
|
| 4 |
+
--save ~/autodl-tmp/lora_7B.pth\
|
| 5 |
+
--lora_schedule poly\
|
| 6 |
+
--plot\
|
| 7 |
+
--lora_strategy "0:64,0.3:32,0.4:0,0.5:32,1:64"
|
my_merge_lora.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from matplotlib import pyplot as plt
|
| 2 |
+
import numpy as np
|
| 3 |
+
from collections import OrderedDict
|
| 4 |
+
import os
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
import sys
|
| 7 |
+
from typing import Dict
|
| 8 |
+
import typing
|
| 9 |
+
import torch
|
| 10 |
+
import argparse
|
| 11 |
+
parser = argparse.ArgumentParser()
|
| 12 |
+
parser.add_argument("--base_model", type=str, required=True)
|
| 13 |
+
parser.add_argument("--lora_load", type=str, required=True)
|
| 14 |
+
parser.add_argument("--lora_schedule", type=str, default="const", choices=["const", "linear", "poly"])
|
| 15 |
+
parser.add_argument("--lora_alpha", type=float, default=None)
|
| 16 |
+
parser.add_argument("--lora_beta", type=float, default=None)
|
| 17 |
+
parser.add_argument("--lora_strategy", type=str, default=None)
|
| 18 |
+
parser.add_argument("--plot", action="store_true")
|
| 19 |
+
parser.add_argument("--save", required=True, type=str)
|
| 20 |
+
args = parser.parse_args()
|
| 21 |
+
|
| 22 |
+
def f_const(alpha):
|
| 23 |
+
def inner(x):
|
| 24 |
+
return alpha
|
| 25 |
+
return inner
|
| 26 |
+
def f_linear(alpha, beta):
|
| 27 |
+
def inner(x):
|
| 28 |
+
return alpha+x*(beta-alpha)
|
| 29 |
+
return inner
|
| 30 |
+
|
| 31 |
+
def f_polyline(*args):
|
| 32 |
+
args = sorted(args)
|
| 33 |
+
xs = []
|
| 34 |
+
ys = []
|
| 35 |
+
xys = args
|
| 36 |
+
for x, y in args:
|
| 37 |
+
xs.append(x)
|
| 38 |
+
ys.append(y)
|
| 39 |
+
def inner(x):
|
| 40 |
+
if(x<=xs[0]):
|
| 41 |
+
return ys[0]
|
| 42 |
+
if(x>=xs[-1]):
|
| 43 |
+
return ys[-1]
|
| 44 |
+
for i, x1 in enumerate(xs):
|
| 45 |
+
x0 = xs[i-1]
|
| 46 |
+
if(x0<=x and x<=x1):
|
| 47 |
+
y0 = ys[i-1]
|
| 48 |
+
y1 = ys[i]
|
| 49 |
+
n = (x-x0)/(x1-x0)
|
| 50 |
+
y = y0*(1-n)+y1*n
|
| 51 |
+
return y
|
| 52 |
+
return ys[-1]
|
| 53 |
+
return inner
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
with torch.no_grad():
|
| 57 |
+
base = args.base_model
|
| 58 |
+
lora = args.lora_load
|
| 59 |
+
w: Dict[str, torch.Tensor] = torch.load(base, map_location="cpu")
|
| 60 |
+
w_lora: Dict[str, torch.Tensor] = torch.load(lora, map_location="cpu")
|
| 61 |
+
out: typing.OrderedDict[str, torch.Tensor] = OrderedDict()
|
| 62 |
+
|
| 63 |
+
tuned_weights = []
|
| 64 |
+
|
| 65 |
+
lora_rank = None
|
| 66 |
+
listkeys = list(w.keys())
|
| 67 |
+
for key in listkeys:
|
| 68 |
+
if key.endswith(".weight"):
|
| 69 |
+
pref = key[:-len(".weight")]
|
| 70 |
+
key_A = pref+".lora_A"
|
| 71 |
+
key_B = pref+".lora_B"
|
| 72 |
+
if(key_A in w_lora and key_B in w_lora):
|
| 73 |
+
print("Weight %s will be merged with lora"%pref)
|
| 74 |
+
tuned_weights.append(key)
|
| 75 |
+
|
| 76 |
+
if(lora_rank is None):
|
| 77 |
+
lora_A = w_lora[key_A]
|
| 78 |
+
lora_B = w_lora[key_B]
|
| 79 |
+
lora_rank = lora_A.shape[0]
|
| 80 |
+
assert lora_rank == lora_B.shape[1]
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
if(args.lora_schedule == "const"):
|
| 84 |
+
alpha = args.lora_alpha
|
| 85 |
+
if(alpha is None):
|
| 86 |
+
print("assuming lora_alpha = lora_rank = %s"%lora_rank)
|
| 87 |
+
alpha = lora_rank
|
| 88 |
+
f_schedule = f_const(alpha)
|
| 89 |
+
elif(args.lora_schedule == "poly"):
|
| 90 |
+
xys = []
|
| 91 |
+
for i in args.lora_strategy.split(","):
|
| 92 |
+
xy = [float(_) for _ in i.split(":")]
|
| 93 |
+
xys.append(xy)
|
| 94 |
+
f_schedule = f_polyline(*xys)
|
| 95 |
+
else:
|
| 96 |
+
alpha = args.lora_alpha
|
| 97 |
+
beta = args.lora_beta
|
| 98 |
+
if(alpha is None):
|
| 99 |
+
print("assuming lora_alpha = lora_rank = %s"%lora_rank)
|
| 100 |
+
alpha = lora_rank
|
| 101 |
+
if(beta is None):
|
| 102 |
+
print("assuming beta = lora_rank = %s"%lora_rank)
|
| 103 |
+
beta = lora_rank
|
| 104 |
+
f_schedule = f_linear(alpha, beta)
|
| 105 |
+
|
| 106 |
+
weight2alpha = {}
|
| 107 |
+
for idx, i in enumerate(tuned_weights):
|
| 108 |
+
# assuming weights are fetched in depth order
|
| 109 |
+
depth = idx
|
| 110 |
+
if(len(tuned_weights)>1):
|
| 111 |
+
depth = depth/(len(tuned_weights)-1)
|
| 112 |
+
else:
|
| 113 |
+
depth = 0.5
|
| 114 |
+
alpha = f_schedule(depth)
|
| 115 |
+
print("%s: alpha=%.3f, alpha/rank=%.2f"%(i, alpha, alpha/lora_rank))
|
| 116 |
+
weight2alpha[i] = alpha
|
| 117 |
+
if(args.plot):
|
| 118 |
+
tot = 32
|
| 119 |
+
xs = np.linspace(0, tot-1, tot)
|
| 120 |
+
ys = [f_schedule(x/(tot-1)) for x in xs]
|
| 121 |
+
plt.plot(xs, ys)
|
| 122 |
+
plt.savefig(args.save+".png")
|
| 123 |
+
print("plot", args.save+".png")
|
| 124 |
+
for key in tqdm(listkeys):
|
| 125 |
+
if(key in tuned_weights):
|
| 126 |
+
pref = key[:-len(".weight")]
|
| 127 |
+
key_A = pref+".lora_A"
|
| 128 |
+
key_B = pref+".lora_B"
|
| 129 |
+
|
| 130 |
+
lora_A = w_lora[key_A]
|
| 131 |
+
lora_B = w_lora[key_B]
|
| 132 |
+
lora_rank = lora_A.shape[0]
|
| 133 |
+
assert lora_rank == lora_B.shape[1]
|
| 134 |
+
|
| 135 |
+
delta_w = (lora_B @ lora_A)*weight2alpha[key]/lora_rank
|
| 136 |
+
new_w = w[key]+delta_w
|
| 137 |
+
out_w = new_w.to(device=w[key].device, dtype=w[key].dtype, copy=True)
|
| 138 |
+
out[key] = out_w
|
| 139 |
+
del w[key]
|
| 140 |
+
else:
|
| 141 |
+
# print("%s = original"%(key))
|
| 142 |
+
out[key] = w[key].clone()
|
| 143 |
+
del w[key]
|
| 144 |
+
# assert list(out.keys()) == list(w.keys())
|
| 145 |
+
# for key in out.keys():
|
| 146 |
+
# assert out[key].shape == w[key].shape
|
| 147 |
+
# assert out[key].dtype == w[key].dtype
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
torch.save(out, args.save)
|
| 151 |
+
print("saved", args.save)
|