chen459664 commited on
Commit
1a9a80b
·
verified ·
1 Parent(s): c000eca

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lm-quant-toolkit/.deps/CLIP_benchmark/clip_benchmark/datasets/cupl_prompts.json +0 -0
  2. lm-quant-toolkit/.deps/CLIP_benchmark/probe_benchmark/scaling_experiment_data2.json +0 -0
  3. lm-quant-toolkit/.deps/hqq/examples/hf/llama2_chat_hf_hub_example.py +65 -0
  4. lm-quant-toolkit/.deps/hqq/examples/hf/whisper.py +98 -0
  5. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/.gitignore +3 -0
  6. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/.pdbrc +10 -0
  7. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/adapter/autoawq.py +32 -0
  8. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/adapter/awq.py +94 -0
  9. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Llama-2-13b-hf.csv +0 -0
  10. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Llama-2-70b-hf.csv +0 -0
  11. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Llama-2-7b-hf.csv +0 -0
  12. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Meta-Llama-3.1-405B-Instruct.csv +0 -0
  13. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/debug-bench.sh +3 -0
  14. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/eval_model.py +115 -0
  15. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/fp16_llama2_demo.py +26 -0
  16. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/quant_llama2_awq_demo.py +40 -0
  17. lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/run-bench.sh +8 -0
  18. lm-quant-toolkit/.deps/hqq/examples/lora/train_hqq_lora_example.py +220 -0
  19. lm-quant-toolkit/.deps/hqq/examples/open_clip/.pdbrc +4 -0
  20. lm-quant-toolkit/.deps/hqq/examples/open_clip/vit_clip_example.py +158 -0
  21. lm-quant-toolkit/.deps/hqq/examples/timm/vit_clip_example.py +73 -0
  22. lm-quant-toolkit/.deps/hqq/examples/vllm/llama2_example.py +25 -0
  23. lm-quant-toolkit/.deps/hqq/hqq.egg-info/PKG-INFO +23 -0
  24. lm-quant-toolkit/.deps/hqq/hqq.egg-info/SOURCES.txt +53 -0
  25. lm-quant-toolkit/.deps/hqq/hqq.egg-info/dependency_links.txt +1 -0
  26. lm-quant-toolkit/.deps/hqq/hqq.egg-info/requires.txt +7 -0
  27. lm-quant-toolkit/.deps/hqq/hqq.egg-info/top_level.txt +1 -0
  28. lm-quant-toolkit/.deps/hqq/hqq/__init__.py +3 -0
  29. lm-quant-toolkit/.deps/hqq/hqq/__pycache__/__init__.cpython-311.pyc +0 -0
  30. lm-quant-toolkit/.deps/hqq/hqq/backends/__init__.py +0 -0
  31. lm-quant-toolkit/.deps/hqq/hqq/backends/marlin.py +118 -0
  32. lm-quant-toolkit/.deps/hqq/hqq/backends/torchao.py +388 -0
  33. lm-quant-toolkit/.deps/hqq/hqq/core/__init__.py +0 -0
  34. lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/__init__.cpython-311.pyc +0 -0
  35. lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/bitpack.cpython-311.pyc +0 -0
  36. lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/optimize.cpython-311.pyc +0 -0
  37. lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/quantize.cpython-311.pyc +0 -0
  38. lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/utils.cpython-311.pyc +0 -0
  39. lm-quant-toolkit/.deps/hqq/hqq/core/bitpack.py +144 -0
  40. lm-quant-toolkit/.deps/hqq/hqq/core/optimize.py +476 -0
  41. lm-quant-toolkit/.deps/hqq/hqq/core/peft.py +545 -0
  42. lm-quant-toolkit/.deps/hqq/hqq/core/quantize.py +948 -0
  43. lm-quant-toolkit/.deps/hqq/hqq/core/utils.py +31 -0
  44. lm-quant-toolkit/.deps/hqq/hqq/engine/__init__.py +0 -0
  45. lm-quant-toolkit/.deps/hqq/hqq/engine/base.py +105 -0
  46. lm-quant-toolkit/.deps/hqq/hqq/engine/hf.py +73 -0
  47. lm-quant-toolkit/.deps/hqq/hqq/engine/open_clip.py +112 -0
  48. lm-quant-toolkit/.deps/hqq/hqq/engine/timm.py +67 -0
  49. lm-quant-toolkit/.deps/hqq/hqq/engine/vllm.py +149 -0
  50. lm-quant-toolkit/.deps/hqq/hqq/kernels/__init__.py +0 -0
lm-quant-toolkit/.deps/CLIP_benchmark/clip_benchmark/datasets/cupl_prompts.json ADDED
The diff for this file is too large to render. See raw diff
 
lm-quant-toolkit/.deps/CLIP_benchmark/probe_benchmark/scaling_experiment_data2.json ADDED
The diff for this file is too large to render. See raw diff
 
