TinyQuery-140M / tinyquery /average_checkpoints.py
karmx's picture
Release TinyQuery 139.7M from scratch with frozen weights, reproducible Mac evaluations and runtime source
b296ad4 verified
Raw
History Blame Contribute Delete
2.24 kB
"""Average compatible checkpoints from the same randomly initialized training lineage."""
import argparse
import json
from pathlib import Path
import torch
from safetensors.torch import load_file,save_file
from tinyquery.prepare import file_sha256
def main():
p=argparse.ArgumentParser();p.add_argument('--checkpoints',nargs='+',required=True);p.add_argument('--weights',nargs='+',type=float)
p.add_argument('--out',required=True);args=p.parse_args();weights=args.weights or [1]*len(args.checkpoints)
assert len(weights)==len(args.checkpoints) and all(w>=0 for w in weights) and sum(weights)>0
weights=[w/sum(weights) for w in weights];total={};config=None;sources=[]
for name,weight in zip(args.checkpoints,weights):
path=Path(name);c=json.loads((path.parent/'config.json').read_text());assert config is None or config==c;config=c
info=json.loads((path.parent/'checkpoint-info.json').read_text());assert info['random_initialization']
state=load_file(str(path));assert not total or total.keys()==state.keys()
for key,value in state.items():
if key not in total:total[key]=value.float()*weight
else:total[key].add_(value.float(),alpha=weight)
sources.append({'checkpoint':str(path),'sha256':file_sha256(path),'weight':weight,'info':info});del state
dest=Path(args.out);dest.mkdir(parents=True,exist_ok=True)
save_file({k:v.to(torch.bfloat16).contiguous() for k,v in total.items()},str(dest/'model.safetensors'),
metadata={'method':'weighted_parameter_average','random_initialization':'true'})
(dest/'config.json').write_text(json.dumps(config,indent=2))
info={'method':'weighted_parameter_average','sources':sources,'random_initialization':True,
'step':max(s['info']['step'] for s in sources),'step_interpretation':'Latest source step; these are averaged weights, not that raw checkpoint.'}
for key in ['processed_tokens','response_tokens','training_seconds']:info[key]=max(s['info'][key] for s in sources)
(dest/'checkpoint-info.json').write_text(json.dumps(info,indent=2));print(json.dumps({'out':str(dest),'sources':[(s['info']['step'],s['weight']) for s in sources]}))
if __name__=='__main__':main()