Sor0ush/c6-repro-bucket / src /ties_merging_utils.py
Sor0ush's picture
download
raw
6.81 kB
import copy
import torch
from collections import OrderedDict
## Model conversion utils
def state_dict_to_vector(state_dict, remove_keys=[]):
shared_state_dict = copy.deepcopy(state_dict)
for key in remove_keys:
if key in shared_state_dict:
del shared_state_dict[key]
sorted_shared_state_dict = OrderedDict(sorted(shared_state_dict.items()))
return torch.nn.utils.parameters_to_vector(
[value.reshape(-1) for key, value in sorted_shared_state_dict.items()]
)
def vector_to_state_dict(vector, state_dict, remove_keys=[]):
# create a reference dict to define the order of the vector
reference_dict = copy.deepcopy(state_dict)
for key in remove_keys:
if key in reference_dict:
del reference_dict[key]
sorted_reference_dict = OrderedDict(sorted(reference_dict.items()))
# create a shared state dict using the refence dict
torch.nn.utils.vector_to_parameters(vector, sorted_reference_dict.values())
# add back the encoder and decoder embedding weights.
if "transformer.shared.weight" in sorted_reference_dict:
for key in remove_keys:
sorted_reference_dict[key] = sorted_reference_dict[
"transformer.shared.weight"
]
return sorted_reference_dict
def add_ptm_to_tv(tv_dict, ptm_dict):
assert set(tv_dict.keys()) == set(
ptm_dict.keys()
), "Differing parameter names in models."
final_dict = copy.deepcopy(tv_dict)
for k, v in ptm_dict.items():
final_dict[k] = tv_dict[k] + v
return final_dict
def check_parameterNamesMatch(checkpoints):
parameter_names = set(checkpoints[0].keys())
if len(checkpoints) >= 2:
# raise ValueError("Number of models is less than 2.")
for checkpoint in checkpoints[1:]:
current_parameterNames = set(checkpoint.keys())
if current_parameterNames != parameter_names:
raise ValueError(
"Differing parameter names in models. "
f"The different parameters are {parameter_names.symmetric_difference(current_parameterNames)}"
)
def check_state_dicts_equal(state_dict1, state_dict2):
if set(state_dict1.keys()) != set(state_dict2.keys()):
return False
for key in state_dict1.keys():
if not torch.equal(state_dict1[key], state_dict2[key]):
return False
return True
## TIES MERGING UTILS
def topk_values_mask(M, K=0.7, return_mask=False, flat_ptm=1, reverse=False):
if K > 1:
K /= 100
original_shape = M.shape
# print(f"original_shape: {original_shape}")
if M.dim() == 1:
M = M.unsqueeze(0)
n, d = M.shape
k = int(d * K)
k = d - k # Keep top k elements instead of bottom k elements
# Find the k-th smallest element by magnitude for each row
kth_values, _ = (M/flat_ptm).abs().kthvalue(k, dim=1, keepdim=True)
# Create a mask tensor with True for the top k elements in each row
if reverse:
mask = (M/flat_ptm).abs() <= kth_values
else:
mask = (M/flat_ptm).abs() >= kth_values
if original_shape == M.squeeze().shape:
final_mask = mask.squeeze()
M = M.squeeze()
out_mask = final_mask.float()
else:
final_mask = mask
out_mask = final_mask.float().mean(dim=1)
if return_mask:
return M * final_mask, final_mask.float().mean(dim=1), final_mask
return M * final_mask, out_mask
def resolve_zero_signs(sign_to_mult, method="majority"):
majority_sign = torch.sign(sign_to_mult.sum())
if method == "majority":
sign_to_mult[sign_to_mult == 0] = majority_sign
elif method == "minority":
sign_to_mult[sign_to_mult == 0] = -1 * majority_sign
return sign_to_mult
def resolve_sign(Tensor):
sign_to_mult = torch.sign(Tensor.sum(dim=0))
sign_to_mult = resolve_zero_signs(sign_to_mult, "majority")
return sign_to_mult
def disjoint_merge(Tensor, merge_func, sign_to_mult):
merge_func = merge_func.split("-")[-1]
# If sign is provided then we select the corresponding entries and aggregate.
if sign_to_mult is not None:
rows_to_keep = torch.where(
sign_to_mult.unsqueeze(0) > 0, Tensor > 0, Tensor < 0
)
selected_entries = Tensor * rows_to_keep
# Else we select all non-zero entries and aggregate.
else:
rows_to_keep = Tensor != 0
selected_entries = Tensor * rows_to_keep
if merge_func == "mean":
non_zero_counts = (selected_entries != 0).sum(dim=0).float()
disjoint_aggs = torch.sum(selected_entries, dim=0) / torch.clamp(non_zero_counts, min=1)
elif merge_func == "sum":
disjoint_aggs = torch.sum(selected_entries, dim=0)
elif merge_func == "max":
disjoint_aggs = selected_entries.abs().max(dim=0)[0]
disjoint_aggs *= sign_to_mult
else:
raise ValueError(f"Merge method {merge_func} is not defined.")
return disjoint_aggs
def ties_merging(
flat_task_checks,
reset_thresh=None,
merge_func="",
):
all_checks = flat_task_checks.clone()
updated_checks, *_ = topk_values_mask(
all_checks, K=reset_thresh, return_mask=False
)
print(f"RESOLVING SIGN")
final_signs = resolve_sign(updated_checks)
assert final_signs is not None
print(f"Disjoint AGGREGATION: {merge_func}")
merged_tv = disjoint_merge(updated_checks, merge_func, final_signs)
return merged_tv
def disjoint_merge_split(Tensor, merge_func, sign_to_mult):
merge_func = merge_func.split("-")[-1]
# If sign is provided then we select the corresponding entries and aggregate.
if sign_to_mult is not None:
rows_to_keep = torch.where(
sign_to_mult.unsqueeze(0) > 0, Tensor > 0, Tensor < 0
)
selected_entries = Tensor * rows_to_keep
# Else we select all non-zero entries and aggregate.
else:
rows_to_keep = Tensor != 0
selected_entries = Tensor * rows_to_keep
if merge_func == "sum":
disjoint_aggs = torch.sum(selected_entries, dim=0)
else:
raise ValueError(f"Merge method {merge_func} is not defined.")
return selected_entries, disjoint_aggs
def ties_merging_split(
flat_task_checks,
reset_thresh=None,
merge_func="",
):
all_checks = flat_task_checks.clone()
updated_checks, *_ = topk_values_mask(
all_checks, K=reset_thresh, return_mask=False
)
print(f"RESOLVING SIGN")
final_signs = resolve_sign(updated_checks)
assert final_signs is not None
print(f"Disjoint AGGREGATION: {merge_func}")
selected_entries, merged_tv = disjoint_merge_split(updated_checks, merge_func, final_signs)
return selected_entries, merged_tv

Xet Storage Details

Size:
6.81 kB
·
Xet hash:
e09d10ac0160387e21b67a27b52387efafab51ef84ac962b70c56ffa055fb695

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.