lm-quant-toolkit/.deps/hqq/examples/hf/llama2_chat_hf_hub_example.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model_id = 'mobiuslabsgmbh/Llama-2-7b-chat-hf-4bit_g64-HQQ'
2
+ #model_id = 'mobiuslabsgmbh/Llama-2-13b-chat-hf-4bit_g64-HQQ'
3
+ #model_id = 'mobiuslabsgmbh/Llama-2-70b-chat-hf-2bit_g16_s128-HQQ'
4
+
5
+ from hqq.engine.hf import HQQModelForCausalLM, AutoTokenizer
6
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
7
+ model = HQQModelForCausalLM.from_quantized(model_id)
8
+
9
+ ##########################################################################################################
10
+ import transformers
11
+ from threading import Thread
12
+
13
+ from sys import stdout
14
+ def print_flush(data):
15
+ stdout.write("\r" + data)
16
+ stdout.flush()
17
+
18
+ #Adapted from https://huggingface.co/spaces/huggingface-projects/llama-2-7b-chat/blob/main/app.py
19
+ def process_conversation(chat):
20
+ system_prompt = chat['system_prompt']
21
+ chat_history = chat['chat_history']
22
+ message = chat['message']
23
+
24
+ conversation = []
25
+ if system_prompt:
26
+ conversation.append({"role": "system", "content": system_prompt})
27
+ for user, assistant in chat_history:
28
+ conversation.extend([{"role": "user", "content": user}, {"role": "assistant", "content": assistant}])
29
+ conversation.append({"role": "user", "content": message})
30
+
31
+ return tokenizer.apply_chat_template(conversation, return_tensors="pt").to('cuda')
32
+
33
+ def chat_processor(chat, max_new_tokens=100, do_sample=True):
34
+ tokenizer.use_default_system_prompt = False
35
+ streamer = transformers.TextIteratorStreamer(tokenizer, timeout=10.0, skip_prompt=True, skip_special_tokens=True)
36
+
37
+ generate_params = dict(
38
+ {"input_ids": process_conversation(chat)},
39
+ streamer=streamer,
40
+ max_new_tokens=max_new_tokens,
41
+ do_sample=do_sample,
42
+ top_p=0.90,
43
+ top_k=50,
44
+ temperature= 0.6,
45
+ num_beams=1,
46
+ repetition_penalty=1.2,
47
+ )
48
+
49
+ t = Thread(target=model.generate, kwargs=generate_params)
50
+ t.start()
51
+
52
+ outputs = []
53
+ for text in streamer:
54
+ outputs.append(text)
55
+ print_flush("".join(outputs))
56
+
57
+ return outputs
58
+
59
+ ###################################################################################################
60
+
61
+ outputs = chat_processor({'system_prompt':"You are a helpful assistant.",
62
+ 'chat_history':[],
63
+ 'message':"How can I build a car?"
64
+ },
65
+ max_new_tokens=1000, do_sample=False)
lm-quant-toolkit/.deps/hqq/examples/hf/whisper.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tested with torch nightly, 4090
2
+ # pip uninstall torch -y; pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu121
3
+ ##############################################################################################
4
+
5
+ import torch
6
+ from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline
7
+
8
+ model_id = "openai/whisper-medium"
9
+ #model_id = "distil-whisper/distil-large-v3"
10
+
11
+ compute_dtype = torch.bfloat16
12
+ device = "cuda:0"
13
+
14
+ model = AutoModelForSpeechSeq2Seq.from_pretrained(model_id, torch_dtype=compute_dtype)
15
+ processor = AutoProcessor.from_pretrained(model_id)
16
+
17
+
18
+ ##############################################################################
19
+ #No quantize
20
+ #model = model.to(device)
21
+
22
+ ##############################################################################
23
+ #Quantize
24
+ from hqq.models.hf.base import AutoHQQHFModel
25
+ from hqq.core.quantize import *
26
+
27
+ quant_config = BaseQuantizeConfig(nbits=4, group_size=64, quant_scale=False, quant_zero=False, axis=1)
28
+ HQQLinear.set_backend(HQQBackend.PYTORCH)
29
+
30
+ AutoHQQHFModel.quantize_model(model.model.encoder, quant_config=quant_config, compute_dtype=compute_dtype, device=device)
31
+ AutoHQQHFModel.quantize_model(model.model.decoder, quant_config=quant_config, compute_dtype=compute_dtype, device=device)
32
+
33
+ from hqq.utils.patching import prepare_for_inference
34
+ prepare_for_inference(model.model.encoder)
35
+ prepare_for_inference(model.model.decoder, backend="torchao_int4")
36
+
37
+ model.model.encoder.forward = torch.compile(model.model.encoder.forward, mode="reduce-overhead", fullgraph=True)
38
+ model.model.decoder.forward = torch.compile(model.model.decoder.forward, mode="reduce-overhead", fullgraph=True)
39
+ # ##############################################################################
40
+
41
+ import time
42
+ import numpy as np
43
+
44
+ if(model_id=="openai/whisper-medium"):
45
+ encoder_input = torch.randn([1, 80, 3000], dtype=compute_dtype, device=device)
46
+ if(model_id=="distil-whisper/distil-large-v3"):
47
+ encoder_input = torch.randn([1, 128, 3000], dtype=compute_dtype, device=device)
48
+
49
+ def run_encoder():
50
+ with torch.no_grad():
51
+ model.model.encoder(encoder_input)
52
+ torch.cuda.synchronize()
53
+
54
+ t = []
55
+ for _ in range(200):
56
+ t1 = time.time()
57
+ run_encoder()
58
+ t2 = time.time()
59
+ t.append(t2-t1)
60
+ print("Encoder", np.mean(t[-100:]), "sec / sample")
61
+
62
+
63
+ decoder_input = torch.randint(0, 1000, [1, 1], dtype=torch.int64, device=device)
64
+ def run_decoder():
65
+ with torch.no_grad():
66
+ out = model.model.decoder(decoder_input)
67
+ torch.cuda.synchronize()
68
+
69
+
70
+ t = []
71
+ for _ in range(200):
72
+ t1 = time.time()
73
+ run_decoder()
74
+ t2 = time.time()
75
+ t.append(t2-t1)
76
+ print("Decoder", np.mean(t[-100:]), "sec / sample")
77
+
78
+
79
+ #openai/whisper-medium | RTX 4090
80
+ #Encoder: use default backend
81
+ #fp16 : 0.0234 sec / sample
82
+ #hqq 4-bit (default,compiled) : 0.0124 sec / sample | 1.89x faster
83
+
84
+
85
+ #Decoder: use torchao backend to decode 1 token at a time
86
+ #fp16 : 0.01080 sec / sample
87
+ #hqq 4-bit (ao_int4, compiled): 0.000928 sec / sample | 11.63x faster
88
+
89
+
90
+ #distil-whisper/distil-large-v3 | RTX 4090
91
+ #Encoder: use default backend
92
+ #fp16 : 0.03738 sec / sample
93
+ #hqq 4-bit (default,compiled) : 0.01869 sec / sample | 2x faster
94
+
95
+
96
+ #Decoder: use torchao backend to decode 1 token at a time
97
+ #fp16 : 0.002592 sec / sample
98
+ #hqq 4-bit (ao_int4, compiled): 0.000326 sec / sample | 7.95x faster
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ snapshots/
2
+ snapshots-*/
3
+ results/
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/.pdbrc ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # b hqq/core/quantize.py:677
2
+ # c
3
+ # b eval_model.py:34
4
+ # b bench.py:221
5
+ # b hqq/models/base.py:132
6
+ # b quant_llama2_hqq_demo.py:30
7
+ # b hqq/models/base.py:265
8
+ # b debug-quant-mem.py:18
9
+ # b hqq/models/hf/llama.py:71
10
+ # b hqq/models/base.py:260
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/adapter/autoawq.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import transformers
4
+
5
+ from awq import AutoAWQForCausalLM
6
+
7
+
8
+ def create_autoawq_model(model_id, quant_config, config_id, load_quantized, save_dir):
9
+ quantized = False
10
+ quant_path = f"{save_dir}/{model_id}-{config_id}-awq"
11
+ if load_quantized and os.path.exists(quant_path):
12
+ model = AutoAWQForCausalLM.from_quantized(quant_path, "", fuse_layers=False)
13
+ tokenizer = transformers.AutoTokenizer.from_pretrained(model_id)
14
+ quantized = True
15
+ model = model.cuda()
16
+ else:
17
+ tokenizer = transformers.AutoTokenizer.from_pretrained(model_id)
18
+ model = AutoAWQForCausalLM.from_pretrained(model_id)
19
+ return model, tokenizer, quantized
20
+
21
+
22
+ def quantize_autoawq_model(model, tokenizer, quant_config, model_id, config_id, save_dir):
23
+ t1 = time.time()
24
+ model.quantize(tokenizer, quant_config=quant_config)
25
+ t2 = time.time()
26
+ print('Took ' + str(t2 - t1) + ' seconds to quantize the model with AutoAWQ')
27
+ quant_path = f"{save_dir}/{model_id}-{config_id}-awq"
28
+ model.save_quantized(quant_path)
29
+ tokenizer.save_pretrained(quant_path)
30
+ return model, t2 - t1
31
+
32
+
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/adapter/awq.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import torch
4
+
5
+ from transformers import AutoModelForCausalLM
6
+ from transformers import AutoTokenizer
7
+ from transformers import AutoConfig
8
+ from accelerate import (
9
+ init_empty_weights,
10
+ infer_auto_device_map,
11
+ load_checkpoint_in_model,
12
+ )
13
+
14
+ from awq.quantize.pre_quant import run_awq
15
+ from awq.quantize.pre_quant import apply_awq
16
+ from awq.quantize.quantizer import real_quantize_model_weight
17
+ from awq.utils.utils import simple_dispatch_model
18
+
19
+
20
+ max_memory = {}
21
+
22
+
23
+ def create_awq_model(model_id, quant_config, config_id, load_quantized, save_dir):
24
+ quantized = False
25
+ quant_path = f"{save_dir}/{model_id}-{config_id}-awq"
26
+
27
+ tokenizer = AutoTokenizer.from_pretrained(
28
+ model_id, use_fast=False, trust_remote_code=True
29
+ )
30
+ config = AutoConfig.from_pretrained(model_id, trust_remote_code=True)
31
+ # Note (Haotian): To avoid OOM after huggingface transformers 4.36.2
32
+ config.use_cache = False
33
+ if load_quantized and os.path.exists(f"{quant_path}/qmodel.pth"):
34
+ with init_empty_weights():
35
+ model = AutoModelForCausalLM.from_config(
36
+ config=config, torch_dtype=torch.float16, trust_remote_code=True
37
+ )
38
+ # Infer device map
39
+ kwargs = {"max_memory": max_memory} if len(max_memory) else {}
40
+ device_map = infer_auto_device_map(
41
+ model,
42
+ no_split_module_classes=[
43
+ "OPTDecoderLayer",
44
+ "LlamaDecoderLayer",
45
+ "BloomBlock",
46
+ "MPTBlock",
47
+ "DecoderLayer",
48
+ ],
49
+ **kwargs,
50
+ )
51
+ # Load checkpoint in the model
52
+ load_checkpoint_in_model(
53
+ model,
54
+ checkpoint=quant_path,
55
+ device_map=device_map,
56
+ offload_state_dict=True,
57
+ )
58
+ # Dispatch model
59
+ model = simple_dispatch_model(model, device_map=device_map)
60
+ quantized = True
61
+ model.eval()
62
+ else:
63
+ kwargs = {"torch_dtype": torch.float16, "low_cpu_mem_usage": True}
64
+ model = AutoModelForCausalLM.from_pretrained(
65
+ model_id, config=config, trust_remote_code=True, **kwargs
66
+ )
67
+ return model, tokenizer, quantized
68
+
69
+
70
+ def quantize_awq_model(model, tokenizer, quant_config, model_id, config_id, save_dir):
71
+ t1 = time.time()
72
+ nbits = quant_config.pop('w_bit')
73
+ awq_results = run_awq(
74
+ model,
75
+ tokenizer,
76
+ w_bit=nbits,
77
+ q_config=quant_config,
78
+ n_samples=128,
79
+ seqlen=512,
80
+ )
81
+ intermediate_fp = f"{save_dir}/{model_id}-{config_id}-awq/intermediate.pth"
82
+ dirpath = os.path.dirname(intermediate_fp)
83
+ os.makedirs(dirpath, exist_ok=True)
84
+ torch.save(awq_results, intermediate_fp)
85
+ awq_results = torch.load(intermediate_fp, map_location="cpu")
86
+ apply_awq(model, awq_results)
87
+ real_quantize_model_weight(model, w_bit=nbits, q_config=quant_config)
88
+
89
+ t2 = time.time()
90
+ print('Took ' + str(t2 - t1) + ' seconds to quantize the model with AWQ')
91
+ quant_path = f"{save_dir}/{model_id}-{config_id}-awq"
92
+ torch.save(model.cpu().state_dict(), f"{quant_path}/qmodel.pth")
93
+ tokenizer.save_pretrained(quant_path)
94
+ return model, t2 - t1
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Llama-2-13b-hf.csv ADDED
The diff for this file is too large to render. See raw diff
 
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Llama-2-70b-hf.csv ADDED
The diff for this file is too large to render. See raw diff
 
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Llama-2-7b-hf.csv ADDED
The diff for this file is too large to render. See raw diff
 
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/data/fnorm-Meta-Llama-3.1-405B-Instruct.csv ADDED
The diff for this file is too large to render. See raw diff
 
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/debug-bench.sh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ python -m pdb bench.py
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/eval_model.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gc
2
+ import time
3
+
4
+ import numpy as np
5
+ import torch
6
+ from datasets import load_dataset
7
+ from tqdm import tqdm
8
+
9
+
10
+ def cleanup():
11
+ torch.cuda.empty_cache()
12
+ gc.collect()
13
+
14
+
15
+ def eval_ptb(model, tokenizer, max_length=1024, stride=512, verbose=True):
16
+ dataset = load_dataset("ptb_text_only", "penn_treebank", split="test")
17
+ return eval_ppl(
18
+ "ptb",
19
+ model,
20
+ tokenizer,
21
+ dataset,
22
+ text_column="sentence",
23
+ max_length=max_length,
24
+ stride=stride,
25
+ verbose=verbose,
26
+ )
27
+
28
+
29
+ def eval_c4(model, tokenizer, max_length=1024, stride=512, verbose=True):
30
+ dataset = load_dataset(
31
+ "allenai/c4",
32
+ data_files={"validation": "en/c4-validation.00000-of-00008.json.gz"},
33
+ split="validation",
34
+ download_mode="reuse_dataset_if_exists",
35
+ )
36
+ # pick first 1100
37
+ dataset = dataset[:1100]
38
+ return eval_ppl(
39
+ "C4",
40
+ model,
41
+ tokenizer,
42
+ dataset,
43
+ text_column="text",
44
+ max_length=max_length,
45
+ stride=stride,
46
+ verbose=verbose,
47
+ )
48
+
49
+
50
+ def eval_wikitext2(model, tokenizer, max_length=1024, stride=512, verbose=True):
51
+ dataset = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
52
+ return eval_ppl(
53
+ "wikitext",
54
+ model,
55
+ tokenizer,
56
+ dataset,
57
+ text_column="text",
58
+ max_length=max_length,
59
+ stride=stride,
60
+ verbose=verbose,
61
+ )
62
+
63
+
64
+ # Adapted from https://huggingface.co/transformers/v4.2.2/perplexity.html
65
+ def eval_ppl(
66
+ ds_type,
67
+ model,
68
+ tokenizer,
69
+ dataset,
70
+ text_column="text",
71
+ max_length=1024,
72
+ stride=512,
73
+ verbose=True,
74
+ ):
75
+ model.eval()
76
+ tokenizer.pad_token = tokenizer.eos_token
77
+ tokenizer.padding_side = "right"
78
+ tokenizer.add_eos_token = False
79
+
80
+ encodings = tokenizer("\n\n".join(dataset[text_column]), return_tensors="pt")
81
+
82
+ encodings["input_ids"] = encodings["input_ids"].to("cuda")
83
+
84
+ lls, t = [], []
85
+ for i in tqdm(
86
+ range(0, encodings["input_ids"].size(1), stride),
87
+ desc=ds_type,
88
+ disable=not verbose,
89
+ ):
90
+ begin_loc = max(i + stride - max_length, 0)
91
+ end_loc = min(i + stride, encodings["input_ids"].size(1))
92
+ trg_len = end_loc - i
93
+ input_ids = encodings["input_ids"][:, begin_loc:end_loc]
94
+ target_ids = input_ids.clone()
95
+ target_ids[:, :-trg_len] = -100 # ignore context
96
+
97
+ t1 = time.time()
98
+ with torch.no_grad():
99
+ log_likelihood = model(input_ids, labels=target_ids).loss * trg_len
100
+ torch.cuda.synchronize()
101
+ t2 = time.time()
102
+ t.append((t2 - t1))
103
+ lls.append(log_likelihood)
104
+
105
+ del input_ids, target_ids
106
+
107
+ ppl = np.round(float(torch.exp(torch.stack(lls).sum() / end_loc)), 4)
108
+ pred_time = np.round(np.mean(t), 3)
109
+ if verbose:
110
+ print(f"{ds_type} perplexity: {ppl}, time: {pred_time} sec")
111
+
112
+ del encodings
113
+ cleanup()
114
+
115
+ return ppl, pred_time
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/fp16_llama2_demo.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+ from transformers import AutoModelForCausalLM
4
+ from transformers import AutoTokenizer
5
+ from eval_model import eval_wikitext2
6
+
7
+ #Settings
8
+ ######################################################################################
9
+ hf_auth = None #HuggingFace token
10
+ cache_path = '' #cache directory to store data
11
+
12
+ #Chose a model
13
+ # model_id = "meta-llama/Llama-2-7b-hf"
14
+ # model_id = "meta-llama/Meta-Llama-3-8B"
15
+ model_id = "meta-llama/Llama-2-13b-hf"
16
+ #model_id = "meta-llama/Llama-2-70b-hf"
17
+
18
+ #Load model on the CPU
19
+ ######################################################################################
20
+ model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", torch_dtype=torch.float16)
21
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
22
+
23
+ #Evaluate the quantized model
24
+ ######################################################################################
25
+ eval_wikitext2(model, tokenizer, verbose=True)
26
+
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/quant_llama2_awq_demo.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch, transformers
2
+
3
+ #Settings
4
+ ######################################################################################
5
+ hf_auth = None #HuggingFace token
6
+ cache_path = '' #cache directory to store data
7
+
8
+ #Chose a model
9
+ # model_id = "meta-llama/Meta-Llama-3-8B"
10
+ # model_id = "meta-llama/Llama-2-7b-hf"
11
+ model_id = "meta-llama/Llama-2-13b-hf"
12
+ #model_id = "meta-llama/Llama-2-70b-hf"
13
+
14
+ #AWQ settings
15
+ ######################################################################################
16
+ from awq import AutoAWQForCausalLM
17
+ import gc, time
18
+
19
+ # Load model
20
+ tokenizer = transformers.AutoTokenizer.from_pretrained(model_id, use_auth_token=hf_auth)
21
+ model = AutoAWQForCausalLM.from_pretrained(model_id, use_auth_token=hf_auth, resume_download=True)
22
+
23
+ #quant_config = {"w_bit": 4, "q_group_size": 128, "zero_point": True, 'version':'GEMM'}
24
+ #quant_config = {"w_bit": 4, "q_group_size": 64, "zero_point": True, 'version':'GEMM'}
25
+ quant_config = {"w_bit": 3, "q_group_size": 64, "zero_point": True, 'version':'gemv_fast'}
26
+
27
+ t1 = time.time()
28
+ model.quantize(tokenizer, quant_config=quant_config)
29
+ t2 = time.time()
30
+ print('Took ' + str(t2-t1) + ' seconds to quantize the model with AWQ')
31
+
32
+ model = model.cuda()
33
+ torch.cuda.empty_cache()
34
+ gc.collect()
35
+
36
+ #Evaluate the quantized model
37
+ ######################################################################################
38
+ from eval_model import eval_wikitext2
39
+ eval_wikitext2(model, tokenizer, verbose=True)
40
+
lm-quant-toolkit/.deps/hqq/examples/llama2_benchmark/run-bench.sh ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # export HF_HOME=/data/hugginface
4
+
5
+ if [ ! -d logs ]; then
6
+ mkdir logs
7
+ fi
8
+ python bench.py 2>&1 | tee logs/bench-$(date +%Y%m%d%H%M%S).log
lm-quant-toolkit/.deps/hqq/examples/lora/train_hqq_lora_example.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #Settings
2
+ ######################################################################################
3
+ hf_auth = None #HuggingFace token
4
+ cache_path = '' #cache directory to store data
5
+
6
+ #Chose a model
7
+ model_id = "meta-llama/Llama-2-7b-hf"
8
+ #model_id = "meta-llama/Llama-2-13b-hf"
9
+ #model_id = "meta-llama/Llama-2-70b-hf"
10
+
11
+ #HQQ Quantize
12
+ ######################################################################################
13
+ from hqq.engine.hf import HQQModelForCausalLM, AutoTokenizer
14
+ model = HQQModelForCausalLM.from_pretrained(model_id, use_auth_token=hf_auth, cache_dir=cache_path)
15
+ tokenizer = AutoTokenizer.from_pretrained(model_id, use_auth_token=hf_auth, cache_dir=cache_path)
16
+
17
+ #Quantize the model
18
+ from hqq.core.quantize import *
19
+ quant_config = BaseQuantizeConfig(nbits=4, group_size=64, quant_scale=False, quant_zero=False)
20
+ model.quantize_model(quant_config=quant_config)
21
+
22
+ #Add Peft
23
+ ######################################################################################
24
+ from hqq.core.peft import PeftUtils
25
+ from hqq.core.quantize import *
26
+
27
+ train_dtype = torch.float32
28
+ base_lora_params = {'lora_type':'default', 'r':32, 'lora_alpha':64, 'dropout':0.05, 'train_dtype':train_dtype}
29
+ lora_params = {'self_attn.q_proj': base_lora_params,
30
+ 'self_attn.k_proj': base_lora_params,
31
+ 'self_attn.v_proj': base_lora_params,
32
+ 'self_attn.o_proj': base_lora_params,
33
+ 'mlp.gate_proj' : None,
34
+ 'mlp.up_proj' : None,
35
+ 'mlp.down_proj' : None}
36
+
37
+ #Apply LoRA
38
+ PeftUtils.add_lora(model, lora_params)
39
+
40
+ #Dataset
41
+ ######################################################################################
42
+ from datasets import load_dataset, Dataset
43
+ from tqdm import tqdm
44
+ import transformers
45
+ import numpy as np
46
+ import random
47
+
48
+ tokenizer.pad_token = tokenizer.eos_token
49
+ tokenizer.padding_side = "right"
50
+ tokenizer.add_bos_token = False
51
+ tokenizer.add_eos_token = False
52
+
53
+ batch_size = 1
54
+ num_epochs = 1
55
+ grad_acc = 1
56
+ max_tokens = 256
57
+ max_samples = 5000
58
+
59
+ #OpenAssistant
60
+ ##########################################################################
61
+ dataset = load_dataset("timdettmers/openassistant-guanaco", split="train")
62
+ dataset_val = load_dataset("timdettmers/openassistant-guanaco", split="test")
63
+
64
+ def pre_process_chat(chat):
65
+ #add proper chat preprocessing (bos/eos tokens, etc.)
66
+ return chat
67
+
68
+ def assitant_prompt(prompt):
69
+ return '### Human:' + prompt + '\n### Assistant:'
70
+
71
+
72
+ random.seed(100)
73
+ idx = random.sample(range(len(dataset)), min(max_samples, len(dataset)))
74
+ dataset = Dataset.from_dict({'text':[pre_process_chat(dataset[i]['text']) for i in tqdm(idx)]})
75
+ dataset_val = Dataset.from_dict({'text':[pre_process_chat(dataset_val[i]['text']) for i in range(len(dataset_val))]})
76
+
77
+ #####################################################################################
78
+ #Train
79
+ from trl import SFTTrainer
80
+
81
+ grad_acc = 2
82
+ logging_st = 1
83
+ max_steps = -1
84
+ lr = 1e-4
85
+ batch_size = 1
86
+ n_epochs = 1
87
+
88
+ training_args = transformers.TrainingArguments(
89
+ output_dir='.',
90
+ per_device_train_batch_size=batch_size,
91
+ #per_device_eval_batch_size=batch_size,
92
+ gradient_accumulation_steps=grad_acc,
93
+ learning_rate=lr,
94
+ logging_steps=logging_st,
95
+ num_train_epochs=n_epochs,
96
+ max_steps=max_steps,
97
+ #evaluation_strategy = "epoch",
98
+ remove_unused_columns=False,
99
+ #logging_strategy="epoch",
100
+ fp16=train_dtype==torch.float32,
101
+ max_grad_norm=1.0,
102
+ save_steps=10000000,
103
+ lr_scheduler_type= "linear",
104
+ )
105
+
106
+ #Wrap model to avoid accelerate issues
107
+ class WrappedModel(torch.nn.Module):
108
+ def __init__(self, model):
109
+ super().__init__()
110
+ self.model = model
111
+
112
+ def forward(self, *args, **kwargs):
113
+ return self.model.forward(*args, **kwargs)
114
+
115
+ def train(self):
116
+ self.model.train()
117
+
118
+ def eval(self):
119
+ self.model.eval()
120
+
121
+ def parameters(self):
122
+ return self.model.parameters()
123
+
124
+ trainer = SFTTrainer(
125
+ model=WrappedModel(model),
126
+ tokenizer=tokenizer,
127
+ max_seq_length=max_tokens,
128
+ train_dataset=dataset,
129
+ eval_dataset=None,
130
+ peft_config=None,
131
+ args=training_args,
132
+ dataset_text_field="text",
133
+ )
134
+
135
+ model.is_parallelizable = False
136
+ trainer.is_model_parallel = False
137
+ trainer.place_model_on_device = False
138
+
139
+ model.train()
140
+ trainer.train()
141
+
142
+ #Prediction/Eval
143
+ ######################################################################################
144
+ #from #https://huggingface.co/spaces/evaluate-metric/perplexity/blob/main/perplexity.py
145
+ def compute_perplexity_batched(model, tokenizer, predictions, encodings=None, batch_size=1, add_start_token=True, device='cuda', max_length=None):
146
+ if tokenizer.pad_token is None and batch_size > 1:
147
+ existing_special_tokens = list(tokenizer.special_tokens_map_extended.values())
148
+ # check that the model already has at least one special token defined
149
+ assert (len(existing_special_tokens) > 0), "If batch_size > 1, model must have at least one special token to use for padding. Please use a different model or set batch_size=1."
150
+ # assign one of the special tokens to also be the pad token
151
+ tokenizer.add_special_tokens({"pad_token": existing_special_tokens[0]})
152
+
153
+ if add_start_token and max_length:
154
+ # leave room for <BOS> token to be added:
155
+ assert (tokenizer.bos_token is not None), "Input model must already have a BOS token if using add_start_token=True. Please use a different model, or set add_start_token=False"
156
+ max_tokenized_len = max_length - 1
157
+ else:
158
+ max_tokenized_len = max_length
159
+
160
+
161
+ if(encodings is None):
162
+ encodings = tokenizer(
163
+ predictions,
164
+ add_special_tokens=False,
165
+ padding=True,
166
+ truncation=True if max_tokenized_len else False,
167
+ max_length=max_tokenized_len,
168
+ return_tensors="pt",
169
+ return_attention_mask=True).to(device)
170
+
171
+ encoded_texts = encodings["input_ids"]
172
+ attn_masks = encodings["attention_mask"]
173
+
174
+ # check that each input is long enough:
175
+ if add_start_token:
176
+ assert torch.all(torch.ge(attn_masks.sum(1), 1)), "Each input text must be at least one token long."
177
+ else:
178
+ assert torch.all(
179
+ torch.ge(attn_masks.sum(1), 2)
180
+ ), "When add_start_token=False, each input text must be at least two tokens long. Run with add_start_token=True if inputting strings of only one token, and remove all empty input strings."
181
+
182
+ ppls = []
183
+ loss_fct = torch.nn.CrossEntropyLoss(reduction="none")
184
+
185
+ for start_index in tqdm(range(0, len(encoded_texts), batch_size)):
186
+ end_index = min(start_index + batch_size, len(encoded_texts))
187
+ encoded_batch = encoded_texts[start_index:end_index]
188
+ attn_mask = attn_masks[start_index:end_index]
189
+
190
+ if add_start_token:
191
+ bos_tokens_tensor = torch.tensor([[tokenizer.bos_token_id]] * encoded_batch.size(dim=0)).to(device)
192
+ encoded_batch = torch.cat([bos_tokens_tensor, encoded_batch], dim=1)
193
+ attn_mask = torch.cat([torch.ones(bos_tokens_tensor.size(), dtype=torch.int64).to(device), attn_mask], dim=1)
194
+
195
+ labels = encoded_batch
196
+
197
+ with torch.no_grad():
198
+ out_logits = model(encoded_batch, attention_mask=attn_mask).logits
199
+
200
+ shift_logits = out_logits[..., :-1, :].contiguous()
201
+ shift_labels = labels[..., 1:].contiguous()
202
+ shift_attention_mask_batch = attn_mask[..., 1:].contiguous()
203
+
204
+ perplexity_batch = torch.exp(
205
+ (loss_fct(shift_logits.transpose(1, 2), shift_labels) * shift_attention_mask_batch).sum(1)
206
+ / shift_attention_mask_batch.sum(1))
207
+
208
+ ppls += perplexity_batch.tolist()
209
+
210
+ return np.mean(ppls)
211
+
212
+
213
+ tokenizer.add_bos_token = True
214
+ tokenizer.add_eos_token = False
215
+ model.eval()
216
+
217
+ #Convert lora weights to the same model dtype for faster inference
218
+ PeftUtils.cast_lora_weights(model, dtype=torch.half)
219
+
220
+ print('perplexity', compute_perplexity_batched(model=model, tokenizer=tokenizer, predictions=[s['text'] for s in dataset_val], batch_size=1, max_length=max_tokens))
lm-quant-toolkit/.deps/hqq/examples/open_clip/.pdbrc ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # b /home/justin/work/hqq/hqq/engine/open_clip.py:57
2
+ # b /home/justin/work/hqq/hqq/models/open_clip/base.py:77
3
+ # b /home/justin/work/hqq/examples/open_clip/vit_clip_example.py:27
4
+ b /home/justin/work/hqq/examples/open_clip/vit_clip_example.py:62
lm-quant-toolkit/.deps/hqq/examples/open_clip/vit_clip_example.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+
4
+ import open_clip
5
+ import torch
6
+ from open_clip import tokenizer
7
+ from PIL import Image
8
+ from skimage import data_dir
9
+
10
+ from hqq.core.quantize import BaseQuantizeConfig
11
+ from hqq.engine.open_clip import HQQOpenCLIP
12
+
13
+ model_ids = [
14
+ "laion/CLIP-ViT-B-16-laion2B-s34B-b88K",
15
+ "laion/CLIP-ViT-B-32-laion2B-s34B-b79K",
16
+ "laion/CLIP-ViT-H-14-laion2B-s32B-b79K",
17
+ "laion/CLIP-ViT-L-14-laion2B-s32B-b82K",
18
+ ]
19
+
20
+
21
+ def quant_models(model_ids):
22
+ for model_id in model_ids:
23
+ model = HQQOpenCLIP.create_model(model_id, device="cpu")
24
+
25
+ # Quantize settings
26
+ # quant_config = BaseQuantizeConfig(nbits=8, group_size=128)
27
+ quant_config = BaseQuantizeConfig(nbits=4, group_size=64)
28
+ # quant_config = BaseQuantizeConfig(nbits=3, group_size=64)
29
+ # quant_config = BaseQuantizeConfig(nbits=2, group_size=16, quant_scale=True)
30
+
31
+ # Quantize
32
+ model.quantize_model(quant_config=quant_config)
33
+
34
+ # Save model
35
+ save_dir = "snapshots/" + model_id
36
+ Path(save_dir).mkdir(parents=True, exist_ok=True)
37
+ model.save_quantized(save_dir=save_dir)
38
+
39
+
40
+ def load_quantized(model_id):
41
+ # Load model
42
+ save_dir = "snapshots/" + model_id
43
+ model = HQQOpenCLIP.from_quantized(save_dir)
44
+ return model
45
+
46
+
47
+ def compare_weights_raw(model_id):
48
+ qnt_pt_file = "snapshots/" + model_id + "/qmodel.pt"
49
+ ref_pt_file = "/home/justin/.cache/huggingface/hub/models--laion--CLIP-ViT-H-14-laion2B-s32B-b79K/snapshots/de081ac0a0ca8dc9d1533eed1ae884bb8ae1404b/open_clip_pytorch_model.bin"
50
+ qnt = torch.load(qnt_pt_file)
51
+ ref = torch.load(ref_pt_file)
52
+ print("*" * 72)
53
+ print("from quantized file")
54
+ for k in qnt:
55
+ print(k)
56
+ print("*" * 72)
57
+ print("from original file")
58
+ for k in ref:
59
+ print(k)
60
+
61
+
62
+ def compare_weights(model_id):
63
+ model, model_ref, _ = create_model_dual(model_id)
64
+ dict1 = dict(model.named_parameters())
65
+ dict2 = dict(model_ref.named_parameters())
66
+ for name, param in dict1.items():
67
+ param_ref = dict2.get(name, None)
68
+ if param_ref is not None:
69
+ if not torch.allclose(param_ref.data, param.data, rtol=0.0, equal_nan=True):
70
+ print(f"weight differs: {name}")
71
+ if name == "text_projection":
72
+ print(param)
73
+ print(param_ref)
74
+ else:
75
+ print(f"weight same: {name}")
76
+ else:
77
+ print(f"not in ref model: {name}")
78
+
79
+
80
+ def create_model_dual(model_id, mask=3):
81
+ model = None
82
+ model_ref = None
83
+ preprocess = None
84
+
85
+ if mask & 1:
86
+ model = load_quantized(model_id)
87
+ model = model.half().cuda()
88
+
89
+ # Load reference model to compare with
90
+ if mask & 2:
91
+ comps = model_id.split("/")
92
+ elems = comps[1].split("-")
93
+ model_name = "-".join(elems[1:4])
94
+ pretrained = "-".join(elems[4:])
95
+ model_ref, _, preprocess = open_clip.create_model_and_transforms(
96
+ model_name, pretrained=pretrained
97
+ )
98
+ model_ref = model_ref.half().cuda()
99
+ return model, model_ref, preprocess
100
+
101
+
102
+ def create_and_quant_model(model_id):
103
+ model = HQQOpenCLIP.create_model(model_id, device="cpu")
104
+ # Quantize settings
105
+ # quant_config = BaseQuantizeConfig(nbits=8, group_size=128)
106
+ quant_config = BaseQuantizeConfig(nbits=4, group_size=64)
107
+ # quant_config = BaseQuantizeConfig(nbits=3, group_size=64)
108
+ # quant_config = BaseQuantizeConfig(nbits=2, group_size=16, quant_scale=True)
109
+ # Quantize
110
+ model.quantize_model(quant_config=quant_config)
111
+ model = model.half().cuda()
112
+ return model
113
+
114
+
115
+ def compare(model_id):
116
+ model = create_and_quant_model(model_id)
117
+ _, model_ref, preprocess = create_model_dual(model_id, mask=2)
118
+ model.eval()
119
+ model_ref.eval()
120
+
121
+ descriptions = {
122
+ "page": "a page of text about segmentation",
123
+ "chelsea": "a facial photo of a tabby cat",
124
+ "astronaut": "a portrait of an astronaut with the American flag",
125
+ "rocket": "a rocket standing on a launchpad",
126
+ "motorcycle_right": "a red motorcycle standing in a garage",
127
+ "camera": "a person looking at a camera on a tripod",
128
+ "horse": "a black-and-white silhouette of a horse",
129
+ "coffee": "a cup of coffee on a saucer",
130
+ }
131
+ texts = descriptions.values()
132
+ text_processed = tokenizer.tokenize(texts).cuda()
133
+
134
+ # preprocess image and text
135
+ img = Image.open(os.path.join(data_dir, "astronaut.png")).convert("RGB")
136
+ img_preprocessed = preprocess(img).cuda().unsqueeze(0)
137
+
138
+ with torch.amp.autocast("cuda"):
139
+ img_embedding, text_embedding, _ = model_ref(img_preprocessed, text_processed)
140
+ probs = (100 * img_embedding @ text_embedding.T).softmax(dim=-1)
141
+ print(probs)
142
+
143
+ with torch.amp.autocast("cuda"):
144
+ img_embedding, text_embedding, _ = model(img_preprocessed, text_processed)
145
+ probs = (100 * img_embedding @ text_embedding.T).softmax(dim=-1)
146
+ print(probs)
147
+
148
+
149
+ def main():
150
+ # quant_models(model_ids)
151
+ # load_quantized(model_ids[0])
152
+ compare(model_ids[2])
153
+ # compare_weights(model_ids[2])
154
+ # compare_weights_raw(model_ids[2])
155
+
156
+
157
+ if __name__ == "__main__":
158
+ main()
lm-quant-toolkit/.deps/hqq/examples/timm/vit_clip_example.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import timm
3
+ import torch
4
+
5
+ from hqq.core.quantize import BaseQuantizeConfig
6
+ from hqq.engine.timm import HQQtimm
7
+
8
+ # Model
9
+ # model_id = 'vit_base_patch32_clip_224.laion2b' #ViT-B-32
10
+ # model_id = 'vit_large_patch14_clip_224.laion2b'#ViT-L-14
11
+ model_id = "vit_huge_patch14_clip_224.laion2b" # ViT-H-14
12
+
13
+ # Load model (on CPU)
14
+ model = HQQtimm.create_model(model_id, pretrained=True)
15
+
16
+ # Quantize settings
17
+ # quant_config = BaseQuantizeConfig(nbits=8, group_size=128)
18
+ quant_config = BaseQuantizeConfig(nbits=4, group_size=64)
19
+ # quant_config = BaseQuantizeConfig(nbits=3, group_size=64)
20
+ # quant_config = BaseQuantizeConfig(nbits=2, group_size=16, quant_scale=True)
21
+
22
+ # Quantize
23
+ model.quantize_model(quant_config=quant_config)
24
+
25
+ ###############################################################
26
+ # #Save model
27
+ # save_dir = "repo/" + model_id
28
+ # model.save_quantized(model, save_dir=save_dir)
29
+
30
+ # #Load model
31
+ # model = HQQtimm.from_quantized(save_dir)
32
+ ###############################################################
33
+
34
+ # Load reference model to compare with
35
+ model_ref = timm.create_model(model_id, pretrained=True)
36
+ model_ref = model_ref.half().cuda()
37
+ model_ref.eval()
38
+
39
+ # Pre-processing
40
+ mean_clip = np.array([0.4815, 0.4578, 0.4082], "float32")
41
+ std_clip = np.array([0.2686, 0.2613, 0.2758], "float32")
42
+
43
+
44
+ def normalize_images_clip(data_np_in, BCHW=True):
45
+ data_t = (
46
+ torch.from_numpy(data_np_in).float()
47
+ if (type(data_np_in) is np.ndarray)
48
+ else data_np_in.float()
49
+ )
50
+ data_t = (data_t / 255.0 - mean_clip) / std_clip
51
+ data_t = data_t.swapaxes(2, 3).swapaxes(1, 2) if (BCHW) else data_t
52
+ return data_t
53
+
54
+
55
+ ###############################################################
56
+ # Compare the compressed model with the original
57
+ x = np.random.rand(16, 224, 224, 3)
58
+ x = normalize_images_clip(x).half().cuda()
59
+
60
+ # Quantize
61
+ with torch.no_grad():
62
+ y_q = model(x)
63
+ y_q /= torch.norm(y_q, p=2, dim=-1, keepdim=True)
64
+
65
+ # Full-precision
66
+ with torch.no_grad():
67
+ y_r = model_ref(x)
68
+ y_r /= torch.norm(y_r, p=2, dim=-1, keepdim=True)
69
+
70
+ # We want the dot product to be as close as possible to 1
71
+ print(
72
+ "Average dot-product score", float(torch.diag(torch.matmul(y_q, y_r.t())).mean())
73
+ ) # ~0.998 (ViT-H-14 @4bit)
lm-quant-toolkit/.deps/hqq/examples/vllm/llama2_example.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model_id = 'meta-llama/Llama-2-7b-chat-hf'
2
+
3
+ #Load VLLM un-quantized model
4
+ from hqq.engine.vllm import HQQLLM
5
+ model = HQQLLM(model=model_id)
6
+
7
+ #Quantize the model
8
+ from hqq.core.quantize import *
9
+ model.quantize_model(BaseQuantizeConfig(nbits=4, group_size=64))
10
+
11
+ #Optional: Save the model
12
+ #model.save_quantized(model_id.split('/')[-1] + '_quantized')
13
+
14
+ #Optional: Set backend
15
+ HQQLinear.set_backend(HQQBackend.PYTORCH_COMPILE) #set backend
16
+
17
+ #Generation
18
+ from vllm.entrypoints.llm import SamplingParams
19
+ sampling_params = SamplingParams(temperature=0.6, top_p=0.90, max_tokens=1000, repetition_penalty=1.2)
20
+
21
+ prompt = "How can I build a car?"
22
+
23
+ output = model.generate([prompt], sampling_params)[0]
24
+ print(output.prompt)
25
+ print(output.outputs[0].text)
lm-quant-toolkit/.deps/hqq/hqq.egg-info/PKG-INFO ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: hqq
3
+ Version: 0.1.7.post2
4
+ Summary: Half-Quadratic Quantization (HQQ)
5
+ Home-page: https://github.com/mobiusml/hqq/
6
+ Author: Dr. Hicham Badri
7
+ Author-email: hicham@mobiuslabs.com
8
+ License: Apache 2
9
+ License-File: LICENSE
10
+ Requires-Dist: numpy>=1.24.4
11
+ Requires-Dist: tqdm>=4.64.1
12
+ Requires-Dist: einops
13
+ Requires-Dist: accelerate
14
+ Requires-Dist: transformers>=4.36.1
15
+ Requires-Dist: huggingface_hub
16
+ Requires-Dist: termcolor
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: home-page
20
+ Dynamic: license
21
+ Dynamic: license-file
22
+ Dynamic: requires-dist
23
+ Dynamic: summary
lm-quant-toolkit/.deps/hqq/hqq.egg-info/SOURCES.txt ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ LICENSE
2
+ setup.py
3
+ hqq/__init__.py
4
+ hqq.egg-info/PKG-INFO
5
+ hqq.egg-info/SOURCES.txt
6
+ hqq.egg-info/dependency_links.txt
7
+ hqq.egg-info/requires.txt
8
+ hqq.egg-info/top_level.txt
9
+ hqq/backends/__init__.py
10
+ hqq/backends/marlin.py
11
+ hqq/backends/torchao.py
12
+ hqq/core/__init__.py
13
+ hqq/core/bitpack.py
14
+ hqq/core/optimize.py
15
+ hqq/core/peft.py
16
+ hqq/core/quantize.py
17
+ hqq/core/utils.py
18
+ hqq/engine/__init__.py
19
+ hqq/engine/base.py
20
+ hqq/engine/hf.py
21
+ hqq/engine/open_clip.py
22
+ hqq/engine/timm.py
23
+ hqq/engine/vllm.py
24
+ hqq/kernels/__init__.py
25
+ hqq/kernels/hqq_aten_cuda.cpp
26
+ hqq/kernels/hqq_aten_cuda_kernel.cu
27
+ hqq/kernels/hqq_aten_torch.cpp
28
+ hqq/kernels/setup_cuda.py
29
+ hqq/kernels/setup_torch.py
30
+ hqq/models/__init__.py
31
+ hqq/models/base.py
32
+ hqq/models/hf/__init__.py
33
+ hqq/models/hf/base.py
34
+ hqq/models/hf/llama.py
35
+ hqq/models/hf/mistral.py
36
+ hqq/models/hf/mixtral.py
37
+ hqq/models/hf/phi.py
38
+ hqq/models/hf/phi_opt.py
39
+ hqq/models/open_clip/__init__.py
40
+ hqq/models/open_clip/base.py
41
+ hqq/models/open_clip/vit_clip.py
42
+ hqq/models/timm/__init__.py
43
+ hqq/models/timm/base.py
44
+ hqq/models/timm/vit_clip.py
45
+ hqq/models/vllm/__init__.py
46
+ hqq/models/vllm/base.py
47
+ hqq/models/vllm/llama.py
48
+ hqq/utils/__init__.py
49
+ hqq/utils/generation_hf.py
50
+ hqq/utils/optimizer.py
51
+ hqq/utils/patching.py
52
+ tests/test_bitpack.py
53
+ tests/test_quantize.py
lm-quant-toolkit/.deps/hqq/hqq.egg-info/dependency_links.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
lm-quant-toolkit/.deps/hqq/hqq.egg-info/requires.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ numpy>=1.24.4
2
+ tqdm>=4.64.1
3
+ einops
4
+ accelerate
5
+ transformers>=4.36.1
6
+ huggingface_hub
7
+ termcolor
lm-quant-toolkit/.deps/hqq/hqq.egg-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ hqq
lm-quant-toolkit/.deps/hqq/hqq/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ __version__ = "0.1.7.post2"
2
+ __author__ = 'Dr. Hicham Badri'
3
+ __credits__ = 'Mobius Labs GmbH'
lm-quant-toolkit/.deps/hqq/hqq/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (297 Bytes). View file
 
lm-quant-toolkit/.deps/hqq/hqq/backends/__init__.py ADDED
File without changes
lm-quant-toolkit/.deps/hqq/hqq/backends/marlin.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2024
2
+ #####################################################
3
+ import torch
4
+
5
+ try:
6
+ import marlin
7
+ except Exception:
8
+ marlin = None
9
+ from ..core.quantize import Quantizer
10
+
11
+
12
+ class MarlinLinear(torch.nn.Module):
13
+ def __init__(
14
+ self, W: torch.Tensor, scales: torch.Tensor, u=None, bias=None, groupsize=-1
15
+ ):
16
+ super().__init__()
17
+
18
+ m, n = W.shape
19
+ device = W.device
20
+ _linear = torch.nn.Linear(m, n)
21
+ _linear.weight.data = W.half().t()
22
+
23
+ effective_groupsize = m if (groupsize == -1) else groupsize
24
+
25
+ _layer = marlin.Layer(m, n, groupsize=groupsize)
26
+ _layer.k = m
27
+ _layer.n = n
28
+ _layer.groupsize = effective_groupsize
29
+ _layer.B = torch.empty((m // 16, n * 16 // 8), dtype=torch.int, device=device)
30
+ _layer.s = torch.empty(
31
+ (m // effective_groupsize, n), dtype=torch.half, device=device
32
+ )
33
+ _layer.pack(_linear, scales.t())
34
+
35
+ self.bias = bias.half() if (bias is not None) else None
36
+ self.Wq_packed = _layer.B.clone()
37
+ self.scales = _layer.s.clone()
38
+ self.workspace_fp = torch.zeros(n // 128 * 16, device=device)
39
+ self.in_features = m
40
+ self.out_features = n
41
+ self.group_size = effective_groupsize
42
+ self.axis = 1
43
+ self.device = device
44
+ self.compute_dtype = torch.float16
45
+ self.u = torch.nn.Parameter(u, requires_grad=False) if (u is not None) else None
46
+
47
+ del _linear, _layer
48
+ torch.cuda.empty_cache()
49
+
50
+ @torch.no_grad()
51
+ def matmul(self, x):
52
+ out = torch.empty(
53
+ x.shape[:-1] + (self.scales.shape[1],), dtype=x.dtype, device=x.device
54
+ )
55
+ marlin.mul(
56
+ x.view((-1, x.shape[-1])),
57
+ self.Wq_packed,
58
+ out.view((-1, out.shape[-1])),
59
+ self.scales,
60
+ self.workspace_fp,
61
+ )
62
+ return out
63
+
64
+ @torch.jit.ignore
65
+ def forward(self, x):
66
+ out = self.matmul(x)
67
+
68
+ if self.u is not None:
69
+ out += torch.matmul(x.sum(axis=-1, keepdim=True), self.u)
70
+
71
+ if self.bias is not None:
72
+ out += self.bias
73
+
74
+ return out
75
+
76
+
77
+ # ONLY WORKS WITH AXIS=1, group_size= - 1
78
+ def patch_hqq_to_marlin(layer, patch_params):
79
+ if marlin is None:
80
+ return layer
81
+
82
+ z_shift = 8.0
83
+ hqq_layer = layer.linear_layer if hasattr(layer, "linear_layer") else layer
84
+
85
+ # Check config suppport
86
+ if (
87
+ (hqq_layer.meta["axis"] == 0)
88
+ or (hqq_layer.meta["group_size"] is not None)
89
+ or (hqq_layer.meta["nbits"] != 4)
90
+ ):
91
+ print("Skipping marlin conversion for", hqq_layer.name)
92
+ return layer
93
+
94
+ W_r = Quantizer.unpack[hqq_layer.meta["packing"]](
95
+ hqq_layer.W_q, dtype=hqq_layer.compute_dtype
96
+ ).t()
97
+ z = hqq_layer.meta["zero"]
98
+ s = hqq_layer.meta["scale"].t()
99
+ W_r = (W_r - z_shift) * s
100
+
101
+ if type(z) in [torch.Tensor, torch.nn.Parameter]:
102
+ z = z.t()
103
+ u = (s * (-z + z_shift)).view([1, -1])
104
+ else:
105
+ u = None
106
+
107
+ marlin_layer = MarlinLinear(W_r, s, u=u, bias=hqq_layer.bias)
108
+
109
+ if hasattr(layer, "linear_layer"):
110
+ del layer.linear_layer
111
+ layer.linear_layer = marlin_layer
112
+ else:
113
+ del hqq_layer
114
+ layer = marlin_layer
115
+
116
+ torch.cuda.empty_cache()
117
+
118
+ return layer
lm-quant-toolkit/.deps/hqq/hqq/backends/torchao.py ADDED
@@ -0,0 +1,388 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2024
2
+ #####################################################
3
+
4
+ # Makes HQQ 4-bit (axis=1) compatbile with torch.ops.aten._weight_int4pack_mm
5
+
6
+ # The code is partially based on: https://github.com/pytorch-labs/gpt-fast/blob/main/quantize.py (BSD-3-Clause license)
7
+ # Only the packing logic is copied, the rest is rewritten to support HQQ's logic
8
+
9
+ # Only works with: bfloat16, axis=1.
10
+ # Only tested on Ada gpus.
11
+
12
+ import torch
13
+ import copy
14
+ from torch import bfloat16, nn, Tensor
15
+ import torch.nn.functional as F
16
+ from typing import Union
17
+
18
+ from ..core.quantize import HQQLinear, Quantizer
19
+ from ..core.peft import HQQLinearLoRA
20
+ from ..core.utils import cleanup
21
+
22
+
23
+ class HQQLinearTorchWeightOnlynt4(torch.nn.Module):
24
+ def __init__(
25
+ self,
26
+ linear_layer: Union[nn.Module, None],
27
+ quant_config: dict,
28
+ del_orig: bool = True,
29
+ compute_dtype: torch.dtype = bfloat16,
30
+ device: str = "cuda",
31
+ initialize: bool = True,
32
+ inner_k_tiles=8,
33
+ padding=True,
34
+ ):
35
+ super().__init__()
36
+
37
+ self.ready = False
38
+ self.in_gpu = False
39
+ self.bias = None
40
+ self.device = device
41
+ self.compute_dtype = compute_dtype
42
+ self.quant_config = (
43
+ copy.deepcopy(quant_config) if (quant_config is not None) else None
44
+ )
45
+ self.del_orig = del_orig
46
+
47
+ if (quant_config is None) and (linear_layer is None):
48
+ raise Exception(
49
+ "Invalid parameters: Both quant_config and linear_layer are None."
50
+ )
51
+
52
+ if (quant_config is None) and (initialize is True):
53
+ raise Exception(
54
+ "Invalid parameters: setting initialize to True requires a quant_config."
55
+ )
56
+
57
+ if self.quant_config is not None:
58
+ weight_quant_params = self.quant_config["weight_quant_params"]
59
+ self.groupsize = weight_quant_params["group_size"]
60
+ self.nbits = weight_quant_params["nbits"]
61
+ self.axis = weight_quant_params["axis"]
62
+
63
+ if linear_layer is not None:
64
+ self.groupsize = linear_layer.meta["group_size"]
65
+ self.nbits = linear_layer.meta["nbits"]
66
+ self.axis = linear_layer.meta["axis"]
67
+
68
+ self.inner_k_tiles = inner_k_tiles
69
+ self.padding = padding
70
+
71
+ assert self.axis==1, "Only axis==1 is supported"
72
+ assert self.nbits in [4], "Unsupported nbits."
73
+ assert (
74
+ self.compute_dtype is bfloat16
75
+ ), "Only bfloat16 compute_dtype is supported."
76
+ assert self.groupsize in [None, 32, 64, 128, 256], "Unsupported groupsize."
77
+ assert self.inner_k_tiles in [2, 4, 8], "Unsupported tile."
78
+
79
+ self.linear_layer = linear_layer
80
+
81
+ if initialize:
82
+ self.initialize()
83
+
84
+ ###################### Initializers ######################
85
+ def initialize_with_hqq_quants(self, W_q, meta, bias=None):
86
+ self.padding = (
87
+ False # Force padding off, a bit tricky to post-pad with grouping
88
+ )
89
+
90
+ self.set_shape(meta["shape"])
91
+ self.process_hqq_quants(W_q, meta)
92
+ self.bias = bias
93
+ self.ready = True
94
+ self.in_gpu = True
95
+ torch.cuda.empty_cache()
96
+
97
+ return self
98
+
99
+ def initialize(self):
100
+ if self.linear_layer is not None:
101
+ W = self.linear_layer.weight.data
102
+ self.set_shape(W.shape)
103
+
104
+ if self.in_features_diff > 0:
105
+ W = F.pad(W, pad=(0, self.in_features_diff), value=0)
106
+
107
+ W_q, meta = self.quantize(W, **self.quant_config)
108
+ self.process_hqq_quants(W_q, meta)
109
+ del W_q, meta
110
+
111
+ self.bias = (
112
+ None
113
+ if (self.linear_layer.bias is None)
114
+ else self.linear_layer.bias.to(
115
+ dtype=self.compute_dtype, device=self.device
116
+ )
117
+ )
118
+
119
+ if self.del_orig:
120
+ del self.linear_layer
121
+
122
+ self.ready = True
123
+ self.in_gpu = True
124
+ torch.cuda.empty_cache()
125
+
126
+ return self
127
+
128
+ ###################### Quantize/packing ######################
129
+
130
+ def quantize(
131
+ self,
132
+ W: Tensor,
133
+ weight_quant_params: dict,
134
+ scale_quant_params=Union[dict,None],
135
+ zero_quant_params=Union[dict,None],
136
+ offload_meta=False,
137
+ ):
138
+ W_q, meta = Quantizer.quantize(
139
+ W,
140
+ **weight_quant_params,
141
+ device=self.device,
142
+ compute_dtype=self.compute_dtype,
143
+ bitpack=False,
144
+ )
145
+
146
+ # ToDO: meta quantization
147
+
148
+ return W_q, meta
149
+
150
+ # TODO: move these to utils
151
+ @torch.no_grad()
152
+ def reshape_meta_axis1(self, meta_tensor, new_group_size, shape):
153
+ meta_tensor = meta_tensor.repeat([1, shape[1]]).reshape(shape)
154
+ meta_tensor = torch.mean(
155
+ meta_tensor.reshape([-1, new_group_size]), axis=1, keepdim=True
156
+ )
157
+ return meta_tensor
158
+
159
+ def find_multiple(self, n: int, k: int) -> int:
160
+ if n % k == 0:
161
+ return n
162
+ return n + k - (n % k)
163
+
164
+ def set_shape(self, shape):
165
+ self.shape = shape
166
+ self.in_features = shape[1]
167
+ self.out_features = shape[0]
168
+
169
+ self.origin_in_features = self.in_features
170
+ if self.padding:
171
+ self.in_features = self.find_multiple(self.in_features, 1024)
172
+
173
+ self.in_features_diff = self.in_features - self.origin_in_features
174
+
175
+ @torch.no_grad()
176
+ def process_hqq_quants(self, W_q, meta):
177
+ scales = meta["scale"]
178
+ zeros = meta["zero"]
179
+ shape = meta["shape"]
180
+
181
+ if meta["packing"] is not None:
182
+ W_q = Quantizer.unpack[meta["packing"]](W_q)
183
+
184
+ if self.groupsize is None:
185
+ self.groupsize = 128
186
+ W_q = W_q.reshape([-1, self.groupsize])
187
+ scales = self.reshape_meta_axis1(scales, self.groupsize, shape)
188
+ zeros = self.reshape_meta_axis1(zeros, self.groupsize, shape)
189
+
190
+ W_q_torch, scales_torch, zeros_torch = self.hqq_quants_to_torch_quants(
191
+ W_q=W_q, scales=scales, zeros=zeros, shape=shape, nbits=self.nbits
192
+ )
193
+ self.weight_int4pack = torch.ops.aten._convert_weight_to_int4pack(
194
+ W_q_torch, self.inner_k_tiles
195
+ )
196
+ self.scales_and_zeros = self.pack_scales_and_zeros(scales_torch, zeros_torch)
197
+
198
+ del W_q_torch, scales_torch, zeros_torch
199
+ torch.cuda.empty_cache()
200
+
201
+ @torch.no_grad()
202
+ def hqq_quants_to_torch_quants(
203
+ self, W_q: Tensor, scales: Tensor, zeros: Tensor, shape, nbits=4
204
+ ):
205
+ W_q = W_q.to(dtype=self.compute_dtype, device=self.device)
206
+ scales = scales.to(dtype=self.compute_dtype, device=self.device)
207
+ zeros = zeros.to(dtype=self.compute_dtype, device=self.device)
208
+
209
+ max_int = 2**nbits - 1
210
+ min_int = 0
211
+ dump = 2 ** (nbits - 1)
212
+
213
+ # HQQ -> torch logic
214
+ new_zeros = (scales * dump) - zeros * scales
215
+
216
+ min_val = new_zeros - scales * dump
217
+
218
+ # group_quantize_tensor_from_qparams
219
+ W_r = (W_q - zeros) * scales
220
+
221
+ W_q = (
222
+ W_r.sub(min_val)
223
+ .div(scales)
224
+ .round()
225
+ .clamp_(min_int, max_int)
226
+ .to(torch.int32)
227
+ .reshape(shape)
228
+ .contiguous()
229
+ )
230
+
231
+ # group_dequantize_tensor_from_qparams
232
+ # W_r = W_q*scales + min_val
233
+
234
+ scales = scales.contiguous().reshape(shape[0], -1)
235
+ new_zeros = new_zeros.contiguous().reshape(shape[0], -1)
236
+
237
+ return W_q, scales, new_zeros
238
+
239
+ def pack_scales_and_zeros(self, scales, zeros):
240
+ assert scales.shape == zeros.shape
241
+ assert scales.dtype == bfloat16
242
+ assert zeros.dtype == bfloat16
243
+ return (
244
+ torch.cat(
245
+ [
246
+ scales.reshape(scales.size(0), scales.size(1), 1),
247
+ zeros.reshape(zeros.size(0), zeros.size(1), 1),
248
+ ],
249
+ 2,
250
+ )
251
+ .transpose(0, 1)
252
+ .contiguous()
253
+ )
254
+
255
+ ###################### Forward/matmul ######################
256
+
257
+ # @torch.jit.ignore()
258
+ def matmul(self, x: Tensor) -> Tensor:
259
+ origin_x_size = x.size()
260
+ x = x.reshape(-1, origin_x_size[-1])
261
+ c = torch.ops.aten._weight_int4pack_mm(
262
+ x, self.weight_int4pack, self.groupsize, self.scales_and_zeros
263
+ )
264
+ new_shape = origin_x_size[:-1] + (self.out_features,)
265
+ c = c.reshape(new_shape)
266
+ return c
267
+
268
+ # TODO without matmul
269
+ def dequantize(self) -> Tensor:
270
+ return self.matmul(
271
+ torch.eye(self.in_features, dtype=self.compute_dtype, device=self.device)
272
+ )[: self.origin_in_features].t()
273
+
274
+ # TODO: backward
275
+ def forward(self, x: Tensor) -> Tensor:
276
+ if self.in_features_diff > 0:
277
+ x = F.pad(x, pad=(0, self.in_features_diff))
278
+
279
+ out = self.matmul(x)
280
+
281
+ if self.bias is not None:
282
+ out += self.bias
283
+ return out
284
+
285
+
286
+ ###################### Patching ######################
287
+ def patch_linearlayers(model, fct, patch_param=None):
288
+ model.base_class.patch_linearlayers(
289
+ model,
290
+ fct,
291
+ {lin_tag: patch_param for lin_tag in model.base_class.get_linear_tags()},
292
+ )
293
+
294
+
295
+ def patch_hqq_to_aoint4(layer, patch_params):
296
+ hqq_layer = None
297
+ if type(layer) is HQQLinear:
298
+ hqq_layer = layer
299
+ if type(layer) is HQQLinearLoRA:
300
+ hqq_layer = layer.linear_layer
301
+
302
+ if hqq_layer is None:
303
+ return layer
304
+
305
+ if hqq_layer.meta["nbits"] != 4 or hqq_layer.meta["axis"] != 1:
306
+ print("Skipping aoint4 conversion for ", hqq_layer.name)
307
+ return layer
308
+
309
+ quant_config = getattr(hqq_layer, "quant_config", None)
310
+
311
+ hqq_aoint4_layer = HQQLinearTorchWeightOnlynt4(
312
+ None,
313
+ quant_config=quant_config,
314
+ compute_dtype=hqq_layer.compute_dtype,
315
+ device=hqq_layer.device,
316
+ del_orig=False,
317
+ initialize=False,
318
+ padding=False,
319
+ )
320
+ hqq_aoint4_layer.initialize_with_hqq_quants(
321
+ hqq_layer.W_q, hqq_layer.meta, hqq_layer.bias
322
+ )
323
+
324
+ del hqq_layer
325
+ torch.cuda.empty_cache()
326
+
327
+ if type(layer) is HQQLinear:
328
+ return hqq_aoint4_layer
329
+
330
+ if type(layer) is HQQLinearLoRA:
331
+ layer.linear_layer = hqq_aoint4_layer
332
+
333
+ return layer
334
+
335
+
336
+ def replace_with_torchInt4(model):
337
+ patch_linearlayers(model, patch_hqq_to_aoint4)
338
+ cleanup()
339
+
340
+
341
+ # Force requantize, mainly to check if the padding with int4mm is faster
342
+ def patch_hqq_to_aoint4_force_requantize(layer, patch_params):
343
+ hqq_layer = None
344
+ if type(layer) is HQQLinear:
345
+ hqq_layer = layer
346
+ if type(layer) is HQQLinearLoRA:
347
+ hqq_layer = layer.linear_layer
348
+
349
+ if hqq_layer is None:
350
+ return layer
351
+
352
+ if hqq_layer.meta["nbits"] != 4 or hqq_layer.meta["axis"] != 1:
353
+ print("Skipping aoint4 conversion for ", hqq_layer.name)
354
+ return layer
355
+
356
+ # Create dummy linear layer to store dequantize weights
357
+ dummy_linear = torch.nn.Linear(1, 1, bias=False)
358
+ dummy_linear.weight.data = hqq_layer.dequantize()
359
+
360
+ # Disable optimizer on already dequantized weights
361
+ quant_config = hqq_layer.quant_config
362
+ quant_config["weight_quant_params"]["optimize"] = False
363
+
364
+ hqq_aoint4_layer = HQQLinearTorchWeightOnlynt4(
365
+ dummy_linear,
366
+ quant_config=quant_config,
367
+ compute_dtype=hqq_layer.compute_dtype,
368
+ device=hqq_layer.device,
369
+ del_orig=True,
370
+ initialize=True,
371
+ padding=True,
372
+ )
373
+
374
+ del hqq_layer
375
+ torch.cuda.empty_cache()
376
+
377
+ if type(layer) is HQQLinear:
378
+ return hqq_aoint4_layer
379
+
380
+ if type(layer) is HQQLinearLoRA:
381
+ layer.linear_layer = hqq_aoint4_layer
382
+
383
+ return layer
384
+
385
+
386
+ def replace_with_torchInt4_force_requantize(model):
387
+ patch_linearlayers(model, patch_hqq_to_aoint4_force_requantize)
388
+ cleanup()
lm-quant-toolkit/.deps/hqq/hqq/core/__init__.py ADDED
File without changes
lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (197 Bytes). View file
 
lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/bitpack.cpython-311.pyc ADDED
Binary file (8.09 kB). View file
 
lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/optimize.cpython-311.pyc ADDED
Binary file (21.9 kB). View file
 
lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/quantize.cpython-311.pyc ADDED
Binary file (38.7 kB). View file
 
lm-quant-toolkit/.deps/hqq/hqq/core/__pycache__/utils.cpython-311.pyc ADDED
Binary file (1.64 kB). View file
 
lm-quant-toolkit/.deps/hqq/hqq/core/bitpack.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+
4
+ import torch
5
+ from torch import uint8, int32, Tensor
6
+ import numpy as np
7
+
8
+
9
+ # Bit packing logic. format: pack/unpack_nBits_target-<uint8 or int32>
10
+ class BitPack:
11
+ # 8-bit
12
+ ################################################
13
+ @staticmethod
14
+ def pack_8bit_u8(W_q: Tensor) -> Tensor:
15
+ return W_q.to(uint8)
16
+
17
+ @staticmethod
18
+ def unpack_8bit_u8(W_q: Tensor, dtype=uint8) -> Tensor:
19
+ return W_q.to(dtype)
20
+
21
+ # 4-bit
22
+ ################################################
23
+ @staticmethod
24
+ def pack_4bit_u8(W_q: Tensor) -> Tensor: # uint8 > uint8/2
25
+ W_q = W_q.to(uint8)
26
+ _step = int(len(W_q) / 2)
27
+
28
+ return (W_q[:_step] << 4) | W_q[_step:]
29
+
30
+ @staticmethod
31
+ def unpack_4bit_u8(W_q: Tensor, dtype=uint8) -> Tensor: # uint8/2 > uint8
32
+ _step = W_q.shape[0]
33
+ tmp = torch.empty([2 * _step, W_q.shape[1]], dtype=dtype, device=W_q.device)
34
+
35
+ tmp[:_step] = (W_q & 0b11110000) >> 4
36
+ tmp[_step:] = W_q & 0b00001111
37
+
38
+ return tmp
39
+
40
+ # 2-bit
41
+ ################################################
42
+ @staticmethod
43
+ def pack_2bit_u8(W_q: Tensor) -> Tensor: # uint8 > uint8/4
44
+ W_q = W_q.to(uint8)
45
+ _step = int(len(W_q) / 4)
46
+
47
+ return (
48
+ W_q[:_step] << 6
49
+ | W_q[_step : 2 * _step] << 4
50
+ | W_q[2 * _step : 3 * _step] << 2
51
+ | W_q[3 * _step :]
52
+ )
53
+
54
+ @staticmethod
55
+ def unpack_2bit_u8(W_q: Tensor, dtype=uint8) -> Tensor:
56
+ _step = W_q.shape[0]
57
+ tmp = torch.empty([4 * _step, W_q.shape[1]], dtype=dtype, device=W_q.device)
58
+
59
+ tmp[0 * _step : 1 * _step] = (W_q & 0b11000000) >> 6
60
+ tmp[1 * _step : 2 * _step] = (W_q & 0b00110000) >> 4
61
+ tmp[2 * _step : 3 * _step] = (W_q & 0b00001100) >> 2
62
+ tmp[3 * _step : 4 * _step] = W_q & 0b00000011
63
+
64
+ return tmp
65
+
66
+ # 3-bit
67
+ ################################################
68
+ @staticmethod
69
+ def pack_3bit_32(W_q_in: Tensor) -> Tensor:
70
+ W_q = torch.zeros(
71
+ [int(10 * np.ceil(W_q_in.shape[0] / 10.0)), W_q_in.shape[1]],
72
+ device=W_q_in.device,
73
+ dtype=int32,
74
+ )
75
+ W_q[: len(W_q_in)] = W_q_in
76
+ _step = int(len(W_q) / 10)
77
+
78
+ W_q = (
79
+ (W_q[:_step] << 27)
80
+ | (W_q[1 * _step : 2 * _step] << 24)
81
+ | (W_q[2 * _step : 3 * _step] << 21)
82
+ | (W_q[3 * _step : 4 * _step] << 18)
83
+ | (W_q[4 * _step : 5 * _step] << 15)
84
+ | (W_q[5 * _step : 6 * _step] << 12)
85
+ | (W_q[6 * _step : 7 * _step] << 9)
86
+ | (W_q[7 * _step : 8 * _step] << 6)
87
+ | (W_q[8 * _step : 9 * _step] << 3)
88
+ | (W_q[9 * _step : 10 * _step])
89
+ )
90
+
91
+ return W_q
92
+
93
+ # A bit faster than _cat version
94
+ @staticmethod
95
+ def unpack_3bit_32(W_q: Tensor, dtype=uint8) -> Tensor:
96
+ _step = W_q.shape[0]
97
+ tmp = torch.empty([10 * _step, W_q.shape[1]], dtype=dtype, device=W_q.device)
98
+
99
+ tmp[0 * _step : 1 * _step] = (W_q & 0b00111000000000000000000000000000) >> 27
100
+ tmp[1 * _step : 2 * _step] = (W_q & 0b00000111000000000000000000000000) >> 24
101
+ tmp[2 * _step : 3 * _step] = (W_q & 0b00000000111000000000000000000000) >> 21
102
+ tmp[3 * _step : 4 * _step] = (W_q & 0b00000000000111000000000000000000) >> 18
103
+ tmp[4 * _step : 5 * _step] = (W_q & 0b00000000000000111000000000000000) >> 15
104
+ tmp[5 * _step : 6 * _step] = (W_q & 0b00000000000000000111000000000000) >> 12
105
+ tmp[6 * _step : 7 * _step] = (W_q & 0b00000000000000000000111000000000) >> 9
106
+ tmp[7 * _step : 8 * _step] = (W_q & 0b00000000000000000000000111000000) >> 6
107
+ tmp[8 * _step : 9 * _step] = (W_q & 0b00000000000000000000000000111000) >> 3
108
+ tmp[9 * _step : 10 * _step] = W_q & 0b00000000000000000000000000000111
109
+
110
+ return tmp
111
+
112
+ # 1-bit
113
+ ################################################
114
+ @staticmethod
115
+ def pack_1bit_u8(W_q: Tensor) -> Tensor:
116
+ W_q = W_q.to(uint8)
117
+ _step = int(len(W_q) / 8)
118
+
119
+ return (
120
+ W_q[:_step] << 7
121
+ | W_q[1 * _step : 2 * _step] << 6
122
+ | W_q[2 * _step : 3 * _step] << 5
123
+ | W_q[3 * _step : 4 * _step] << 4
124
+ | W_q[4 * _step : 5 * _step] << 3
125
+ | W_q[5 * _step : 6 * _step] << 2
126
+ | W_q[6 * _step : 7 * _step] << 1
127
+ | W_q[7 * _step : 8 * _step]
128
+ )
129
+
130
+ @staticmethod
131
+ def unpack_1bit_u8(W_q: Tensor, dtype=uint8) -> Tensor:
132
+ _step = W_q.shape[0]
133
+ tmp = torch.empty([8 * _step, W_q.shape[1]], dtype=dtype, device=W_q.device)
134
+
135
+ tmp[0 * _step : 1 * _step] = (W_q & 0b10000000) >> 7
136
+ tmp[1 * _step : 2 * _step] = (W_q & 0b01000000) >> 6
137
+ tmp[2 * _step : 3 * _step] = (W_q & 0b00100000) >> 5
138
+ tmp[3 * _step : 4 * _step] = (W_q & 0b00010000) >> 4
139
+ tmp[4 * _step : 5 * _step] = (W_q & 0b00001000) >> 3
140
+ tmp[5 * _step : 6 * _step] = (W_q & 0b00000100) >> 2
141
+ tmp[6 * _step : 7 * _step] = (W_q & 0b00000010) >> 1
142
+ tmp[7 * _step : 8 * _step] = W_q & 0b00000001
143
+
144
+ return tmp
lm-quant-toolkit/.deps/hqq/hqq/core/optimize.py ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+ import torch
4
+ import numpy as np
5
+ from torch import float32, float16, Tensor
6
+ from functools import partial
7
+ from typing import Union
8
+
9
+
10
+ # re-estimate the scale based on the inverse median: Only tested with axis==0
11
+ def update_scale_inverse_median(
12
+ W_f: Tensor, scale: Tensor, zero: Tensor, axis: int, min_max: list
13
+ ) -> tuple:
14
+ scale_rng = 2e4
15
+ z_val = 1e-4
16
+ delta = 1e-2
17
+
18
+ W_q = torch.round(W_f * scale + zero).clamp(min_max[0], min_max[1])
19
+
20
+ # Correct zero to avoid W_q==zero
21
+ zero_c = zero.clone()
22
+ zero_c_indx = torch.sum(1.0 * ((W_q - zero) == 0), axis=axis, keepdim=True) > 0
23
+ zero_c[zero_c_indx] = zero_c[zero_c_indx] + delta
24
+
25
+ # Build scale tensor
26
+ W_f_c = W_f.clone()
27
+ W_f_c_mask = torch.abs(W_f_c) < z_val
28
+ W_f_c[W_f_c_mask] = z_val
29
+
30
+ scale_tensor = (W_q - zero_c).float() / W_f_c.float()
31
+ # W_r = (W_q - zero_c)/scale_tensor
32
+
33
+ # Normalize scale_tensor
34
+ scale_b = torch.median(scale_tensor, axis=axis, keepdim=True)[0]
35
+ scale_b = scale_b.clamp(min=-scale_rng, max=scale_rng).half()
36
+
37
+ # Mix with older scale
38
+ W_r = (W_q - zero_c) / scale_b
39
+ err_b = torch.abs(W_f - W_r).mean(axis=axis, keepdim=True)
40
+
41
+ W_r = (W_q - zero_c) / scale
42
+ err_a = torch.abs(W_f - W_r).mean(axis=axis, keepdim=True)
43
+
44
+ mask = (err_b < err_a).half()
45
+ scale_b = mask * scale_b + (1 - mask) * scale
46
+
47
+ # W_r = (W_q - zero_c)/scale_b
48
+ return scale_b, zero_c
49
+
50
+
51
+ # Greedy local search: Only tested with axis==0
52
+ def update_scale_grid_search(
53
+ W_f: Tensor, scale: Tensor, zero: Tensor, axis: int, min_max: list, N: int = 128 + 1
54
+ ) -> Tensor:
55
+ # Make sure it's an odd number so that the original scale is included
56
+ assert N % 2 == 1, "Please check whether N: odd number"
57
+ rng_dump = 0.05 # 0.05 / 1.
58
+ z_val = 2e-4
59
+
60
+ device = scale.device
61
+ dtype = scale.dtype
62
+ ###############################
63
+ W_q = torch.round(W_f * scale + zero).clamp(min_max[0], min_max[1])
64
+ n_clusters = max(W_q.shape[0], W_q.shape[1])
65
+ rng = torch.abs(scale).mean() * rng_dump if (rng_dump < 1.0) else rng_dump
66
+
67
+ scale_shifted = (
68
+ torch.linspace(-rng, rng, N)[:, None]
69
+ .to(dtype=dtype, device=device)
70
+ .repeat(1, n_clusters)
71
+ + scale
72
+ )
73
+
74
+ # Safe inverse
75
+ scale_shifted[
76
+ torch.logical_and(scale_shifted >= 0, torch.abs(scale_shifted) <= z_val)
77
+ ] = z_val
78
+ scale_shifted[
79
+ torch.logical_and(scale_shifted < 0, torch.abs(scale_shifted) <= z_val)
80
+ ] = -z_val
81
+
82
+ err = torch.empty([N, n_clusters], dtype=dtype, device=device)
83
+ for i in range(N):
84
+ W_r = (W_q - zero) / scale_shifted[i][None, :]
85
+ err[i] = torch.abs(W_f - W_r).mean(axis=axis, keepdim=True)
86
+
87
+ ind_r = torch.argmin(err, axis=axis).to(torch.int32)
88
+ ind_c = torch.arange(len(ind_r), dtype=torch.int32, device=device)
89
+ scale_b = scale_shifted[ind_r, ind_c]
90
+
91
+ return scale_b
92
+
93
+
94
+ # Shrinking operator
95
+ def shrink_lp_op(x: Tensor, beta: float, lp_norm: float) -> Tensor:
96
+ if lp_norm == 1:
97
+ return torch.sign(x) * torch.nn.functional.relu(torch.abs(x) - 1.0 / beta)
98
+ else:
99
+ return torch.sign(x) * torch.nn.functional.relu(
100
+ torch.abs(x) - (1.0 / beta) * torch.pow(torch.abs(x), lp_norm - 1)
101
+ )
102
+
103
+
104
+ # Proximal solver || W - dequantize(quantize(W))||_p^p - Experimental
105
+ @torch.inference_mode()
106
+ def optimize_weights_proximal_v2(
107
+ tensor: Tensor,
108
+ scale: Tensor,
109
+ zero: Tensor,
110
+ min_max: list,
111
+ axis: int = 0,
112
+ device: Union[str, None] = None,
113
+ dtype: Union[torch.dtype, None] = None,
114
+ opt_params: dict = {
115
+ "lp_norm": 0.7,
116
+ "beta": 1e1,
117
+ "kappa": 1.01,
118
+ "iters": 20,
119
+ "tol": 0.0,
120
+ "early_stop": True,
121
+ "scale_gridsearch": False,
122
+ },
123
+ verbose: bool = False,
124
+ ) -> tuple:
125
+ # Params
126
+ lp_norm = max(opt_params["lp_norm"], 0.1)
127
+ beta = opt_params["beta"]
128
+ kappa = opt_params["kappa"]
129
+ iters = opt_params["iters"]
130
+ early_stop = opt_params["early_stop"]
131
+ tol = opt_params["tol"]
132
+
133
+ # Check
134
+ assert lp_norm <= 1.0, "lp_norm should be <=1"
135
+ assert beta > 0.0, "beta should be > 0"
136
+ assert kappa > 1.0, "kappa should be > 1"
137
+ assert iters > 1, "iters should be > 1"
138
+
139
+ # Cast/device
140
+ if device is None:
141
+ device = tensor.device
142
+ else:
143
+ device = torch.device(device)
144
+
145
+ if dtype is None:
146
+ dtype = float16 if (device.type == "cuda") else float32
147
+
148
+ W_f = tensor.to(device=device, dtype=dtype)
149
+ scale = scale.to(device=device, dtype=dtype)
150
+ zero = zero.to(device=device, dtype=dtype)
151
+
152
+ # Update scale: works slightly better. Tested on Llama2 only
153
+ if opt_params["scale_gridsearch"]:
154
+ scale = update_scale_grid_search(W_f, scale, zero, axis, min_max)
155
+
156
+ # Optimize for zero-point
157
+ best_error = 1e4
158
+ scale_prev, zero_prev = scale.clone(), zero.clone()
159
+ for i in range(iters):
160
+ W_q = torch.round(W_f * scale + zero).clamp(min_max[0], min_max[1])
161
+ W_r = (W_q - zero) / scale
162
+
163
+ # current_error = float(torch.pow(torch.abs(W_f - W_r), max(0.80, lp_norm)).mean())
164
+ current_error = float(torch.abs(W_f - W_r).mean())
165
+
166
+ if verbose:
167
+ print(i, np.round(current_error, 6))
168
+
169
+ if early_stop:
170
+ if best_error - current_error > tol:
171
+ best_error = current_error
172
+ scale_prev, zero_prev = scale.clone(), zero.clone()
173
+ else:
174
+ scale, zero = scale_prev.clone(), zero_prev.clone()
175
+ break
176
+
177
+ W_e = shrink_lp_op(W_f - W_r, beta, lp_norm)
178
+ zero = torch.mean(W_q - (W_f - W_e) * scale, axis=axis, keepdim=True)
179
+ beta *= kappa
180
+
181
+ # Clean-up
182
+ scale = scale.to(tensor.device)
183
+ zero = zero.to(tensor.device)
184
+ del W_f, W_q, W_r, W_e, scale_prev, zero_prev
185
+ torch.cuda.empty_cache()
186
+
187
+ W_q = torch.round(tensor * scale + zero).clamp(min_max[0], min_max[1])
188
+
189
+ return W_q, scale, zero
190
+
191
+
192
+ # Proximal solver || W - dequantize(quantize(W))||_p^p
193
+ @torch.inference_mode()
194
+ def optimize_weights_proximal_legacy(
195
+ tensor: Tensor,
196
+ scale: Tensor,
197
+ zero: Tensor,
198
+ min_max: list,
199
+ axis: int = 0,
200
+ device: Union[str, None] = None,
201
+ opt_params: dict = {"lp_norm": 0.7, "beta": 1e1, "kappa": 1.01, "iters": 20},
202
+ verbose: bool = False,
203
+ ) -> tuple:
204
+ lp_norm, beta, kappa, iters = (
205
+ opt_params["lp_norm"],
206
+ opt_params["beta"],
207
+ opt_params["kappa"],
208
+ opt_params["iters"],
209
+ )
210
+
211
+ if device is None:
212
+ device = tensor.device
213
+ else:
214
+ device = torch.device(device)
215
+
216
+ dtype = float16 if (device.type == "cuda") else float32
217
+ W_f = tensor.to(dtype=dtype, device=device)
218
+ scale = scale.to(dtype=dtype, device=device)
219
+ zero = zero.to(dtype=dtype, device=device)
220
+
221
+ best_error = 1e4
222
+ for i in range(iters):
223
+ W_q = torch.round(W_f * scale + zero).clamp(min_max[0], min_max[1])
224
+ W_r = (W_q - zero) / scale
225
+ W_e = shrink_lp_op(W_f - W_r, beta, lp_norm)
226
+ zero = torch.mean(W_q - (W_f - W_e) * scale, axis=axis, keepdim=True)
227
+ beta *= kappa
228
+
229
+ current_error = float(torch.abs(W_f - W_r).mean())
230
+ if verbose:
231
+ print(i, np.round(current_error, 6))
232
+ if current_error < best_error:
233
+ best_error = current_error
234
+ else:
235
+ break
236
+
237
+ scale = scale.to(tensor.device)
238
+ zero = zero.to(tensor.device)
239
+ del W_f, W_q, W_r, W_e
240
+ torch.cuda.empty_cache()
241
+
242
+ W_q = torch.round(tensor * scale + zero).clamp(min_max[0], min_max[1])
243
+ return W_q, scale, zero
244
+
245
+
246
+ # Default: fast with early stopping
247
+ optimize_weights_proximal = optimize_weights_proximal_legacy
248
+
249
+ # Slower, better quality: no early stoppping, more iterations
250
+ optimize_weights_proximal_slow = partial(
251
+ optimize_weights_proximal_v2,
252
+ dtype=torch.float32,
253
+ opt_params={
254
+ "lp_norm": 0.7,
255
+ "beta": 1e1,
256
+ "kappa": 1.01,
257
+ "iters": 100,
258
+ "tol": 0.0,
259
+ "early_stop": False,
260
+ "scale_gridsearch": False,
261
+ },
262
+ )
263
+
264
+ ##############################################################################################################
265
+ # L1 with SGD optimizer: supports scale and W_q updates. L{p<1} fails with SGD
266
+
267
+
268
+ class LinearSchedulerWithWarmStart(torch.optim.lr_scheduler._LRScheduler):
269
+ def __init__(self, optimizer, lr_start, lr_end, iters, warm_start=0, last_epoch=-1):
270
+ iters_wrm = max(0, int(iters * warm_start))
271
+ self.lr_wrm = (
272
+ np.linspace(lr_end, lr_start, iters_wrm)
273
+ if (iters_wrm > 0)
274
+ else np.array([])
275
+ )
276
+ self.lr_mid = np.linspace(lr_start, lr_end, iters - iters_wrm)
277
+ self.lr_sch = np.concatenate([self.lr_wrm, self.lr_mid])
278
+ self.idx = 0
279
+ super(LinearSchedulerWithWarmStart, self).__init__(optimizer, last_epoch)
280
+
281
+ def get_lr(self):
282
+ self.idx = min(self.idx, len(self.lr_sch) - 1)
283
+ out = [self.lr_sch[self.idx] for base_lr in self.base_lrs]
284
+ self.idx += 1
285
+ return out
286
+
287
+
288
+ # SGD solver || W - dequantize(quantize(W))||_1 (p=1 only, with additional fake inputs x)
289
+ def optimize_weights_autograd(
290
+ tensor: Tensor,
291
+ scale: Tensor,
292
+ zero: Tensor,
293
+ min_max: list,
294
+ axis: int = 0,
295
+ device: Union[str, None] = None,
296
+ dtype: Union[torch.dtype, None] = float32,
297
+ opt_params: dict = {
298
+ "lr": 2e-3,
299
+ "iters": 2500,
300
+ "lr_schedule": False,
301
+ "update_Wq": False,
302
+ "use_fake_data": False,
303
+ },
304
+ data_params: dict = {"normalize": False, "data_rng": 10.0, "data_ctx": 32},
305
+ compile: bool = True,
306
+ verbose: bool = False,
307
+ ) -> tuple:
308
+ ref_device = scale.device
309
+ ref_dtype = scale.dtype
310
+
311
+ if device is None:
312
+ device = tensor.device
313
+ else:
314
+ device = torch.device(device)
315
+
316
+ W_f = tensor.to(dtype=dtype, device=device)
317
+
318
+ params = {}
319
+ params["scale"] = torch.nn.Parameter(
320
+ scale.to(dtype=dtype, device=device), requires_grad=True
321
+ )
322
+ params["zero"] = torch.nn.Parameter(
323
+ zero.to(dtype=dtype, device=device), requires_grad=True
324
+ )
325
+
326
+ if opt_params["update_Wq"]:
327
+ with torch.no_grad():
328
+ params["W_q"] = torch.round(W_f * params["scale"] + params["zero"]).clamp(
329
+ min_max[0], min_max[1]
330
+ )
331
+ params["W_q"] = torch.nn.Parameter(params["W_q"], requires_grad=True)
332
+
333
+ optimizer = torch.optim.AdamW(
334
+ [params[k] for k in params],
335
+ lr=opt_params["lr"],
336
+ betas=(0.9, 0.99),
337
+ eps=1e-06,
338
+ weight_decay=0.0,
339
+ )
340
+
341
+ if opt_params["lr_schedule"]:
342
+ scheduler = LinearSchedulerWithWarmStart(
343
+ optimizer,
344
+ lr_start=opt_params["lr"],
345
+ lr_end=1e-6,
346
+ iters=opt_params["iters"],
347
+ warm_start=0,
348
+ )
349
+ else:
350
+ scheduler = None
351
+
352
+ with torch.no_grad():
353
+ if data_params["normalize"]:
354
+ scale_loss = 1.0 / (tensor.abs().mean() + 1e-4)
355
+ else:
356
+ scale_loss = 1.0
357
+
358
+ def _loss_fct(output, target):
359
+ return torch.mean(torch.abs(scale_loss * (target - output))) # L1
360
+
361
+ def _fake_quant_fixed_Wq(W_f):
362
+ # Quantize
363
+ W_q = torch.round(W_f * params["scale"] + params["zero"]).clamp(
364
+ min_max[0], min_max[1]
365
+ )
366
+ # Dequantize
367
+ W_r = (W_q - params["zero"]) / params["scale"]
368
+ return W_r
369
+
370
+ def _fake_quant_update_Wq(W_f):
371
+ # Quantize
372
+ W_q = torch.round(params["W_q"]).clamp(min_max[0], min_max[1])
373
+ # Dequantize
374
+ W_r = (W_q - params["zero"]) / params["scale"]
375
+ return W_r
376
+
377
+ if opt_params["update_Wq"]:
378
+ _fake_quant = _fake_quant_update_Wq
379
+ else:
380
+ _fake_quant = _fake_quant_fixed_Wq
381
+
382
+ def _fake_quant_loss(W_f):
383
+ return _loss_fct(_fake_quant(W_f), W_f)
384
+
385
+ def _fake_quant_loss_with_fake_data(W_f):
386
+ x = (
387
+ torch.rand(
388
+ [data_params["data_ctx"], W_f.shape[1]], device=device, dtype=dtype
389
+ )
390
+ - 0.5
391
+ ) * 2 ** data_params["data_rng"]
392
+ y_ref = torch.matmul(x, W_f.T)
393
+ y_pred = torch.matmul(x, _fake_quant(W_f).T)
394
+ return _loss_fct(y_pred, y_ref)
395
+
396
+ if opt_params["use_fake_data"]:
397
+ _fake_quant_loss = _fake_quant_loss_with_fake_data
398
+ else:
399
+ _fake_quant_loss = _fake_quant_loss
400
+
401
+ if compile:
402
+ _fake_quant_loss = torch.compile(_fake_quant_loss)
403
+
404
+ def _step(W_f):
405
+ optimizer.zero_grad()
406
+ loss = _fake_quant_loss(W_f)
407
+ loss.backward()
408
+ optimizer.step()
409
+ if scheduler is not None:
410
+ scheduler.step()
411
+ return np.round(loss.item(), 10)
412
+
413
+ with torch.no_grad():
414
+ _init_loss = _fake_quant_loss(W_f).item()
415
+
416
+ for i in range(opt_params["iters"]):
417
+ loss_out = _step(W_f)
418
+ if verbose and (i % 100) == 0:
419
+ print(i, loss_out)
420
+
421
+ with torch.no_grad():
422
+ _final_loss = _fake_quant_loss(W_f).item()
423
+
424
+ if _final_loss < _init_loss:
425
+ for k in params:
426
+ params[k] = params[k].data.detach()
427
+ else:
428
+ if verbose:
429
+ print("optimization failed...")
430
+ params = {"scale": scale, "zero": zero}
431
+
432
+ scale = params["scale"].to(device=ref_device, dtype=ref_dtype)
433
+ zero = params["zero"].to(device=ref_device, dtype=ref_dtype)
434
+
435
+ if "W_q" in params:
436
+ W_q = params["W_q"].to(device=ref_device, dtype=ref_dtype)
437
+ else:
438
+ W_q = (
439
+ torch.round(tensor * scale + zero)
440
+ .clamp(min_max[0], min_max[1])
441
+ .to(device=ref_device, dtype=ref_dtype)
442
+ )
443
+
444
+ del W_f
445
+ torch.cuda.empty_cache()
446
+ return W_q, scale, zero
447
+
448
+
449
+ optimize_weights_autograd_main = partial(
450
+ optimize_weights_autograd,
451
+ dtype=torch.float32,
452
+ opt_params={
453
+ "lr": 2e-3,
454
+ "iters": 1000,
455
+ "lr_schedule": True,
456
+ "update_Wq": True,
457
+ "use_fake_data": False,
458
+ },
459
+ verbose=False,
460
+ compile=True,
461
+ )
462
+
463
+ optimize_weights_autograd_fakedata = partial(
464
+ optimize_weights_autograd,
465
+ dtype=torch.float32,
466
+ opt_params={
467
+ "lr": 2e-3,
468
+ "iters": 1000,
469
+ "lr_schedule": True,
470
+ "update_Wq": True,
471
+ "use_fake_data": True,
472
+ },
473
+ data_params={"normalize": False, "data_rng": 10.0, "data_ctx": 32},
474
+ verbose=False,
475
+ compile=True,
476
+ )
lm-quant-toolkit/.deps/hqq/hqq/core/peft.py ADDED
@@ -0,0 +1,545 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+ import torch
4
+ from torch import float16, bfloat16, float32
5
+ from torch import Tensor, nn
6
+ import numpy as np
7
+ from .quantize import HQQLinear, Quantizer
8
+ from .utils import cleanup
9
+ from typing import Union
10
+
11
+
12
+ # Return trainable weight matrix
13
+ def _get_dense_param(
14
+ in_features: int,
15
+ out_features: int,
16
+ device="cuda",
17
+ trainable: bool = True,
18
+ dtype: torch.dtype = float32,
19
+ ) -> Tensor:
20
+ W = (
21
+ nn.Linear(in_features, out_features, bias=None)
22
+ .weight.data.t()
23
+ .to(dtype)
24
+ .to(device)
25
+ .contiguous()
26
+ )
27
+ return nn.Parameter(W, requires_grad=trainable)
28
+
29
+
30
+ # Applies LoRA to a linear module (include HQQLinear)
31
+ class HQQLinearLoRA(nn.Module):
32
+ def __init__(self, linear_layer: nn.Module, peft_config: dict):
33
+ super().__init__()
34
+
35
+ # Device
36
+ self.device = (
37
+ linear_layer.device
38
+ if hasattr(linear_layer, "device")
39
+ else next(linear_layer.parameters()).device
40
+ )
41
+ self.train_dtype = (
42
+ peft_config["train_dtype"]
43
+ if ("train_dtype" in peft_config)
44
+ else torch.float
45
+ )
46
+
47
+ # Linear layer
48
+ self.linear_layer = linear_layer
49
+ self.in_features = linear_layer.in_features
50
+ self.out_features = linear_layer.out_features
51
+
52
+ # Bias
53
+ self.bias = None if (linear_layer.bias is None) else linear_layer.bias.clone()
54
+ self.linear_layer.bias = None
55
+ self.train_bias = (
56
+ peft_config["train_bias"] if ("train_bias" in peft_config) else False
57
+ )
58
+
59
+ if self.bias is not None:
60
+ self.bias = nn.Parameter(self.bias, requires_grad=self.train_bias)
61
+ if self.train_bias:
62
+ self.bias.data = self.bias.data.to(self.train_dtype)
63
+
64
+ if (self.bias is None) and self.train_bias:
65
+ self.bias = nn.Parameter(
66
+ torch.zeros(
67
+ (self.out_features,), device=self.device, dtype=self.train_dtype
68
+ ),
69
+ requires_grad=True,
70
+ )
71
+
72
+ # Dropout
73
+ if "dropout" in peft_config:
74
+ self.peft_drop = (
75
+ nn.Dropout(p=peft_config["dropout"])
76
+ if (peft_config["dropout"] > 0.0)
77
+ else nn.Identity()
78
+ )
79
+ else:
80
+ self.peft_drop = nn.Identity()
81
+
82
+ # LoRA A/B
83
+ self.peft_config = peft_config
84
+ self.lora_alpha = peft_config["lora_alpha"]
85
+ self.r = peft_config["r"]
86
+ self.scaling = self.lora_alpha / self.r
87
+
88
+ self.lora_A = _get_dense_param(
89
+ self.in_features,
90
+ self.r,
91
+ device=self.device,
92
+ trainable=True,
93
+ dtype=self.train_dtype,
94
+ )
95
+
96
+ self.lora_B = _get_dense_param(
97
+ self.r,
98
+ self.out_features,
99
+ device=self.device,
100
+ trainable=True,
101
+ dtype=self.train_dtype,
102
+ )
103
+
104
+ # LoRA weights init
105
+ if "lora_init" in peft_config:
106
+ # Set lora init
107
+ assert (
108
+ peft_config["lora_init"]["lora_A"].shape[0],
109
+ peft_config["lora_init"]["lora_B"].shape[1],
110
+ ) == (self.in_features, self.out_features), (
111
+ "Invalid init LoRA weight shapes. Expected: lora_A: "
112
+ + str(self.in_features)
113
+ + " x r , lora_B: r x "
114
+ + str(self.out_features)
115
+ + ")"
116
+ )
117
+ self.lora_A.data = peft_config["lora_init"]["lora_A"].to(
118
+ device=self.device, dtype=self.train_dtype
119
+ )
120
+ self.lora_B.data = peft_config["lora_init"]["lora_B"].to(
121
+ device=self.device, dtype=self.train_dtype
122
+ )
123
+ else:
124
+ # Init weights, as as the original LoRA implementation
125
+ nn.init.kaiming_uniform_(self.lora_A, a=np.sqrt(5))
126
+ nn.init.zeros_(self.lora_B)
127
+
128
+ def forward_lora(self, x: Tensor) -> Tensor: # output is self.train_dtype
129
+ return (
130
+ torch.matmul(
131
+ torch.matmul(self.peft_drop(x.to(self.lora_A.dtype)), self.lora_A),
132
+ self.lora_B,
133
+ )
134
+ * self.scaling
135
+ )
136
+
137
+ def forward(self, x: Tensor) -> Tensor:
138
+ x_dtype = x.dtype
139
+
140
+ # Forward with the base linear layer
141
+ out = self.linear_layer(x)
142
+
143
+ # LoRA
144
+ if self.train_bias:
145
+ out += (self.forward_lora(x) + self.bias).to(x_dtype)
146
+
147
+ else:
148
+ out += self.forward_lora(x).to(x_dtype)
149
+ if self.bias is not None:
150
+ out += self.bias
151
+
152
+ return out
153
+
154
+ def merge_and_quantize(self, quant_config: dict) -> nn.Module:
155
+ # not easy to figure out the type for "any" potential linear layer (nn.Linear, HQQLinear, etc.)
156
+ for _dtype in [float16, bfloat16, float32]:
157
+ try:
158
+ # Get initial weights
159
+ W = self.linear_layer(
160
+ torch.eye(self.in_features, device=self.device, dtype=_dtype)
161
+ ).t() # == self.linear_layer.dequantize()
162
+ except Exception:
163
+ pass
164
+
165
+ # Merge weights
166
+ W += (
167
+ (torch.matmul(self.lora_A.data, self.lora_B.data) * self.scaling)
168
+ .t()
169
+ .to(W.dtype)
170
+ )
171
+
172
+ # New HQQ layer
173
+ new_hqq_layer = HQQLinear(None, quant_config)
174
+ new_hqq_layer.bias = None if (self.bias is None) else self.bias.clone()
175
+ new_hqq_layer.quantize(W, **quant_config)
176
+
177
+ return new_hqq_layer
178
+
179
+ def cast(self, dtype: torch.dtype = float16):
180
+ self.lora_A.data = self.lora_A.data.to(dtype)
181
+ self.lora_B.data = self.lora_B.data.to(dtype)
182
+ if self.bias is not None:
183
+ self.bias.data = self.bias.data.to(dtype)
184
+ if isinstance(self.scaling, nn.Parameter):
185
+ self.scaling.data = self.scaling.data.to(dtype)
186
+ if isinstance(self.scaling, Tensor):
187
+ self.scaling = self.scaling.to(dtype)
188
+ return self
189
+
190
+ def state_dict(self):
191
+ return {
192
+ "lora_A": self.lora_A.data,
193
+ "lora_B": self.lora_B.data,
194
+ "scaling": self.scaling,
195
+ "bias": self.bias,
196
+ }
197
+
198
+ def load_state_dict(self, state_dict):
199
+ self.lora_A.data = state_dict["lora_A"].data.to(self.device)
200
+ self.lora_B.data = state_dict["lora_B"].data.to(self.device)
201
+
202
+ if state_dict["bias"] is not None:
203
+ self.bias.data = state_dict["bias"].data.to(self.device)
204
+
205
+ # Handle different use-cases of scaling
206
+ if isinstance(state_dict["scaling"], (int, float)):
207
+ self.scaling = state_dict["scaling"]
208
+ if isinstance(state_dict["scaling"], nn.Parameter):
209
+ self.scaling.data = state_dict["scaling"].data.to(self.device)
210
+ if isinstance(state_dict["scaling"], Tensor):
211
+ self.scaling = state_dict["scaling"].to(self.device)
212
+
213
+
214
+ # LoRA with fake quantization
215
+ class HQQLinearLoRAWithFakeQuant(HQQLinearLoRA):
216
+ def __init__(self, linear_layer: nn.Module, peft_config: dict):
217
+ super(HQQLinearLoRAWithFakeQuant, self).__init__(linear_layer, peft_config)
218
+ self.quant_param = peft_config["quant_param"]
219
+
220
+ # @torch.no_grad()
221
+ # @torch.compile()
222
+ def fake_quant(self, weight):
223
+ if self.quant_param:
224
+ W_q, meta = Quantizer.quantize(
225
+ weight, **self.quant_param, bitpack=False
226
+ ) # todo: clone() tensor
227
+ weight_est = Quantizer.dequantize(W_q, meta)
228
+ else:
229
+ weight_est = weight
230
+ return weight_est
231
+
232
+ def forward(self, x: Tensor) -> Tensor:
233
+ x_dtype = x.dtype
234
+
235
+ # Get initial weights
236
+ W = self.linear_layer(
237
+ torch.eye(self.in_features, device=self.device, dtype=x_dtype)
238
+ ).t() # == self.linear_layer.dequantize()
239
+
240
+ # Merge weights
241
+ W += (torch.matmul(self.lora_A, self.lora_B) * self.scaling).t().to(W.dtype)
242
+
243
+ # Fake quant
244
+ W = self.fake_quant(W).to(x_dtype)
245
+
246
+ # Matmul
247
+ out = torch.matmul(x, W.t())
248
+
249
+ # Bias
250
+ if self.bias is not None:
251
+ out += self.bias
252
+
253
+ out = out.to(x_dtype)
254
+
255
+ return out
256
+
257
+
258
+ # Experimental
259
+ class HQQLinearGroupedProj(nn.Module):
260
+ def __init__(self, linear_layer: nn.Module, peft_config: dict):
261
+ super().__init__()
262
+
263
+ # Device
264
+ self.device = (
265
+ linear_layer.device
266
+ if hasattr(linear_layer, "device")
267
+ else next(linear_layer.parameters()).device
268
+ )
269
+ self.train_dtype = (
270
+ peft_config["train_dtype"]
271
+ if ("train_dtype" in peft_config)
272
+ else torch.float
273
+ )
274
+
275
+ # Linear layer
276
+ self.linear_layer = linear_layer
277
+ self.in_features = linear_layer.in_features
278
+ self.out_features = linear_layer.out_features
279
+ self.bias = None if (linear_layer.bias is None) else linear_layer.bias.clone()
280
+
281
+ # Turn-off bias in the linear layer
282
+ self.linear_layer.bias = None
283
+
284
+ # Group proj
285
+ self.peft_config = peft_config
286
+ self.proj_size = peft_config["proj_size"]
287
+ self.proj_num = peft_config["proj_num"]
288
+ self.proj = nn.Parameter(
289
+ torch.stack(
290
+ [torch.eye(self.proj_size, dtype=self.train_dtype, device=self.device)]
291
+ * self.proj_num
292
+ )
293
+ )
294
+ if peft_config["zero_trainable"]:
295
+ self.linear_layer.meta["zero"] = nn.Parameter(
296
+ self.linear_layer.meta["zero"].to(self.train_dtype), requires_grad=True
297
+ )
298
+
299
+ @torch.compile()
300
+ def forward(self, x: Tensor) -> Tensor:
301
+ x_dtype = x.dtype
302
+
303
+ # Forward with base linear
304
+ with torch.no_grad():
305
+ W = self.linear_layer.dequantize().clone()
306
+ # W = self.linear_layer(torch.eye(self.in_features, device=self.device, dtype=x_dtype)).t()
307
+ shape = W.shape
308
+
309
+ # Grouped proj
310
+ proj_b, gs = self.proj.shape[0], self.proj.shape[1]
311
+ W = (
312
+ torch.matmul(self.proj, W.reshape((proj_b, gs, -1)).to(self.proj.dtype))
313
+ .to(x_dtype)
314
+ .reshape(shape)
315
+ )
316
+
317
+ # Matmul
318
+ out = torch.matmul(x, W.t())
319
+
320
+ # Bias
321
+ if self.bias is not None:
322
+ out += self.bias
323
+
324
+ out = out.to(x_dtype)
325
+
326
+ return out
327
+
328
+ def cast(self, dtype: torch.dtype = float16):
329
+ self.proj.data = self.proj.data.to(dtype)
330
+ self.linear_layer.meta["zero"] = self.linear_layer.meta["zero"].to(dtype)
331
+ if self.bias is not None:
332
+ if self.bias.requires_grad:
333
+ self.bias.data = self.bias.data.to(dtype)
334
+ else:
335
+ self.bias = self.bias.to(dtype)
336
+ return self
337
+
338
+ def state_dict(self):
339
+ return {
340
+ "proj": self.proj.data,
341
+ "bias": self.bias,
342
+ "peft_config": self.peft_config,
343
+ }
344
+
345
+ def load_state_dict(self, state_dict):
346
+ self.proj.data = state_dict["proj"].data.to(self.device)
347
+ self.bias = state_dict["bias"] if ("bias" in state_dict) else None
348
+ self.bias = self.bias.to(self.device) if (self.bias is not None) else None
349
+ self.peft_config = state_dict["peft_config"]
350
+
351
+
352
+ _HQQ_LORA_CLASSES = [HQQLinearLoRA, HQQLinearLoRAWithFakeQuant, HQQLinearGroupedProj]
353
+ _HQQ_LORA_MAPPING = {
354
+ "default": HQQLinearLoRA,
355
+ "lora_with_fakequant": HQQLinearLoRAWithFakeQuant,
356
+ "grouped_proj": HQQLinearGroupedProj,
357
+ }
358
+
359
+
360
+ def is_hqq_lora_layer(layer):
361
+ return type(layer) in _HQQ_LORA_CLASSES
362
+
363
+
364
+ ##################################################################################################################
365
+ def autoname_modules(model):
366
+ for name, module in model.named_modules():
367
+ module.name = name
368
+
369
+
370
+ # Patching functions
371
+ def patch_linear_add_peft(layer: nn.Module, patch_params: Union[dict,None]) -> nn.Module:
372
+ _peft_config = patch_params
373
+ if _peft_config:
374
+ lora_type = (
375
+ _peft_config["lora_type"] if ("lora_type" in _peft_config) else "default"
376
+ )
377
+ new_layer = _HQQ_LORA_MAPPING[lora_type](layer, _peft_config)
378
+ else:
379
+ new_layer = layer
380
+ return new_layer
381
+
382
+
383
+ def patch_linear_merge_peft(layer: nn.Module, patch_params: Union[dict,None]) -> nn.Module:
384
+ _quant_config = patch_params
385
+ if _quant_config:
386
+ new_layer = layer.merge_and_quantize(_quant_config)
387
+ del layer
388
+ cleanup()
389
+ else:
390
+ new_layer = layer
391
+ return new_layer
392
+
393
+
394
+ def patch_linear_cast_peft(layer: nn.Module, patch_params: Union[dict,None]) -> nn.Module:
395
+ if is_hqq_lora_layer(layer):
396
+ layer.cast(patch_params)
397
+ return layer
398
+
399
+
400
+ # Putting it all together
401
+ class PeftUtils:
402
+ @classmethod
403
+ def get_base_class(cls, model, base_class):
404
+ # Get base class
405
+ if base_class is None:
406
+ base_class = getattr(model, "base_class", None)
407
+
408
+ assert (
409
+ base_class is not None
410
+ ), "You need to provide the base HQQ class (LlamaHQQ, MixtralHQQ, etc.) as model.base_class or as an argument base_class=LlamaHQQ. Use AutoHQQHFMode if the model architecture is not supported."
411
+
412
+ return base_class
413
+
414
+ @classmethod
415
+ def add_lora(
416
+ cls, model, peft_config, base_class: bool = None, verbose: bool = True
417
+ ) -> None:
418
+ # Base classs
419
+ base_class = cls.get_base_class(model, base_class)
420
+
421
+ base_class.setup_model(model)
422
+
423
+ # Freeze
424
+ for param in model.parameters():
425
+ param.requires_grad = False
426
+
427
+ # Patch
428
+ base_class.patch_linearlayers(
429
+ model, patch_linear_add_peft, peft_config, verbose=verbose
430
+ )
431
+
432
+ # Rename modules
433
+ autoname_modules(model)
434
+
435
+ # add config to model
436
+ model.peft_config = peft_config
437
+
438
+ @classmethod
439
+ def merge_lora(
440
+ cls, model, merge_lora_params, base_class: bool = None, verbose: bool = True
441
+ ) -> None:
442
+ # Base classs
443
+ base_class = cls.get_base_class(model, base_class)
444
+
445
+ # Patch
446
+ base_class.patch_linearlayers(
447
+ model, patch_linear_merge_peft, merge_lora_params, verbose=verbose
448
+ )
449
+
450
+ @classmethod
451
+ def cast_lora_weights(
452
+ cls, model, dtype: torch.dtype, base_class: bool = None, verbose: bool = True
453
+ ) -> None:
454
+ # Base classs
455
+ base_class = cls.get_base_class(model, base_class)
456
+
457
+ base_class.setup_model(model)
458
+
459
+ # Linear tags
460
+ linear_tags = model.linear_tags
461
+
462
+ # Patch
463
+ base_class.patch_linearlayers(
464
+ model,
465
+ patch_linear_cast_peft,
466
+ dict([(linear_tag, dtype) for linear_tag in linear_tags]),
467
+ verbose=verbose,
468
+ )
469
+
470
+ @classmethod
471
+ def save_lora_weights(
472
+ cls, model, filename: str, base_class: bool = None, verbose: bool = True
473
+ ) -> None:
474
+ # Base classs
475
+ base_class = cls.get_base_class(model, base_class)
476
+
477
+ base_class.setup_model(model)
478
+
479
+ lora_global_params = {}
480
+
481
+ def _patch_linear_save_weights(layer, patch_params, return_layer=True):
482
+ if is_hqq_lora_layer(layer):
483
+ lora_global_params[layer.name] = layer.state_dict()
484
+ if return_layer:
485
+ return layer
486
+
487
+ # Linear tags
488
+ linear_tags = model.linear_tags
489
+
490
+ # Patch
491
+ base_class.patch_linearlayers(
492
+ model,
493
+ _patch_linear_save_weights,
494
+ dict([(linear_tag, None) for linear_tag in linear_tags]),
495
+ verbose=verbose,
496
+ )
497
+
498
+ # save
499
+ torch.save(
500
+ {"peft_config": model.peft_config, "parameters": lora_global_params},
501
+ filename,
502
+ )
503
+
504
+ @classmethod
505
+ def load_lora_weights(
506
+ cls, model, filename: str, base_class: bool = None, verbose: bool = True
507
+ ) -> None:
508
+ # Base classs
509
+ base_class = cls.get_base_class(model, base_class)
510
+
511
+ base_class.setup_model(model)
512
+
513
+ lora_data = torch.load(filename, map_location="cpu")
514
+
515
+ # V0.2 format: automatically creates lora modules if the model doesn't contain it
516
+ if ("peft_config" in lora_data) and ("parameters" in lora_data):
517
+ peft_config = lora_data["peft_config"]
518
+ lora_global_params = lora_data["parameters"]
519
+ if not hasattr(model, "peft_config"):
520
+ cls.add_lora(model=model, peft_config=peft_config)
521
+
522
+ # v0.1 format
523
+ else:
524
+ if not hasattr(model, "peft_config"):
525
+ raise Exception(
526
+ "Using older version of lora weights. LoRa modules should be manually added in this case."
527
+ )
528
+ lora_global_params = lora_data
529
+
530
+ def _patch_linear_load_weights(layer, patch_params, return_layer=True):
531
+ if is_hqq_lora_layer(layer):
532
+ layer.load_state_dict(lora_global_params[layer.name])
533
+ if return_layer:
534
+ return layer
535
+
536
+ # Linear tags
537
+ linear_tags = model.linear_tags
538
+
539
+ # Patch
540
+ base_class.patch_linearlayers(
541
+ model,
542
+ _patch_linear_load_weights,
543
+ dict([(linear_tag, None) for linear_tag in linear_tags]),
544
+ verbose=verbose,
545
+ )
lm-quant-toolkit/.deps/hqq/hqq/core/quantize.py ADDED
@@ -0,0 +1,948 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+ import copy
4
+ from enum import Enum
5
+ from typing import Union
6
+
7
+ import torch
8
+ from torch import Tensor, float16, int32, nn, uint8
9
+
10
+ from .bitpack import BitPack
11
+ from .optimize import optimize_weights_proximal
12
+ from .utils import is_divisible
13
+
14
+
15
+ # Main HQQ Quantizer
16
+ class Quantizer:
17
+ SUPPORTED_BITS = [8, 6, 5, 4, 3, 2, 1]
18
+ optimize_weights = optimize_weights_proximal
19
+
20
+ bit_to_packing = {
21
+ 8: "8bit_u8",
22
+ 6: "8bit_u8", # todo: bitpacking
23
+ 5: "8bit_u8", # todo: bitpacking
24
+ 4: "4bit_u8",
25
+ 3: "3bit_32",
26
+ 2: "2bit_u8",
27
+ 1: "1bit_u8",
28
+ }
29
+
30
+ pack = {
31
+ "8bit_u8": BitPack.pack_8bit_u8,
32
+ "4bit_u8": BitPack.pack_4bit_u8,
33
+ "3bit_32": BitPack.pack_3bit_32,
34
+ "2bit_u8": BitPack.pack_2bit_u8,
35
+ "1bit_u8": BitPack.pack_1bit_u8,
36
+ }
37
+
38
+ unpack = {
39
+ "8bit_u8": BitPack.unpack_8bit_u8,
40
+ "4bit_u8": BitPack.unpack_4bit_u8,
41
+ "3bit_32": BitPack.unpack_3bit_32,
42
+ "2bit_u8": BitPack.unpack_2bit_u8,
43
+ "1bit_u8": BitPack.unpack_1bit_u8,
44
+ }
45
+
46
+ unpack_view_dtype = {
47
+ "8bit_u8": uint8,
48
+ "4bit_u8": uint8,
49
+ "3bit_32": int32,
50
+ "2bit_u8": uint8,
51
+ "1bit_u8": uint8,
52
+ }
53
+
54
+ @classmethod
55
+ def quantize(
56
+ cls,
57
+ tensor: Tensor,
58
+ nbits: int = 4,
59
+ channel_wise: bool = True,
60
+ group_size: int = 64,
61
+ optimize: bool = False,
62
+ round_zero: bool = False,
63
+ axis: int = 0,
64
+ bitpack: bool = True,
65
+ compute_dtype: Union[torch.dtype, None] = None,
66
+ view_as_float: bool = False,
67
+ device: str = "cuda",
68
+ ) -> tuple:
69
+ assert nbits in Quantizer.SUPPORTED_BITS, (
70
+ "nbits=" + str(nbits) + " not supported."
71
+ )
72
+ assert axis in [0, 1], "axis should be either 0 or 1"
73
+ if group_size is not None:
74
+ assert is_divisible(tensor.numel(), group_size), (
75
+ "group_size should be divisble by the total tensor dimensions. shape: "
76
+ + str(tensor.shape)
77
+ + ", group_size: "
78
+ + str(group_size)
79
+ )
80
+
81
+ W = tensor.float()
82
+ shape = W.shape
83
+
84
+ # Reshape for grouping
85
+ if (group_size is not None) and channel_wise:
86
+ W = (
87
+ W.reshape([-1, group_size])
88
+ if (axis == 1)
89
+ else W.reshape([group_size, -1])
90
+ )
91
+
92
+ # Get min/max values
93
+ if not channel_wise:
94
+ _min, _max = W.min(), W.max()
95
+ optimize = False
96
+ else:
97
+ _min = W.min(axis=axis, keepdim=True)[0]
98
+ _max = W.max(axis=axis, keepdim=True)[0]
99
+
100
+ max_v = 2**nbits - 1
101
+ min_v = 0
102
+ min_max = [min_v, max_v]
103
+
104
+ # Note: here we work with the inverse of the scale to avoid division and quantize instead via W*scale + zero, the scale is inverted later on.
105
+ scale = (max_v / (_max - _min)).clamp(
106
+ max=2e4
107
+ ) # clamp to avoid half-precision problems
108
+ zero = -_min * scale
109
+
110
+ # Round zero as in: https://github.com/casper-hansen/AutoAWQ/blob/main/awq/quantize/quantizer.py#L42C9-L42C14
111
+ if round_zero:
112
+ zero = torch.round(zero)
113
+
114
+ # Fine-tune weights
115
+ # if False:
116
+ if optimize:
117
+ W_q, scale, zero = Quantizer.optimize_weights(
118
+ tensor=W,
119
+ scale=scale,
120
+ zero=zero,
121
+ min_max=min_max,
122
+ axis=axis,
123
+ device=device,
124
+ )
125
+ else:
126
+ W_q = torch.round(W * scale + zero).clamp(min_max[0], min_max[1])
127
+
128
+ # Store meta-data (we invert the scale for dequantization)
129
+ meta = {
130
+ "nbits": nbits,
131
+ "group_size": group_size,
132
+ "shape": shape,
133
+ "scale": 1.0 / scale,
134
+ "zero": zero,
135
+ "axis": axis,
136
+ "packing": Quantizer.bit_to_packing[nbits],
137
+ }
138
+ meta["unpack_view_dtype"] = Quantizer.unpack_view_dtype[meta["packing"]]
139
+
140
+ # Pack bits
141
+ meta["view_as_float"] = view_as_float
142
+ if bitpack:
143
+ W_q = Quantizer.pack[meta["packing"]](W_q)
144
+ if view_as_float:
145
+ W_q = W_q.view(
146
+ torch.float32 if compute_dtype is None else compute_dtype
147
+ ) # store quantized weights as compute_dtype
148
+ else:
149
+ W_q = W_q.to(tensor.dtype)
150
+ meta["packing"] = None
151
+
152
+ # cleanup
153
+ del W, _min, _max
154
+ torch.cuda.empty_cache()
155
+
156
+ return W_q, meta
157
+
158
+ # Main dequantization: bit_unpacking > (W_q - z)*s > reshape
159
+ @classmethod
160
+ def dequantize(cls, W_q: Tensor, meta: dict) -> Tensor:
161
+ compute_dtype = meta["compute_dtype"] if ("compute_dtype" in meta) else float16
162
+ if meta["packing"]:
163
+ if meta["view_as_float"]:
164
+ W_q = W_q.view(meta["unpack_view_dtype"])
165
+ W_r = Quantizer.unpack[meta["packing"]](W_q, dtype=compute_dtype)
166
+ if meta["nbits"] == 3:
167
+ W_r = W_r[
168
+ : meta["group_size"]
169
+ if meta["axis"] == 0
170
+ else meta["shape"][0] * meta["shape"][1] // meta["group_size"]
171
+ ]
172
+ else:
173
+ W_r = W_q.to(compute_dtype)
174
+ zero = meta["zero"].to(compute_dtype)
175
+ scale = meta["scale"].to(compute_dtype)
176
+ W_r = ((W_r - zero) * scale).reshape(meta["shape"])
177
+ return W_r
178
+
179
+ @classmethod
180
+ def to_inplace(cls, W_q: Tensor, meta: dict, device) -> tuple:
181
+ compute_dtype = meta["compute_dtype"] if ("compute_dtype" in meta) else float16
182
+ if W_q is not None:
183
+ W_q = W_q.to(device).contiguous()
184
+ for key in meta:
185
+ if type(meta[key]) == torch.Tensor:
186
+ meta[key] = (
187
+ (
188
+ meta[key].to(compute_dtype)
189
+ if torch.is_floating_point(meta[key])
190
+ else meta[key]
191
+ )
192
+ .to(device)
193
+ .contiguous()
194
+ )
195
+ return W_q, meta
196
+
197
+ @classmethod
198
+ def to_ooplace(cls, W_q: Tensor, meta: dict, device) -> tuple:
199
+ compute_dtype = meta["compute_dtype"] if ("compute_dtype" in meta) else float16
200
+ if W_q is not None:
201
+ W_q_c = W_q.to(device).contiguous()
202
+ else:
203
+ W_q_c = None
204
+ meta_c = {}
205
+ for key in meta:
206
+ if type(meta[key]) == torch.Tensor:
207
+ meta_c[key] = (
208
+ (
209
+ meta[key].to(compute_dtype)
210
+ if torch.is_floating_point(meta[key])
211
+ else meta[key]
212
+ )
213
+ .to(device)
214
+ .contiguous()
215
+ )
216
+ else:
217
+ meta_c[key] = meta[key]
218
+ return W_q_c, meta_c
219
+
220
+ @classmethod
221
+ def cuda(cls, W_q: Tensor, meta: dict, device) -> tuple:
222
+ return Quantizer.to_inplace(W_q, meta, device=device)
223
+
224
+ @classmethod
225
+ def cpu(cls, W_q: Tensor, meta: dict) -> tuple:
226
+ return Quantizer.to_ooplace(W_q, meta, device="cpu")
227
+
228
+
229
+ # Check Aten/CUDA backend if available
230
+ hqq_aten_is_available = False
231
+ try:
232
+ import hqq_aten
233
+
234
+ hqq_aten_is_available = True
235
+ except Exception:
236
+ hqq_aten = None
237
+ hqq_aten_is_available = False
238
+
239
+
240
+ class HQQBackend(Enum):
241
+ # Name of the forward functions
242
+ PYTORCH = "forward_pytorch_backprop"
243
+ PYTORCH_COMPILE = "forward_pytorch_backprop_compile"
244
+ ATEN = "forward_aten_backprop"
245
+
246
+ # Alias for backward compatibility
247
+ PYTORCH_BACKPROP = "forward_pytorch_backprop"
248
+ PYTORCH_BACKPROP_COMPILE = "forward_pytorch_backprop_compile"
249
+ ATEN_BACKPROP = "forward_aten_backprop"
250
+
251
+ PYTORCH_FORWARD = "forward_pytorch"
252
+ PYTORCH_FORWARD_COMPILE = "forward_pytorch_compile"
253
+ ATEN_FORWARD = "forward_aten"
254
+
255
+ # Experimental
256
+ ATEN_FORWARD_INT8 = "forward_aten_int8"
257
+
258
+
259
+ # No cache: less memory, slower
260
+ class HQQMatmulNoCacheDeq(torch.autograd.Function):
261
+ @staticmethod
262
+ def forward(x: Tensor, dequantize, bias: Tensor):
263
+ out = torch.matmul(x, dequantize().t())
264
+ if bias is not None:
265
+ out += bias
266
+ return out
267
+
268
+ @staticmethod
269
+ def setup_context(ctx, inputs, outputs):
270
+ x, dequantize, bias = inputs
271
+ ctx.save_for_backward(x, bias)
272
+ ctx.dequantize = dequantize
273
+
274
+ @staticmethod
275
+ def backward(ctx, grad_output):
276
+ x, bias = ctx.saved_tensors
277
+
278
+ grad_input = grad_weight = grad_bias = None
279
+
280
+ if ctx.needs_input_grad[0]:
281
+ grad_input = torch.matmul(grad_output, ctx.dequantize())
282
+
283
+ # weight grad for frozen quantized weights not defined
284
+ # if ctx.needs_input_grad[1]:
285
+ # grad_weight = torch.matmul(grad_output.t(), x)
286
+
287
+ if bias is not None and ctx.needs_input_grad[2]:
288
+ grad_bias = grad_output.sum(0)
289
+
290
+ return grad_input, grad_weight, grad_bias
291
+
292
+
293
+ class HQQMatmulNoCacheMul(torch.autograd.Function):
294
+ @staticmethod
295
+ def forward(x, matmul, bias):
296
+ out = matmul(x, transpose=True)
297
+ if bias is not None:
298
+ out += bias
299
+ return out
300
+
301
+ @staticmethod
302
+ def setup_context(ctx, inputs, outputs):
303
+ x, matmul, bias = inputs
304
+ ctx.save_for_backward(x, bias)
305
+ ctx.matmul = matmul
306
+
307
+ @staticmethod
308
+ def backward(ctx, grad_output):
309
+ x, bias = ctx.saved_tensors
310
+
311
+ grad_input = grad_weight = grad_bias = None
312
+
313
+ if ctx.needs_input_grad[0]:
314
+ grad_input = ctx.matmul(grad_output, transpose=False)
315
+
316
+ # weight grad for frozen quantized weights not defined
317
+ # if ctx.needs_input_grad[1]:
318
+ # grad_weight = torch.matmul(grad_output.t(), x)
319
+
320
+ if bias is not None and ctx.needs_input_grad[2]:
321
+ grad_bias = grad_output.sum(0)
322
+
323
+ return grad_input, grad_weight, grad_bias
324
+
325
+
326
+ # Cache dequantized tensor: Faster but needs more memory
327
+ class HQQMatmulCachedDeq(torch.autograd.Function):
328
+ @staticmethod
329
+ def forward(ctx, x, hqq_layer, bias):
330
+ weight_tmp = hqq_layer.dequantize()
331
+ out = torch.matmul(x, weight_tmp.t())
332
+ if bias is not None:
333
+ out += bias
334
+
335
+ ctx.save_for_backward(x, bias, weight_tmp)
336
+ return out
337
+
338
+ @staticmethod
339
+ def backward(ctx, grad_output):
340
+ x, bias, weight_tmp = ctx.saved_tensors
341
+
342
+ grad_input = grad_weight = grad_bias = None
343
+
344
+ if ctx.needs_input_grad[0]:
345
+ grad_input = torch.matmul(grad_output, weight_tmp)
346
+
347
+ del weight_tmp
348
+
349
+ if bias is not None and ctx.needs_input_grad[2]:
350
+ grad_bias = grad_output.sum(0)
351
+
352
+ return grad_input, grad_weight, grad_bias
353
+
354
+
355
+ # Main linear layer
356
+ class HQQLinear(nn.Module):
357
+ # Default backend
358
+ backend = HQQBackend.PYTORCH
359
+
360
+ def __init__(
361
+ self,
362
+ linear_layer: Union[nn.Module, None],
363
+ quant_config: dict,
364
+ del_orig: bool = True,
365
+ compute_dtype: torch.dtype = float16,
366
+ device: str = "cuda",
367
+ initialize: bool = True,
368
+ ):
369
+ super().__init__()
370
+ self.ready = False
371
+ self.in_gpu = False
372
+ self.bias = None
373
+ self.device = device
374
+ self.compute_dtype = compute_dtype
375
+ self.quant_config = copy.deepcopy(quant_config)
376
+ self.del_orig = del_orig
377
+ self.offload_meta = (
378
+ self.quant_config.pop("offload_meta")
379
+ if (self.quant_config is not None)
380
+ else None
381
+ )
382
+
383
+ self.set_backend(HQQLinear.backend)
384
+
385
+ self.linear_layer = linear_layer
386
+ self.W_q = None
387
+ self.meta = None
388
+
389
+ if initialize:
390
+ self.initialize()
391
+
392
+ def initialize(self):
393
+ if self.linear_layer is not None:
394
+ self.quantize(self.linear_layer.weight.data, **self.quant_config)
395
+ self.bias = (
396
+ None
397
+ if (self.linear_layer.bias is None)
398
+ else self.linear_layer.bias.to(
399
+ device=self.device, dtype=self.compute_dtype
400
+ )
401
+ )
402
+
403
+ if self.del_orig:
404
+ del self.linear_layer
405
+ torch.cuda.empty_cache()
406
+
407
+ def extra_repr(self) -> str:
408
+ out = ""
409
+ if hasattr(self, "meta"):
410
+ if self.meta is not None:
411
+ in_features, out_features = self.meta["shape"][::-1]
412
+ out = f"in_features={in_features}, out_features={out_features}, bias={self.bias is not None}"
413
+ return out
414
+
415
+ # Set backends
416
+ @classmethod
417
+ def set_backend(cls, backend: HQQBackend):
418
+ if "aten" in backend.value:
419
+ if hqq_aten_is_available is False:
420
+ print(
421
+ "ATEN/CUDA backend not availabe. Make sure you install the hqq_aten library."
422
+ )
423
+ return
424
+ print(
425
+ "Warning: the ATEN/CUDA backend only supports axis=0 and GPU runtime."
426
+ )
427
+ HQQLinear.backend = backend
428
+ cls.forward = getattr(cls, backend.value)
429
+
430
+ # TODO: rewrite this mess
431
+ def cuda(self, device):
432
+ self.meta["compute_dtype"] = self.compute_dtype
433
+
434
+ if type(self.W_q) == nn.parameter.Parameter:
435
+ self.W_q.data, self.meta = Quantizer.cuda(self.W_q.data, self.meta, device)
436
+ else:
437
+ self.W_q, self.meta = Quantizer.cuda(self.W_q, self.meta, device)
438
+
439
+ if self.meta["quant_zero"]:
440
+ if "zero_q" in self.meta:
441
+ self.meta["zero_q"], self.meta["meta_zero"] = Quantizer.cuda(
442
+ self.meta["zero_q"], self.meta["meta_zero"], device
443
+ )
444
+ else:
445
+ _, self.meta["meta_zero"] = Quantizer.cuda(
446
+ None, self.meta["meta_zero"], device
447
+ )
448
+ else:
449
+ self.meta["zero"] = self.meta["zero"].to(device)
450
+
451
+ if self.meta["quant_scale"]:
452
+ if "scale_q" in self.meta:
453
+ self.meta["scale_q"], self.meta["meta_scale"] = Quantizer.cuda(
454
+ self.meta["scale_q"], self.meta["meta_scale"], device
455
+ )
456
+ else:
457
+ _, self.meta["meta_scale"] = Quantizer.cuda(
458
+ None, self.meta["meta_scale"], device
459
+ )
460
+ else:
461
+ self.meta["scale"] = self.meta["scale"].to(device)
462
+
463
+ # #Use zero/scale with streams for dequantization is faster than packing in "zero_scale"
464
+ # for key in ["zero", "zero_q", "scale", "scale_q"]:
465
+ # if((key in self.meta) and self.offload_meta):
466
+ # self.meta[key] = self.meta[key].contiguous().cpu().pin_memory()
467
+
468
+ if self.offload_meta:
469
+ if "zero_scale" not in self.meta:
470
+ if self.meta["quant_scale"] and self.meta["quant_zero"]:
471
+ self.meta["zero_scale"] = torch.stack(
472
+ (self.meta["zero_q"], self.meta["scale_q"])
473
+ )
474
+ del self.meta["scale_q"], self.meta["zero_q"]
475
+ else:
476
+ self.meta["zero_scale"] = torch.stack(
477
+ (self.meta["zero"], self.meta["scale"])
478
+ ).to(self.compute_dtype)
479
+ del self.meta["scale"], self.meta["zero"]
480
+
481
+ self.meta["zero_scale"] = (
482
+ self.meta["zero_scale"].contiguous().cpu().pin_memory()
483
+ )
484
+
485
+ if self.bias is not None:
486
+ self.bias = self.bias.to(device=device, dtype=self.compute_dtype)
487
+
488
+ self.W_q = nn.Parameter(self.W_q, requires_grad=False)
489
+ self.device = device
490
+ self.in_gpu = True
491
+
492
+ torch.cuda.empty_cache()
493
+
494
+ return self
495
+
496
+ def to(self, *args, **kwargs):
497
+ # TODO: later
498
+ return self
499
+
500
+ # TODO: later
501
+ # def to_empty(self, device, recurse=True):
502
+ # return self.cuda(device)
503
+
504
+ def type(self, dst_type):
505
+ # TODO: later
506
+ return self
507
+
508
+ def half(self, *args, **kwargs):
509
+ return self
510
+
511
+ def bfloat16(self, *args, **kwargs):
512
+ # TODO: later
513
+ return self
514
+
515
+ def float(self, *args, **kwargs):
516
+ # TODO: later
517
+ return self
518
+
519
+ def double(self, *args, **kwargs):
520
+ return self
521
+
522
+ def cpu(self):
523
+ # TODO: later
524
+ return self
525
+
526
+ def state_dict(self, *args, **kwargs): # nn.Module override compatible
527
+ state = {"W_q": self.W_q, "meta": self.meta, "bias": self.bias}
528
+ if "destination" in kwargs and "prefix" in kwargs:
529
+ for key, value in state.items():
530
+ kwargs["destination"][kwargs["prefix"] + key] = value
531
+ return state
532
+
533
+ def _load_from_state_dict(
534
+ self,
535
+ state_dict,
536
+ prefix,
537
+ local_metadata,
538
+ strict,
539
+ missing_keys,
540
+ unexpected_keys,
541
+ error_msgs,
542
+ ):
543
+ W_q_key = prefix + "W_q"
544
+ meta_key = prefix + "meta"
545
+ bias_key = prefix + "bias"
546
+
547
+ if W_q_key not in state_dict:
548
+ missing_keys.append(W_q_key)
549
+ if meta_key not in state_dict:
550
+ missing_keys.append(meta_key)
551
+ if missing_keys:
552
+ return # Can't load weights if either weight or meta is missing
553
+
554
+ W_q = nn.Parameter(state_dict.pop(W_q_key), requires_grad=False)
555
+ meta = state_dict.pop(meta_key)
556
+ bias = state_dict.pop(bias_key, None)
557
+
558
+ unexpected_keys += state_dict.keys()
559
+
560
+ self.load_state_dict({"W_q": W_q, "meta": meta, "bias": bias}, strict)
561
+
562
+ def load_state_dict(self, state_dict, strict=True, assign=False):
563
+ self.W_q = state_dict["W_q"]
564
+ self.meta = state_dict["meta"]
565
+ self.bias = state_dict["bias"] if ("bias" in state_dict) else None
566
+
567
+ # Meta-data offloading
568
+ self.offload_meta = False
569
+ for key in ["zero", "zero_q", "scale", "scale_q", "zero_scale"]:
570
+ if key in self.meta:
571
+ if self.meta[key].device.type == "cpu":
572
+ self.offload_meta = True
573
+ self.meta[key] = self.meta[key].contiguous().pin_memory()
574
+
575
+ # Float view settings
576
+ if "unpack_view_dtype" not in self.meta:
577
+ self.meta["unpack_view_dtype"] = Quantizer.unpack_view_dtype[
578
+ self.meta["packing"]
579
+ ]
580
+
581
+ if "view_as_float" not in self.meta:
582
+ self.meta["view_as_float"] = False
583
+
584
+ if "meta_scale" in self.meta:
585
+ if "view_as_float" not in self.meta["meta_scale"]:
586
+ self.meta["meta_scale"]["view_as_float"] = False
587
+
588
+ if "meta_zero" in self.meta:
589
+ if "view_as_float" not in self.meta["meta_zero"]:
590
+ self.meta["meta_zero"]["view_as_float"] = False
591
+
592
+ # Check GPU
593
+ self.cuda(self.device)
594
+ self.ready = True
595
+
596
+ # Set in_features/out_features
597
+ self.in_features, self.out_features = self.meta["shape"][::-1]
598
+
599
+ def quantize(
600
+ self,
601
+ W: Tensor,
602
+ weight_quant_params: dict,
603
+ scale_quant_params: dict,
604
+ zero_quant_params: dict,
605
+ ) -> None:
606
+ quant_scale = scale_quant_params is not None
607
+ quant_zero = zero_quant_params is not None
608
+
609
+ self.in_features, self.out_features = W.t().shape
610
+
611
+ # Quantize
612
+ W_q, meta = Quantizer.quantize(
613
+ W,
614
+ device=self.device,
615
+ compute_dtype=self.compute_dtype,
616
+ **weight_quant_params,
617
+ )
618
+ meta.update({"quant_scale": quant_scale, "quant_zero": quant_zero})
619
+
620
+ if meta["quant_zero"]:
621
+ meta["zero_q"], meta["meta_zero"] = Quantizer.quantize(
622
+ meta["zero"],
623
+ device=self.device,
624
+ view_as_float=False,
625
+ **zero_quant_params,
626
+ )
627
+ del meta["zero"]
628
+ meta["meta_zero"]["compute_dtype"] = self.compute_dtype
629
+
630
+ if meta["quant_scale"]:
631
+ meta["scale_q"], meta["meta_scale"] = Quantizer.quantize(
632
+ meta["scale"],
633
+ device=self.device,
634
+ view_as_float=False,
635
+ **scale_quant_params,
636
+ )
637
+ del meta["scale"]
638
+ meta["meta_scale"]["compute_dtype"] = self.compute_dtype
639
+
640
+ self.W_q = W_q
641
+ self.meta = meta
642
+ self.cuda(self.device)
643
+ self.ready = True
644
+
645
+ def dequantize(self):
646
+ assert self.ready, "model was not quantized"
647
+ W_q, meta = self.W_q, self.meta
648
+ device = W_q.device
649
+ del_keys = set()
650
+
651
+ # Zero/Scale packed together
652
+ if "zero_scale" in meta:
653
+ zero_scale = meta["zero_scale"].to(device=device)
654
+
655
+ if zero_scale.dtype == uint8:
656
+ meta["zero_q"], meta["scale_q"] = zero_scale[0], zero_scale[1]
657
+ del_keys.update({"zero_q", "scale_q"})
658
+ else:
659
+ meta["zero"], meta["scale"] = zero_scale[0], zero_scale[1]
660
+ del_keys.update({"zero", "scale"})
661
+
662
+ if meta["quant_zero"]:
663
+ meta["zero"] = Quantizer.dequantize(
664
+ meta["zero_q"].to(device=device), meta["meta_zero"]
665
+ )
666
+ del_keys.add("zero")
667
+
668
+ if meta["quant_scale"]:
669
+ meta["scale"] = Quantizer.dequantize(
670
+ meta["scale_q"].to(device=device), meta["meta_scale"]
671
+ )
672
+ del_keys.add("scale")
673
+
674
+ W_est = Quantizer.dequantize(W_q, meta)
675
+
676
+ # Cleanup
677
+ for key in del_keys:
678
+ del meta[key]
679
+ return W_est
680
+
681
+ def matmul(self, x: Tensor, transpose: bool = True) -> Tensor:
682
+ weight = self.dequantize()
683
+ return torch.matmul(x, weight.t() if (transpose) else weight)
684
+
685
+ @torch.compile()
686
+ def matmul_compile(self, *args, **kwargs):
687
+ return self.matmul(*args, **kwargs)
688
+
689
+ def forward_pytorch_backprop(self, x: Tensor) -> Tensor:
690
+ return HQQMatmulNoCacheMul.apply(x, self.matmul, self.bias)
691
+
692
+ def forward_pytorch_backprop_compile(self, x: Tensor) -> Tensor:
693
+ return HQQMatmulNoCacheMul.apply(x, self.matmul_compile, self.bias)
694
+
695
+ def forward_pytorch(self, x: Tensor) -> Tensor:
696
+ out = torch.matmul(x, self.dequantize().t())
697
+ if self.bias is not None:
698
+ out += self.bias
699
+ return out
700
+
701
+ @torch.compile()
702
+ def forward_pytorch_compile(self, x: Tensor) -> Tensor:
703
+ return self.forward_pytorch(x)
704
+
705
+ ############################################################################################
706
+ # ATen C++ / CUDA Bacekdn
707
+ ##########################################################################################
708
+ # Requires building the aten backend
709
+ @torch.jit.ignore
710
+ def dequantize_Wq_aten(self, W_q: Tensor, meta: dict):
711
+ if meta["view_as_float"]:
712
+ W_q = W_q.view(meta["unpack_view_dtype"])
713
+
714
+ return hqq_aten.dequantize(
715
+ W_q,
716
+ meta["scale"],
717
+ meta["zero"],
718
+ meta["shape"],
719
+ meta["group_size"] if (meta["group_size"]) else -1,
720
+ meta["nbits"],
721
+ meta["axis"],
722
+ meta["packing"],
723
+ )
724
+
725
+ def dequantize_aten(self):
726
+ # Dequantize
727
+ assert self.ready, "model was not quantized"
728
+ assert (
729
+ self.meta["axis"] == 0
730
+ ), "only axis=0 is supported. Use HQQLinear.set_backend(HQQBackend.PYTORCH) instead."
731
+
732
+ W_q, meta = self.W_q, self.meta
733
+ device = W_q.device
734
+ del_keys = set()
735
+
736
+ # Zero/Scale packed together
737
+ if "zero_scale" in meta:
738
+ zero_scale = meta["zero_scale"].to(device=device, non_blocking=True)
739
+ if zero_scale.dtype == uint8:
740
+ meta["zero_q"], meta["scale_q"] = zero_scale[0], zero_scale[1]
741
+ del_keys.update({"zero_q", "scale_q"})
742
+ else:
743
+ meta["zero"], meta["scale"] = zero_scale[0], zero_scale[1]
744
+ del_keys.update({"zero", "scale"})
745
+
746
+ # Dequantize zero_q / scale_q with device loading
747
+ if meta["quant_zero"]:
748
+ if meta["meta_zero"]["group_size"]:
749
+ meta["zero"] = self.dequantize_Wq_aten(
750
+ meta["zero_q"].to(device=device), meta["meta_zero"]
751
+ )
752
+ else:
753
+ meta["zero"] = Quantizer.dequantize(
754
+ meta["zero_q"].to(device=device), meta["meta_zero"]
755
+ )
756
+ del_keys.add("zero")
757
+
758
+ if meta["quant_scale"]:
759
+ if meta["meta_scale"]["group_size"]:
760
+ meta["scale"] = self.dequantize_Wq_aten(
761
+ meta["scale_q"].to(device=device), meta["meta_scale"]
762
+ )
763
+ else:
764
+ meta["scale"] = Quantizer.dequantize(
765
+ meta["scale_q"].to(device=device), meta["meta_scale"]
766
+ )
767
+ del_keys.add("scale")
768
+
769
+ # Reconstruct the weights
770
+ W_est = self.dequantize_Wq_aten(W_q, meta)
771
+
772
+ # Cleanup
773
+ for key in del_keys:
774
+ del meta[key]
775
+
776
+ return W_est
777
+
778
+ # Much faster with data-offloading zero_q/scale_q but takes more VRAM
779
+ def dequantize_aten_with_streams(self):
780
+ # Create streams
781
+ if hasattr(self, "stream_zero") is False:
782
+ self.stream_zero = torch.cuda.Stream()
783
+ self.stream_scale = torch.cuda.Stream()
784
+
785
+ # Dequantize
786
+ assert self.ready, "model was not quantized"
787
+ W_q, meta = self.W_q, self.meta
788
+ device = W_q.device
789
+ del_keys = set()
790
+
791
+ # Zero/Scale packed together
792
+ if "zero_scale" in meta:
793
+ zero_scale = meta["zero_scale"].to(device=device, non_blocking=True)
794
+ if zero_scale.dtype == uint8:
795
+ meta["zero_q"], meta["scale_q"] = zero_scale[0], zero_scale[1]
796
+ del_keys.update({"zero_q", "scale_q"})
797
+ else:
798
+ meta["zero"], meta["scale"] = zero_scale[0], zero_scale[1]
799
+ del_keys.update({"zero", "scale"})
800
+
801
+ # Using non_blocking=False for the moment, otherwise it can result in strange behaviors
802
+ non_blocking = False
803
+ with torch.cuda.stream(self.stream_zero):
804
+ if meta["quant_zero"]:
805
+ if meta["meta_zero"]["group_size"]:
806
+ meta["zero"] = self.dequantize_Wq_aten(
807
+ meta["zero_q"].to(device=device, non_blocking=non_blocking),
808
+ meta["meta_zero"],
809
+ )
810
+ else:
811
+ meta["zero"] = Quantizer.dequantize(
812
+ meta["zero_q"].to(device=device, non_blocking=non_blocking),
813
+ meta["meta_zero"],
814
+ )
815
+ del_keys.add("zero")
816
+
817
+ with torch.cuda.stream(self.stream_scale):
818
+ if meta["quant_scale"]:
819
+ if meta["meta_scale"]["group_size"]:
820
+ meta["scale"] = self.dequantize_Wq_aten(
821
+ meta["scale_q"].to(device=device, non_blocking=non_blocking),
822
+ meta["meta_scale"],
823
+ )
824
+ else:
825
+ meta["scale"] = Quantizer.dequantize(
826
+ meta["scale_q"].to(device=device, non_blocking=non_blocking),
827
+ meta["meta_scale"],
828
+ )
829
+ del_keys.add("scale")
830
+
831
+ # Wait for streams to finish
832
+ torch.cuda.synchronize()
833
+
834
+ # Reconstruct the weights
835
+ W_est = self.dequantize_Wq_aten(W_q, meta)
836
+
837
+ # Cleanup
838
+ for key in del_keys:
839
+ del meta[key]
840
+
841
+ return W_est
842
+
843
+ def forward_aten(self, x: Tensor) -> Tensor:
844
+ W_est = self.dequantize_aten()
845
+ out = torch.matmul(x, W_est.t())
846
+ if self.bias is not None:
847
+ out += self.bias
848
+
849
+ return out
850
+
851
+ def forward_aten_backprop(self, x: Tensor) -> Tensor:
852
+ return HQQMatmulNoCacheDeq.apply(x, self.dequantize_aten, self.bias)
853
+
854
+ # TODO: as fused kernel in CUDA
855
+ def _get_int8_matrix(self, M):
856
+ scale = torch.abs(M).amax() / 127.0
857
+ return torch.round(M / scale).to(torch.int8), scale.float()
858
+
859
+ # TODO: in ATEN
860
+ @torch.compile()
861
+ def _matmul_int8(self, A, B):
862
+ dtype = A.dtype
863
+ A, scale_A = self._get_int8_matrix(A)
864
+ B, scale_B = self._get_int8_matrix(B)
865
+ return (torch._int_mm(A, B) * (scale_A * scale_B)).to(dtype)
866
+
867
+ def forward_aten_int8(self, x: Tensor) -> Tensor:
868
+ W_est = self.dequantize_aten()
869
+ out = self._matmul_int8(x[0], W_est.t())[None, ...]
870
+ if self.bias is not None:
871
+ out += self.bias
872
+
873
+ return out
874
+
875
+ # TODO: fix this hack later for open_clip
876
+ @property
877
+ def weight(self):
878
+ return self.dequantize()
879
+
880
+
881
+ def hqq_base_quant_config(
882
+ nbits: int = 4,
883
+ group_size: int = 64,
884
+ quant_zero: bool = True,
885
+ quant_scale: bool = False,
886
+ offload_meta: bool = False, # meta-data should be quantized with the same settings to use offload_meta
887
+ view_as_float: bool = False,
888
+ axis: int = 0,
889
+ mixed: bool = False, # Auto tune nbits and group_size according to weight distribution
890
+ budget: float = 0.0, # overall quantization budget as bits per parameter
891
+ ):
892
+ assert (
893
+ nbits in Quantizer.SUPPORTED_BITS
894
+ ), "nbits value not supported. Check Quantizer.SUPPORTED_BITS."
895
+ if group_size is not None:
896
+ assert is_divisible(
897
+ group_size, 8
898
+ ), "Invalid group_size param: the value should be a multiple of 8."
899
+ weight_quant_params = {
900
+ "nbits": nbits,
901
+ "channel_wise": True,
902
+ "group_size": group_size,
903
+ "optimize": True,
904
+ "round_zero": True if nbits == 4 else False,
905
+ "axis": axis,
906
+ "view_as_float": view_as_float,
907
+ }
908
+
909
+ if offload_meta:
910
+ if quant_scale != quant_zero:
911
+ # print(colored("quant_zero and quant_scale must be the same when offload_meta is set to True. Setting quant_scale=quant_zero." , 'yellow'))
912
+ quant_scale = quant_zero
913
+
914
+ scale_quant_params = (
915
+ {"nbits": 8, "channel_wise": True, "group_size": 128, "optimize": False}
916
+ if (quant_scale)
917
+ else None
918
+ )
919
+ zero_quant_params = (
920
+ {"nbits": 8, "channel_wise": True, "group_size": 128, "optimize": False}
921
+ if (quant_zero)
922
+ else None
923
+ )
924
+
925
+ else:
926
+ scale_quant_params = (
927
+ {"nbits": 8, "channel_wise": True, "group_size": 128, "optimize": False}
928
+ if (quant_scale)
929
+ else None
930
+ )
931
+ zero_quant_params = (
932
+ {"nbits": 8, "channel_wise": False, "group_size": None, "optimize": False}
933
+ if (quant_zero)
934
+ else None
935
+ )
936
+
937
+ return {
938
+ "weight_quant_params": weight_quant_params,
939
+ "scale_quant_params": scale_quant_params,
940
+ "zero_quant_params": zero_quant_params,
941
+ "offload_meta": offload_meta,
942
+ "mixed": mixed,
943
+ "budget": budget,
944
+ }
945
+
946
+
947
+ # Alias: follow similar Auto-GPTQ naming
948
+ BaseQuantizeConfig = hqq_base_quant_config
lm-quant-toolkit/.deps/hqq/hqq/core/utils.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+ import torch
4
+ import gc
5
+ import numpy as np
6
+ from typing import Union
7
+
8
+
9
+ def cleanup() -> None:
10
+ try:
11
+ torch.cuda.empty_cache()
12
+ except Exception:
13
+ pass
14
+ gc.collect()
15
+
16
+
17
+ def is_divisible(val1: int, val2: int) -> bool:
18
+ return int(val2 * np.ceil(val1 / val2)) == val1
19
+
20
+
21
+ def zero_pad_row(
22
+ tensor: torch.Tensor, num_rows: int, dtype: Union[torch.dtype, None] = None
23
+ ) -> torch.Tensor:
24
+ out = torch.zeros(
25
+ [num_rows, tensor.shape[1]],
26
+ device=tensor.device,
27
+ dtype=tensor.dtype if (dtype is None) else dtype,
28
+ )
29
+ out[: len(tensor)] = tensor
30
+
31
+ return out
lm-quant-toolkit/.deps/hqq/hqq/engine/__init__.py ADDED
File without changes
lm-quant-toolkit/.deps/hqq/hqq/engine/base.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+ from abc import abstractmethod
4
+ from typing import Union
5
+
6
+ import torch
7
+ from torch import float16
8
+
9
+ from ..models.base import BaseHQQModel
10
+
11
+ # Wrapper that makes it easier to add quantization support to different engines (HF, VLLM, etc.)
12
+
13
+
14
+ class HQQWrapper:
15
+ @abstractmethod
16
+ def _get_arch_key_from_save_dir(cls, save_dir: str):
17
+ pass
18
+
19
+ @classmethod
20
+ def _get_hqq_class(cls, arg):
21
+ arch = arg if (isinstance(arg, str)) else arg.arch_key
22
+ return cls._HQQ_REGISTRY[arch]
23
+
24
+ @classmethod
25
+ def _validate_params(cls, params: dict):
26
+ pass
27
+
28
+ @classmethod
29
+ def _is_quantizable(cls, model):
30
+ return hasattr(model, "hqq_quantized")
31
+
32
+ @classmethod
33
+ def _make_quantizable(cls, model, quantized: bool):
34
+ model.hqq_quantized = quantized
35
+ model.base_class = cls._get_hqq_class(model)
36
+
37
+ @classmethod
38
+ def _check_arch_support(cls, arg):
39
+ arch = arg if (isinstance(arg, str)) else getattr(arg, "arch_key", None)
40
+ assert arch in cls._HQQ_REGISTRY, (
41
+ "Model architecture " + arch + " not supported yet."
42
+ )
43
+
44
+ @classmethod
45
+ def _check_if_already_quantized(cls, model):
46
+ assert not model.hqq_quantized, "Model already quantized"
47
+
48
+ @classmethod
49
+ def _check_if_not_quantized(cls, model):
50
+ assert model.hqq_quantized, "Model not quantized."
51
+
52
+ @classmethod
53
+ def _set_quantized(cls, model, quantized: bool):
54
+ model.hqq_quantized = quantized
55
+
56
+ #####################################################
57
+ @classmethod
58
+ def quantize_model_(
59
+ cls, model, quant_config, compute_dtype: torch.dtype = float16, device="cuda"
60
+ ):
61
+ if cls._is_quantizable(model) is False:
62
+ cls._make_quantizable(model, quantized=False)
63
+ cls._check_arch_support(model)
64
+ cls._check_if_already_quantized(model)
65
+ cls._get_hqq_class(model).quantize_model(
66
+ model, quant_config=quant_config, compute_dtype=compute_dtype, device=device
67
+ )
68
+ cls._set_quantized(model, True)
69
+
70
+ @classmethod
71
+ def save_quantized_(cls, model, save_dir: str):
72
+ cls._check_if_not_quantized(model)
73
+ cls._get_hqq_class(model).save_quantized(model, save_dir=save_dir)
74
+
75
+ @classmethod
76
+ def from_quantized(
77
+ cls,
78
+ save_dir_or_hub,
79
+ compute_dtype: torch.dtype = float16,
80
+ device="cuda",
81
+ cache_dir: Union[str, None] = "",
82
+ adapter: str = None,
83
+ **kwargs,
84
+ ):
85
+ # Both local and hub-support
86
+ save_dir = BaseHQQModel.try_snapshot_download(
87
+ save_dir_or_hub, cache_dir=cache_dir
88
+ )
89
+ arch_key = cls._get_arch_key_from_save_dir(save_dir)
90
+ cls._check_arch_support(arch_key)
91
+
92
+ model = cls._get_hqq_class(arch_key).from_quantized(
93
+ save_dir,
94
+ compute_dtype=compute_dtype,
95
+ device=device,
96
+ cache_dir=cache_dir,
97
+ adapter=adapter,
98
+ )
99
+
100
+ cls._make_quantizable(model, quantized=True)
101
+ return model
102
+
103
+ @classmethod
104
+ def get_linear_tags(cls, model):
105
+ return cls._get_hqq_class(model).get_linear_tags()
lm-quant-toolkit/.deps/hqq/hqq/engine/hf.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+
4
+ import transformers
5
+ import torch
6
+ from .base import HQQWrapper
7
+
8
+ from ..models.hf.llama import LlamaHQQ
9
+ from hqq.models.hf.mixtral import MixtralHQQ
10
+ from hqq.models.hf.phi import PhiHQQ
11
+ from hqq.models.hf.mistral import MistralHQQ
12
+
13
+ _HQQ_REGISTRY = {}
14
+ _HQQ_REGISTRY["LlamaForCausalLM"] = LlamaHQQ
15
+ _HQQ_REGISTRY["MixtralForCausalLM"] = MixtralHQQ
16
+ _HQQ_REGISTRY["PhiForCausalLM"] = PhiHQQ
17
+ _HQQ_REGISTRY["MistralForCausalLM"] = MistralHQQ
18
+
19
+ # Alias
20
+ AutoTokenizer = transformers.AutoTokenizer
21
+
22
+ # Used to call super() on classmethods
23
+ _Parent = transformers.AutoModelForCausalLM
24
+
25
+
26
+ class HQQModelForCausalLM(_Parent, HQQWrapper):
27
+ _HQQ_REGISTRY = _HQQ_REGISTRY
28
+
29
+ def __init__(self, *args, **kwargs):
30
+ super().__init__(*args, **kwargs)
31
+
32
+ @classmethod
33
+ def _make_quantizable(cls, model, quantized: bool) -> None:
34
+ model.hqq_quantized = quantized
35
+ model.arch_key = model.config.architectures[0]
36
+ model.quantize_model = (
37
+ lambda quant_config,
38
+ compute_dtype=torch.float16,
39
+ device="cuda": cls.quantize_model_(
40
+ model=model,
41
+ quant_config=quant_config,
42
+ compute_dtype=compute_dtype,
43
+ device=device,
44
+ )
45
+ )
46
+ model.save_quantized = lambda save_dir: cls.save_quantized_(
47
+ model=model, save_dir=save_dir
48
+ )
49
+ model.cuda = lambda *args, **kwargs: model if (quantized) else model.cuda
50
+ model.to = lambda *args, **kwargs: model if (quantized) else model.to
51
+ model.float = lambda *args, **kwargs: model if (quantized) else model.float
52
+ model.half = lambda *args, **kwargs: model if (quantized) else model.half
53
+ model.base_class = cls._get_hqq_class(model)
54
+
55
+ # Force loading the model on CPU and unquantized
56
+ @classmethod
57
+ def _validate_params(cls, params: dict) -> None:
58
+ for p in ["load_in_4bit", "load_in_8bit"]: # ignore these
59
+ if p in params:
60
+ params[p] = False
61
+ params["device_map"] = None
62
+
63
+ @classmethod
64
+ def from_pretrained(cls, *args, **kwargs):
65
+ cls._validate_params(kwargs)
66
+ model = super(_Parent, cls).from_pretrained(*args, **kwargs)
67
+ cls._make_quantizable(model, quantized=False)
68
+ return model
69
+
70
+ @classmethod
71
+ def _get_arch_key_from_save_dir(cls, save_dir: str):
72
+ config = transformers.AutoConfig.from_pretrained(save_dir)
73
+ return config.architectures[0]
lm-quant-toolkit/.deps/hqq/hqq/engine/open_clip.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import torch
4
+
5
+ from ..models.base import BaseHQQModel
6
+ from ..models.open_clip.vit_clip import ViTCLIPHQQ
7
+ from .base import HQQWrapper
8
+
9
+ _HQQ_REGISTRY = {}
10
+ _HQQ_REGISTRY["ViT-B-16"] = ViTCLIPHQQ
11
+ _HQQ_REGISTRY["ViT-B-16-plus-240"] = ViTCLIPHQQ
12
+ _HQQ_REGISTRY["ViT-B-16-plus"] = ViTCLIPHQQ
13
+ _HQQ_REGISTRY["ViT-B-16-quickgelu"] = ViTCLIPHQQ
14
+ _HQQ_REGISTRY["ViT-B-16-SigLIP-256"] = ViTCLIPHQQ
15
+ _HQQ_REGISTRY["ViT-B-16-SigLIP-384"] = ViTCLIPHQQ
16
+ _HQQ_REGISTRY["ViT-B-16-SigLIP-512"] = ViTCLIPHQQ
17
+ _HQQ_REGISTRY["ViT-B-16-SigLIP-i18n-256"] = ViTCLIPHQQ
18
+ _HQQ_REGISTRY["ViT-B-16-SigLIP"] = ViTCLIPHQQ
19
+ _HQQ_REGISTRY["ViT-B-32-256"] = ViTCLIPHQQ
20
+ _HQQ_REGISTRY["ViT-B-32"] = ViTCLIPHQQ
21
+ _HQQ_REGISTRY["ViT-B-32-plus-256"] = ViTCLIPHQQ
22
+ _HQQ_REGISTRY["ViT-B-32-quickgelu"] = ViTCLIPHQQ
23
+ _HQQ_REGISTRY["ViT-bigG-14-CLIPA-336"] = ViTCLIPHQQ
24
+ _HQQ_REGISTRY["ViT-bigG-14-CLIPA"] = ViTCLIPHQQ
25
+ _HQQ_REGISTRY["ViT-bigG-14"] = ViTCLIPHQQ
26
+ _HQQ_REGISTRY["ViT-e-14"] = ViTCLIPHQQ
27
+ _HQQ_REGISTRY["ViT-g-14"] = ViTCLIPHQQ
28
+ _HQQ_REGISTRY["ViT-H-14-378-quickgelu"] = ViTCLIPHQQ
29
+ _HQQ_REGISTRY["ViT-H-14-CLIPA-336"] = ViTCLIPHQQ
30
+ _HQQ_REGISTRY["ViT-H-14-CLIPA"] = ViTCLIPHQQ
31
+ _HQQ_REGISTRY["ViT-H-14"] = ViTCLIPHQQ
32
+ _HQQ_REGISTRY["ViT-H-14-quickgelu"] = ViTCLIPHQQ
33
+ _HQQ_REGISTRY["ViT-H-16"] = ViTCLIPHQQ
34
+ _HQQ_REGISTRY["ViT-L-14-280"] = ViTCLIPHQQ
35
+ _HQQ_REGISTRY["ViT-L-14-336"] = ViTCLIPHQQ
36
+ _HQQ_REGISTRY["ViT-L-14-CLIPA-336"] = ViTCLIPHQQ
37
+ _HQQ_REGISTRY["ViT-L-14-CLIPA"] = ViTCLIPHQQ
38
+ _HQQ_REGISTRY["ViT-L-14"] = ViTCLIPHQQ
39
+ _HQQ_REGISTRY["ViT-L-14-quickgelu"] = ViTCLIPHQQ
40
+ _HQQ_REGISTRY["ViT-L-16-320"] = ViTCLIPHQQ
41
+ _HQQ_REGISTRY["ViT-L-16"] = ViTCLIPHQQ
42
+ _HQQ_REGISTRY["ViT-L-16-SigLIP-256"] = ViTCLIPHQQ
43
+ _HQQ_REGISTRY["ViT-L-16-SigLIP-384"] = ViTCLIPHQQ
44
+ _HQQ_REGISTRY["ViT-M-16-alt"] = ViTCLIPHQQ
45
+ _HQQ_REGISTRY["ViT-M-16"] = ViTCLIPHQQ
46
+ _HQQ_REGISTRY["ViT-M-32-alt"] = ViTCLIPHQQ
47
+ _HQQ_REGISTRY["ViT-M-32"] = ViTCLIPHQQ
48
+ _HQQ_REGISTRY["ViT-S-16-alt"] = ViTCLIPHQQ
49
+ _HQQ_REGISTRY["ViT-S-16"] = ViTCLIPHQQ
50
+ _HQQ_REGISTRY["ViT-S-32-alt"] = ViTCLIPHQQ
51
+ _HQQ_REGISTRY["ViT-S-32"] = ViTCLIPHQQ
52
+ _HQQ_REGISTRY["ViT-SO400M-14-SigLIP-384"] = ViTCLIPHQQ
53
+ _HQQ_REGISTRY["ViT-SO400M-14-SigLIP"] = ViTCLIPHQQ
54
+
55
+
56
+ class HQQOpenCLIP(HQQWrapper):
57
+ _HQQ_REGISTRY = _HQQ_REGISTRY
58
+
59
+ def __init__(self, *args, **kwargs):
60
+ super().__init__(*args, **kwargs)
61
+
62
+ @classmethod
63
+ def _make_quantizable(cls, model, quantized: bool):
64
+ model.hqq_quantized = quantized
65
+ model.quantize_model = (
66
+ lambda quant_config,
67
+ compute_dtype=torch.float16,
68
+ device="cuda": cls.quantize_model_(
69
+ model=model,
70
+ quant_config=quant_config,
71
+ compute_dtype=compute_dtype,
72
+ device=device,
73
+ )
74
+ )
75
+ model.save_quantized = lambda save_dir: cls.save_quantized_(
76
+ model=model, save_dir=save_dir
77
+ )
78
+ # model.cuda = lambda *args, **kwargs: model if (quantized) else model.cuda
79
+ # model.to = lambda *args, **kwargs: model if (quantized) else model.to
80
+ # model.float = lambda *args, **kwargs: model if (quantized) else model.float
81
+ # model.half = lambda *args, **kwargs: model if (quantized) else model.half
82
+ model.base_class = ViTCLIPHQQ
83
+
84
+ @classmethod
85
+ def _validate_params(cls, params: dict):
86
+ pass
87
+
88
+ @classmethod
89
+ def create_model(cls, model_id, **kwargs):
90
+ cls._validate_params(kwargs)
91
+ # check if the first positional argument is an directory that exists
92
+ comps = model_id.split("/")
93
+ elems = comps[1].split("-")
94
+ model_name = "-".join(elems[1:4])
95
+ pretrained = "-".join(elems[4:])
96
+ model = cls._get_hqq_class(model_name).create_model(
97
+ model_name, model_name=model_name, pretrained=pretrained, **kwargs
98
+ )
99
+ cls._make_quantizable(model, quantized=False)
100
+ return model
101
+
102
+ @classmethod
103
+ def wrap_model(cls, model, model_name):
104
+ model.arch_key = model_name
105
+ cls._make_quantizable(model, quantized=False)
106
+ return model
107
+
108
+ @classmethod
109
+ def _get_arch_key_from_save_dir(cls, save_dir: str):
110
+ with open(BaseHQQModel.get_config_file(save_dir), "r") as file:
111
+ config = json.load(file)
112
+ return config["architecture"]
lm-quant-toolkit/.deps/hqq/hqq/engine/timm.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+ import timm
4
+ import json
5
+ import torch
6
+ from .base import HQQWrapper
7
+
8
+ from ..models.base import BaseHQQModel
9
+ from ..models.timm.vit_clip import ViTCLIPHQQ
10
+
11
+ _HQQ_REGISTRY = {}
12
+ _HQQ_REGISTRY["vit_huge_patch14_clip_336"] = ViTCLIPHQQ
13
+ _HQQ_REGISTRY["vit_huge_patch14_clip_224"] = ViTCLIPHQQ
14
+ _HQQ_REGISTRY["vit_large_patch14_clip_224"] = ViTCLIPHQQ
15
+ _HQQ_REGISTRY["vit_large_patch14_clip_336"] = ViTCLIPHQQ
16
+ _HQQ_REGISTRY["vit_base_patch16_clip_384"] = ViTCLIPHQQ
17
+ _HQQ_REGISTRY["vit_base_patch32_clip_448"] = ViTCLIPHQQ
18
+ _HQQ_REGISTRY["vit_base_patch32_clip_384"] = ViTCLIPHQQ
19
+ _HQQ_REGISTRY["vit_base_patch16_clip_224"] = ViTCLIPHQQ
20
+ _HQQ_REGISTRY["vit_base_patch32_clip_224"] = ViTCLIPHQQ
21
+
22
+
23
+ class HQQtimm(HQQWrapper):
24
+ _HQQ_REGISTRY = _HQQ_REGISTRY
25
+
26
+ def __init__(self, *args, **kwargs):
27
+ super().__init__(*args, **kwargs)
28
+
29
+ @classmethod
30
+ def _make_quantizable(cls, model, quantized: bool):
31
+ model.hqq_quantized = quantized
32
+ model.arch_key = model.default_cfg["architecture"]
33
+ model.quantize_model = (
34
+ lambda quant_config,
35
+ compute_dtype=torch.float16,
36
+ device="cuda": cls.quantize_model_(
37
+ model=model,
38
+ quant_config=quant_config,
39
+ compute_dtype=compute_dtype,
40
+ device=device,
41
+ )
42
+ )
43
+ model.save_quantized = lambda save_dir: cls.save_quantized_(
44
+ model=model, save_dir=save_dir
45
+ )
46
+ model.cuda = lambda *args, **kwargs: model if (quantized) else model.cuda
47
+ model.to = lambda *args, **kwargs: model if (quantized) else model.to
48
+ model.float = lambda *args, **kwargs: model if (quantized) else model.float
49
+ model.half = lambda *args, **kwargs: model if (quantized) else model.half
50
+ model.base_class = cls._get_hqq_class(model)
51
+
52
+ @classmethod
53
+ def _validate_params(cls, params: dict):
54
+ pass
55
+
56
+ @classmethod
57
+ def create_model(cls, *args, **kwargs):
58
+ cls._validate_params(kwargs)
59
+ model = timm.create_model(*args, **kwargs)
60
+ cls._make_quantizable(model, quantized=False)
61
+ return model
62
+
63
+ @classmethod
64
+ def _get_arch_key_from_save_dir(cls, save_dir: str):
65
+ with open(BaseHQQModel.get_config_file(save_dir), "r") as file:
66
+ config = json.load(file)
67
+ return config["architecture"]
lm-quant-toolkit/.deps/hqq/hqq/engine/vllm.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Written by Dr. Hicham Badri @Mobius Labs GmbH - 2023
2
+ #####################################################
3
+
4
+ # Import VLLM architectures here with the dummy_load trick
5
+ import torch
6
+ from torch import float16
7
+ import transformers
8
+ from ..models.vllm.llama import LlamaForCausalLM, LlamaHQQ
9
+ from ..models.base import BaseHQQModel
10
+ from .base import HQQWrapper
11
+ from termcolor import colored
12
+
13
+ # Set them in the model registry
14
+ import vllm
15
+
16
+ vllm.model_executor.model_loader._MODEL_REGISTRY["LlamaForCausalLM"] = LlamaForCausalLM
17
+
18
+ _HQQ_REGISTRY = {}
19
+ _HQQ_REGISTRY["LlamaForCausalLM"] = LlamaHQQ
20
+
21
+ # VLLM requires model input as string, so this is the fallback for a dummy init used to load the model from quantized weights + load the tokenizer
22
+ _ARCH_TO_DEFAULT = {}
23
+ _ARCH_TO_DEFAULT["LlamaForCausalLM"] = "meta-llama/Llama-2-7b-chat-hf"
24
+
25
+ _Parent = vllm.entrypoints.llm.LLM
26
+
27
+
28
+ # Similar to the from vllm import LLM class, with some extra parameters and only loads a dummy model
29
+ class HQQLLM(_Parent, HQQWrapper):
30
+ _HQQ_REGISTRY = _HQQ_REGISTRY
31
+ INIT_CACHE_MEM = 1.0 # Default cache mem in GB. This is extra-memory, but you need it otherwise runtime is slower
32
+
33
+ def __init__(self, *args, **kwargs):
34
+ self._validate_params(kwargs)
35
+
36
+ if "force_skip" in kwargs:
37
+ force_skip = kwargs["force_skip"]
38
+ del kwargs["force_skip"]
39
+ else:
40
+ force_skip = False
41
+
42
+ # This will init a dummy model
43
+ super().__init__(*args, **kwargs)
44
+
45
+ cache_dir = kwargs["cache_dir"] if ("cache_dir" in kwargs) else ""
46
+ model_id = kwargs["model"]
47
+
48
+ # Here we load the model on CPU so that we can quantize it while avoiding extra GPU cost
49
+ self.arch_key = self.llm_engine.model_config.hf_config.architectures[0]
50
+ model_config = self.llm_engine.model_config.hf_config
51
+ workers = self.llm_engine.workers
52
+
53
+ if force_skip is False:
54
+ for i in range(len(workers)):
55
+ workers[i].model.__init__(model_config, dummy_load=False)
56
+ workers[i].model.load_weights(
57
+ model_name_or_path=model_id, cache_dir=cache_dir
58
+ )
59
+
60
+ self.hqq_quantized = False
61
+
62
+ def _validate_params(self, kwargs: dict):
63
+ if "gpu_memory_utilization" not in kwargs:
64
+ total_gpu_mem = torch.cuda.get_device_properties(0).total_memory / 1e9 # GB
65
+ kwargs["gpu_memory_utilization"] = HQQLLM.INIT_CACHE_MEM / total_gpu_mem
66
+
67
+ # In case the user wants to use the fp16 model and skip quantization
68
+ def cuda(self):
69
+ self._check_if_already_quantized(self)
70
+ workers = self.llm_engine.workers
71
+ for i in range(len(workers)):
72
+ workers[i].model = workers[i].model.half().cuda(i)
73
+ return self
74
+
75
+ def quantize_model(
76
+ self, quant_config: dict, compute_dtype: torch.dtype = float16, device="cuda"
77
+ ):
78
+ return self.quantize_model_(
79
+ model=self,
80
+ quant_config=quant_config,
81
+ compute_dtype=compute_dtype,
82
+ device=device,
83
+ )
84
+
85
+ def save_quantized(self, save_dir: str):
86
+ return self.save_quantized_(model=self, save_dir=save_dir)
87
+
88
+ @classmethod
89
+ def _get_arch_key_from_save_dir(cls, save_dir: str):
90
+ config = transformers.AutoConfig.from_pretrained(save_dir)
91
+ return config.architectures[0]
92
+
93
+ # This requires custom loading because VLLM requires a str input model to initalize the workers
94
+ @classmethod
95
+ def from_quantized(
96
+ cls,
97
+ save_dir_or_hub: str,
98
+ compute_dtype: torch.dtype = float16,
99
+ cache_dir: str = "",
100
+ tensor_parallel_size: int = 1,
101
+ ):
102
+ assert tensor_parallel_size == 1, "Only single GPU is supported."
103
+ # Both local and hub-support
104
+ save_dir = BaseHQQModel.try_snapshot_download(save_dir_or_hub)
105
+ arch_key = cls._get_arch_key_from_save_dir(save_dir)
106
+ cls._check_arch_support(arch_key)
107
+
108
+ # Trick to initialize the tokenizer and a dummy model inside a VLLM instance
109
+ instance = cls(
110
+ model=_ARCH_TO_DEFAULT[arch_key], force_skip=True, tensor_parallel_size=1
111
+ )
112
+ workers = instance.llm_engine.workers
113
+ for i in range(len(workers)):
114
+ workers[i].model = cls._get_hqq_class(
115
+ arch_key
116
+ ).from_quantized_single_worker(
117
+ save_dir_or_hub=save_dir_or_hub,
118
+ compute_dtype=compute_dtype,
119
+ cache_dir=cache_dir,
120
+ device="cuda:" + str(i),
121
+ )
122
+
123
+ cls._make_quantizable(instance, quantized=True)
124
+ return instance
125
+
126
+
127
+ # From https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/llms/vllm.py
128
+
129
+
130
+ try:
131
+ from langchain.llms import VLLM as LangchainVLLMBase
132
+ from langchain_core.pydantic_v1 import root_validator
133
+
134
+ class LangchainVLLM(LangchainVLLMBase):
135
+ def set(self, model):
136
+ self.client = model
137
+ return self
138
+
139
+ @root_validator()
140
+ def validate_environment(cls, values: dict) -> dict:
141
+ return values
142
+ except Exception:
143
+ LangchainVLLM = None
144
+ print(
145
+ colored(
146
+ 'Langchain not installed. You can install it via "pip install langchain"',
147
+ "cyan",
148
+ )
149
+ )
lm-quant-toolkit/.deps/hqq/hqq/kernels/__init__.py ADDED
File without changes