chen459664 commited on
Commit
1216cb5
·
verified ·
1 Parent(s): 02bc7b8

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. baselines_1/Llama-2-7b-hf_bi_idx_10.json +34 -0
  2. baselines_1/Llama-2-7b-hf_bi_idx_5.json +34 -0
  3. baselines_1/Llama-2-7b-hf_zd_idx_10.json +34 -0
  4. baselines_1/Llama-2-7b-hf_zd_idx_5.json +34 -0
  5. llm-awq/.gitignore +173 -0
  6. llm-awq/LICENSE +21 -0
  7. llm-awq/awq.egg-info/top_level.txt +3 -0
  8. llm-awq/awq/kernels/csrc/attention/decoder_masked_multihead_attention.h +185 -0
  9. llm-awq/awq/kernels/csrc/attention/decoder_masked_multihead_attention_template.hpp +1608 -0
  10. llm-awq/awq/kernels/csrc/attention/setup.py +159 -0
  11. llm-awq/awq/kernels/csrc/layernorm/layernorm.h +3 -0
  12. llm-awq/awq/kernels/csrc/layernorm/reduction.cuh +82 -0
  13. llm-awq/awq/kernels/csrc/position_embedding/pos_encoding_kernels.cu +88 -0
  14. llm-awq/awq/kernels/csrc/quantization/dequantize.cuh +79 -0
  15. llm-awq/awq/kernels/csrc/quantization/gemm_cuda.h +4 -0
  16. llm-awq/awq/kernels/csrc/quantization/gemm_cuda_gen.cu +298 -0
  17. llm-awq/awq/kernels/csrc/quantization/gemv_cuda.h +9 -0
  18. llm-awq/awq/kernels/csrc/quantization_new/dequantize.cuh +123 -0
  19. llm-awq/awq/kernels/csrc/quantization_new/dispatch_utils.cuh +18 -0
  20. llm-awq/awq/kernels/csrc/quantization_new/gemm/gemm_cuda.cu +1236 -0
  21. llm-awq/awq/kernels/csrc/quantization_new/gemm/gemm_cuda.h +3 -0
  22. llm-awq/awq/kernels/csrc/quantization_new/gemm/semaphore.h +109 -0
  23. llm-awq/awq/kernels/csrc/quantization_new/gemv/gemv_cuda.cu +339 -0
  24. llm-awq/awq/kernels/csrc/quantization_new/gemv/gemv_cuda.h +12 -0
  25. llm-awq/awq/kernels/csrc/rope_new/fused_rope_with_pos.cu +407 -0
  26. llm-awq/awq/kernels/csrc/rope_new/fused_rope_with_pos.h +5 -0
  27. llm-awq/awq/kernels/csrc/w8a8/act.cu +141 -0
  28. llm-awq/awq/kernels/csrc/w8a8/act.h +29 -0
  29. llm-awq/awq/kernels/csrc/w8a8/dispatch_utils.h +14 -0
  30. llm-awq/awq/kernels/csrc/w8a8/layernorm.cu +232 -0
  31. llm-awq/awq/kernels/csrc/w8a8/layernorm.h +21 -0
  32. llm-awq/awq/kernels/csrc/w8a8/quantization.cu +113 -0
  33. llm-awq/awq/kernels/csrc/w8a8/quantization.h +4 -0
  34. llm-awq/awq/kernels/csrc/w8a8/utils.cuh +469 -0
  35. llm-awq/awq/kernels/csrc/w8a8/w8a8_gemm_cuda.cu +953 -0
  36. llm-awq/awq/kernels/csrc/w8a8/w8a8_gemm_cuda.h +4 -0
  37. llm-awq/awq/quantize/__init__.py +2 -0
  38. llm-awq/awq/quantize/__pycache__/w8a8_linear.cpython-311.pyc +0 -0
  39. llm-awq/awq/quantize/auto_clip.py +98 -0
  40. llm-awq/awq/quantize/auto_scale.py +480 -0
  41. llm-awq/awq/quantize/pre_quant.py +254 -0
  42. llm-awq/awq/quantize/qmodule.py +235 -0
  43. llm-awq/awq/quantize/quantizer.py +165 -0
  44. llm-awq/awq/quantize/smooth.py +246 -0
  45. llm-awq/awq/quantize/w8a8_linear.py +276 -0
  46. llm-awq/awq/utils/__init__.py +0 -0
  47. llm-awq/awq/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  48. llm-awq/awq/utils/__pycache__/parallel.cpython-311.pyc +0 -0
  49. llm-awq/awq/utils/lm_eval_adaptor.py +116 -0
  50. llm-awq/awq/utils/module.py +39 -0
baselines_1/Llama-2-7b-hf_bi_idx_10.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ 4,
3
+ 4,
4
+ 4,
5
+ 4,
6
+ 4,
7
+ 4,
8
+ 4,
9
+ 4,
10
+ 4,
11
+ 4,
12
+ 4,
13
+ 4,
14
+ 4,
15
+ 4,
16
+ 4,
17
+ 4,
18
+ 4,
19
+ 4,
20
+ 4,
21
+ 4,
22
+ 2,
23
+ 2,
24
+ 2,
25
+ 2,
26
+ 2,
27
+ 2,
28
+ 2,
29
+ 2,
30
+ 2,
31
+ 2,
32
+ 4,
33
+ 4
34
+ ]
baselines_1/Llama-2-7b-hf_bi_idx_5.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ 4,
3
+ 4,
4
+ 4,
5
+ 4,
6
+ 4,
7
+ 4,
8
+ 4,
9
+ 4,
10
+ 4,
11
+ 4,
12
+ 4,
13
+ 4,
14
+ 4,
15
+ 4,
16
+ 4,
17
+ 4,
18
+ 4,
19
+ 4,
20
+ 4,
21
+ 4,
22
+ 4,
23
+ 4,
24
+ 4,
25
+ 4,
26
+ 2,
27
+ 2,
28
+ 2,
29
+ 2,
30
+ 2,
31
+ 4,
32
+ 4,
33
+ 4
34
+ ]
baselines_1/Llama-2-7b-hf_zd_idx_10.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ 4,
3
+ 4,
4
+ 4,
5
+ 4,
6
+ 4,
7
+ 4,
8
+ 4,
9
+ 4,
10
+ 4,
11
+ 4,
12
+ 4,
13
+ 4,
14
+ 4,
15
+ 4,
16
+ 4,
17
+ 4,
18
+ 4,
19
+ 2,
20
+ 2,
21
+ 4,
22
+ 2,
23
+ 2,
24
+ 2,
25
+ 2,
26
+ 4,
27
+ 2,
28
+ 2,
29
+ 2,
30
+ 2,
31
+ 4,
32
+ 4,
33
+ 4
34
+ ]
baselines_1/Llama-2-7b-hf_zd_idx_5.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ 4,
3
+ 4,
4
+ 4,
5
+ 4,
6
+ 4,
7
+ 4,
8
+ 4,
9
+ 4,
10
+ 4,
11
+ 4,
12
+ 4,
13
+ 4,
14
+ 4,
15
+ 4,
16
+ 4,
17
+ 4,
18
+ 4,
19
+ 4,
20
+ 4,
21
+ 4,
22
+ 4,
23
+ 4,
24
+ 2,
25
+ 2,
26
+ 4,
27
+ 2,
28
+ 4,
29
+ 2,
30
+ 2,
31
+ 4,
32
+ 4,
33
+ 4
34
+ ]
llm-awq/.gitignore ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .DS_Store
2
+
3
+ data/
4
+ checkpoints
5
+ demo_images
6
+ serve_images
7
+ # Byte-compiled / optimized / DLL files
8
+ __pycache__/
9
+ *.py[cod]
10
+ *$py.class
11
+
12
+ # C extensions
13
+ *.so
14
+
15
+ # Distribution / packaging
16
+ .Python
17
+ *.pyc
18
+ build/
19
+ develop-eggs/
20
+ dist/
21
+ downloads/
22
+ eggs/
23
+ .eggs/
24
+ lib/
25
+ lib64/
26
+ parts/
27
+ sdist/
28
+ var/
29
+ wheels/
30
+ share/python-wheels/
31
+ *.egg-info/
32
+ .installed.cfg
33
+ *.egg
34
+ MANIFEST
35
+
36
+ # PyInstaller
37
+ # Usually these files are written by a python script from a template
38
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
39
+ *.manifest
40
+ *.spec
41
+
42
+ # Installer logs
43
+ pip-log.txt
44
+ pip-delete-this-directory.txt
45
+
46
+ # Unit test / coverage reports
47
+ htmlcov/
48
+ .tox/
49
+ .nox/
50
+ .coverage
51
+ .coverage.*
52
+ .cache
53
+ nosetests.xml
54
+ coverage.xml
55
+ *.cover
56
+ *.py,cover
57
+ .hypothesis/
58
+ .pytest_cache/
59
+ cover/
60
+
61
+ # Translations
62
+ *.mo
63
+ *.pot
64
+
65
+ # Django stuff:
66
+ *.log
67
+ local_settings.py
68
+ db.sqlite3
69
+ db.sqlite3-journal
70
+
71
+ # Flask stuff:
72
+ instance/
73
+ .webassets-cache
74
+
75
+ # Scrapy stuff:
76
+ .scrapy
77
+
78
+ # Sphinx documentation
79
+ docs/_build/
80
+
81
+ # PyBuilder
82
+ .pybuilder/
83
+ target/
84
+
85
+ # Jupyter Notebook
86
+ .ipynb_checkpoints
87
+
88
+ # IPython
89
+ profile_default/
90
+ ipython_config.py
91
+
92
+ # pyenv
93
+ # For a library or package, you might want to ignore these files since the code is
94
+ # intended to run in multiple environments; otherwise, check them in:
95
+ # .python-version
96
+
97
+ # pipenv
98
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
99
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
100
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
101
+ # install all needed dependencies.
102
+ #Pipfile.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ #poetry.lock
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ #pdm.lock
114
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
115
+ # in version control.
116
+ # https://pdm.fming.dev/#use-with-ide
117
+ .pdm.toml
118
+
119
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
120
+ __pypackages__/
121
+
122
+ # Celery stuff
123
+ celerybeat-schedule
124
+ celerybeat.pid
125
+
126
+ # SageMath parsed files
127
+ *.sage.py
128
+
129
+ # Environments
130
+ .env
131
+ .venv
132
+ env/
133
+ venv/
134
+ ENV/
135
+ env.bak/
136
+ venv.bak/
137
+
138
+ # Spyder project settings
139
+ .spyderproject
140
+ .spyproject
141
+
142
+ # Rope project settings
143
+ .ropeproject
144
+
145
+ # mkdocs documentation
146
+ /site
147
+
148
+ # mypy
149
+ .mypy_cache/
150
+ .dmypy.json
151
+ dmypy.json
152
+
153
+ # Pyre type checker
154
+ .pyre/
155
+
156
+ # pytype static type analyzer
157
+ .pytype/
158
+
159
+ # Cython debug symbols
160
+ cython_debug/
161
+
162
+ # PyCharm
163
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
164
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
165
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
166
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
167
+ #.idea/
168
+
169
+ *.pt
170
+ **/*.pt
171
+ **/*.pyc
172
+ *.json
173
+ __pycache__
llm-awq/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 MIT HAN Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
llm-awq/awq.egg-info/top_level.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ awq
2
+ figures
3
+ tinychat
llm-awq/awq/kernels/csrc/attention/decoder_masked_multihead_attention.h ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Downloaded from from FasterTransformer v5.2.1
2
+ // https://github.com/NVIDIA/FasterTransformer/blob/release/v5.2.1_tag/src/fastertransformer/kernels/decoder_masked_multihead_attention.h
3
+ /*
4
+ * Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #pragma once
20
+
21
+ #include "cuda_bf16_wrapper.h"
22
+ #include <cuda_fp16.h>
23
+ #include <cuda_runtime_api.h>
24
+ #include <stdint.h>
25
+ #include <stdio.h>
26
+ #include <stdlib.h>
27
+
28
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
29
+
30
+ #define CHECK_CUDA(call) \
31
+ do { \
32
+ cudaError_t status_ = call; \
33
+ if (status_ != cudaSuccess) { \
34
+ fprintf(stderr, "CUDA error (%s:%d): %s\n", __FILE__, __LINE__, cudaGetErrorString(status_)); \
35
+ exit(1); \
36
+ } \
37
+ } while (0)
38
+
39
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
40
+
41
+ // The structure of parameters for the masked multihead attention kernel.
42
+ //
43
+ // We use the following terminology to describe the different dimensions.
44
+ //
45
+ // B: Batch size (number of sequences),
46
+ // L: Sequence length,
47
+ // D: Hidden dimension,
48
+ // H: Number of heads,
49
+ // Dh: Hidden dimension per head - Dh = D / H.
50
+
51
+ template<typename T>
52
+ struct Multihead_attention_params_base {
53
+
54
+ // The output buffer. Dimensions B x D.
55
+ T* out = nullptr;
56
+
57
+ // The input Qs and the associated bias. Dimensions B x D and D, resp.
58
+ const T *q = nullptr, *q_bias = nullptr;
59
+ // The input Ks and the associated bias. Dimensions B x D and D, resp.
60
+ const T *k = nullptr, *k_bias = nullptr;
61
+ // The input Vs and the associated bias. Dimensions B x D and D, resp.
62
+ const T *v = nullptr, *v_bias = nullptr;
63
+
64
+ // The cache for the Ks. The size must be at least B x L x D.
65
+ T* k_cache = nullptr;
66
+ // The cache for the Vs. The size must be at least B x L x D.
67
+ T* v_cache = nullptr;
68
+ // The indirections to use for cache when beam sampling.
69
+ const int* cache_indir = nullptr;
70
+
71
+ // Stride to handle the case when KQV is a single buffer
72
+ int stride = 0;
73
+
74
+ // The batch size.
75
+ int batch_size = 0;
76
+ // The beam width
77
+ int beam_width = 0;
78
+ // The sequence length.
79
+ int memory_max_len = 0;
80
+ // The number of heads (H).
81
+ int num_heads = 0;
82
+ // The number of heads for KV cache.
83
+ int num_kv_heads = 0;
84
+ // The hidden dimension per head (Dh).
85
+ int hidden_size_per_head = 0;
86
+ // The per-head latent space reserved for rotary embeddings.
87
+ int rotary_embedding_dim = 0;
88
+ bool neox_rotary_style = false;
89
+ float rotary_base = 0.0f;
90
+ float rotary_scale = 1.0f;
91
+ // The maximum length of input sentences.
92
+ int max_input_length = 0;
93
+ // The current timestep. TODO(bhsueh) Check that do we only this param in cross attention?
94
+ int timestep = 0;
95
+ // The current timestep of each sentences (support different timestep for different sentences)
96
+
97
+ // The 1.f / sqrt(Dh). Computed on the host.
98
+ float inv_sqrt_dh = 0.0f;
99
+
100
+ // Used when we have some input context like gpt
101
+ const int* total_padding_tokens = nullptr;
102
+
103
+ const bool* masked_tokens = nullptr;
104
+ const int* prefix_prompt_lengths = nullptr;
105
+ int max_prefix_prompt_length = 0;
106
+
107
+ const T* relative_attention_bias = nullptr;
108
+ int relative_attention_bias_stride = 0;
109
+ // The slope per head of linear position bias to attention score (H).
110
+ const float* linear_bias_slopes = nullptr;
111
+
112
+ const T* ia3_key_weights = nullptr;
113
+ const T* ia3_value_weights = nullptr;
114
+ const int* ia3_tasks = nullptr;
115
+
116
+ const float* qkv_scale_out = nullptr;
117
+ const float* attention_out_scale = nullptr;
118
+ int int8_mode = 0;
119
+ };
120
+
121
+ template<typename T, bool CROSS_ATTENTION>
122
+ struct Multihead_attention_params: public Multihead_attention_params_base<T> {
123
+ // output cross attentions
124
+ float* cross_attention_out = nullptr;
125
+ int max_decoder_seq_len = 0;
126
+ bool is_return_cross_attentions = false;
127
+
128
+ // allows to exist attention eary
129
+ bool* finished = nullptr;
130
+
131
+ // required in case of cross attention
132
+ // will need it here till if constexpr in c++17
133
+ int* memory_length_per_sample = nullptr;
134
+
135
+ // required in case of masked attention with different length
136
+ const int* length_per_sample = nullptr;
137
+ };
138
+
139
+ template<typename T>
140
+ struct Multihead_attention_params<T, true>: public Multihead_attention_params_base<T> {
141
+ // output cross attentions
142
+ float* cross_attention_out = nullptr;
143
+ int max_decoder_seq_len = 0;
144
+ bool is_return_cross_attentions = false;
145
+
146
+ // allows to exist attention eary
147
+ bool* finished = nullptr;
148
+
149
+ // required in case of cross attention
150
+ int* memory_length_per_sample = nullptr;
151
+
152
+ // required in case of masked attention with different length
153
+ const int* length_per_sample = nullptr;
154
+ };
155
+
156
+ template<class T>
157
+ using Masked_multihead_attention_params = Multihead_attention_params<T, false>;
158
+
159
+ template<class T>
160
+ using Cross_multihead_attention_params = Multihead_attention_params<T, true>;
161
+
162
+ template<typename T>
163
+ struct outputCrossAttentionParam {
164
+ // max decoder output length
165
+ int max_decoder_seq_len = 0;
166
+ T* cross_attention_out = nullptr;
167
+ bool is_return_cross_attentions = false;
168
+ };
169
+
170
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
171
+
172
+ void masked_multihead_attention(const Masked_multihead_attention_params<float>& params, const cudaStream_t& stream);
173
+ void masked_multihead_attention(const Masked_multihead_attention_params<uint16_t>& params, const cudaStream_t& stream);
174
+ #ifdef ENABLE_BF16
175
+ void masked_multihead_attention(const Masked_multihead_attention_params<__nv_bfloat16>& params,
176
+ const cudaStream_t& stream);
177
+ #endif
178
+ void cross_multihead_attention(const Cross_multihead_attention_params<float>& params, const cudaStream_t& stream);
179
+ void cross_multihead_attention(const Cross_multihead_attention_params<uint16_t>& params, const cudaStream_t& stream);
180
+ #ifdef ENABLE_BF16
181
+ void cross_multihead_attention(const Cross_multihead_attention_params<__nv_bfloat16>& params,
182
+ const cudaStream_t& stream);
183
+ #endif
184
+
185
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
llm-awq/awq/kernels/csrc/attention/decoder_masked_multihead_attention_template.hpp ADDED
@@ -0,0 +1,1608 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Downloaded from from FasterTransformer v5.2.1
2
+ // https://github.com/NVIDIA/FasterTransformer/blob/release/v5.2.1_tag/src/fastertransformer/kernels/decoder_masked_multihead_attention/decoder_masked_multihead_attention_template.hpp
3
+ /*
4
+ * Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ #pragma once
19
+
20
+ #include "decoder_masked_multihead_attention.h"
21
+ #include "decoder_masked_multihead_attention_utils.h"
22
+ #include "cuda_bf16_wrapper.h"
23
+ #include "cuda_bf16_fallbacks.cuh"
24
+ #include <assert.h>
25
+ #include <float.h>
26
+ #include <type_traits>
27
+
28
+ // #define MMHA_USE_HMMA_FOR_REDUCTION
29
+
30
+ // Below are knobs to extend FP32 accumulation for higher FP16 accuracy
31
+
32
+ // Does not seem to affect the accuracy that much
33
+ #define MMHA_USE_FP32_ACUM_FOR_FMA
34
+
35
+ // Seems to slightly improve the accuracy
36
+ #define MMHA_USE_FP32_ACUM_FOR_OUT
37
+
38
+ #if 0 && defined(MMHA_USE_FP32_ACUM_FOR_OUT)
39
+ // Does not seem to improve the accuracy
40
+ //#define MMHA_USE_FP32_ACUM_FOR_LOGITS
41
+ #endif
42
+
43
+ namespace mmha {
44
+
45
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
46
+
47
+ //
48
+ // We use the following terminology to describe the different dimensions.
49
+ //
50
+ // B: Batch size (number of sequences),
51
+ // L: Sequence length,
52
+ // D: Hidden dimension,
53
+ // H: Number of heads,
54
+ // Dh: Hidden dimension per head - Dh = D / H.
55
+ //
56
+ // The different kernels assign a threadblock for B x H pair. The grid has size (1, B, H). We use
57
+ // 64, 128 and 256 threads per block.
58
+ //
59
+ // Each threadblock loads Dh values from Q and its associated bias. The kernels run a loop to
60
+ // compute Q * K^T where K is loaded from a cache buffer -- except for the current timestep. The
61
+ // cache buffer helps with memory accesses and contains keys with bias.
62
+ //
63
+ // The layout of the cache buffer for the keys is [B, H, Dh/x, L, x] where x == 8 for FP16 and
64
+ // x == 4 for FP32 where the fastest moving dimension (contiguous data) is the rightmost one. The
65
+ // values for x are chosen to create chunks of 16 bytes.
66
+ //
67
+ // The different kernels use 1, 2 or 4 threads per key (THREADS_PER_KEY). The size of the LDGs
68
+ // depends on the number of threads per key. Each thread sums Dh / THREADS_PER_KEY elements. At
69
+ // the end of each iteration of the Q * K^T loop, we perform a reduction between lanes using an
70
+ // HMMA instruction (Tensor Core). Each Q * K^T valuey is stored in shared memory in FP32.
71
+ //
72
+ // After that loop, a parallel softmax is computed across the different Q * K^T values stored in
73
+ // shared memory.
74
+ //
75
+ // The kernel ends with a loop over the values in V. We use THREADS_PER_VALUE to control how many
76
+ // timesteps are computed by loop iteration. As with the keys, the values are read from a cache
77
+ // except for the current timestep. The layout of the cache buffer for the values is much simpler
78
+ // as it is [B, H, L, Dh].
79
+ //
80
+
81
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
82
+
83
+ template<typename T, int Dh>
84
+ struct Qk_vec_ {
85
+ };
86
+
87
+ template<>
88
+ struct Qk_vec_<float, 32> {
89
+ using Type = float;
90
+ };
91
+ template<>
92
+ struct Qk_vec_<float, 64> {
93
+ using Type = float2;
94
+ };
95
+ template<>
96
+ struct Qk_vec_<float, 128> {
97
+ using Type = float4;
98
+ };
99
+ template<>
100
+ struct Qk_vec_<float, 256> {
101
+ using Type = float4;
102
+ };
103
+ template<>
104
+ struct Qk_vec_<uint16_t, 32> {
105
+ using Type = uint32_t;
106
+ };
107
+ template<>
108
+ struct Qk_vec_<uint16_t, 64> {
109
+ using Type = uint32_t;
110
+ };
111
+ template<>
112
+ struct Qk_vec_<uint16_t, 128> {
113
+ using Type = uint2;
114
+ };
115
+ template<>
116
+ struct Qk_vec_<uint16_t, 256> {
117
+ using Type = uint4;
118
+ };
119
+ #ifdef ENABLE_BF16
120
+ template<>
121
+ struct Qk_vec_<__nv_bfloat16, 32> {
122
+ using Type = __nv_bfloat162;
123
+ };
124
+ template<>
125
+ struct Qk_vec_<__nv_bfloat16, 64> {
126
+ using Type = __nv_bfloat162;
127
+ };
128
+ template<>
129
+ struct Qk_vec_<__nv_bfloat16, 128> {
130
+ using Type = bf16_4_t;
131
+ };
132
+ template<>
133
+ struct Qk_vec_<__nv_bfloat16, 256> {
134
+ using Type = bf16_8_t;
135
+ };
136
+ #endif // ENABLE_BF16
137
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
138
+
139
+ template<typename T, int THREADS_PER_KEY>
140
+ struct K_vec_ {
141
+ };
142
+
143
+ template<>
144
+ struct K_vec_<float, 4> {
145
+ using Type = float;
146
+ };
147
+ template<>
148
+ struct K_vec_<float, 2> {
149
+ using Type = float2;
150
+ };
151
+ template<>
152
+ struct K_vec_<float, 1> {
153
+ using Type = float4;
154
+ };
155
+ template<>
156
+ struct K_vec_<uint16_t, 4> {
157
+ using Type = uint32_t;
158
+ };
159
+ template<>
160
+ struct K_vec_<uint16_t, 2> {
161
+ using Type = uint2;
162
+ };
163
+ template<>
164
+ struct K_vec_<uint16_t, 1> {
165
+ using Type = uint4;
166
+ };
167
+ #ifdef ENABLE_BF16
168
+ template<>
169
+ struct K_vec_<__nv_bfloat16, 4> {
170
+ using Type = __nv_bfloat162;
171
+ };
172
+ template<>
173
+ struct K_vec_<__nv_bfloat16, 2> {
174
+ using Type = bf16_4_t;
175
+ };
176
+ template<>
177
+ struct K_vec_<__nv_bfloat16, 1> {
178
+ using Type = bf16_8_t;
179
+ };
180
+ #endif // ENABLE_BF16
181
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
182
+
183
+ template<typename T, int V_VEC_SIZE>
184
+ struct V_vec_ {
185
+ };
186
+
187
+ template<>
188
+ struct V_vec_<float, 1> {
189
+ using Type = float;
190
+ };
191
+ template<>
192
+ struct V_vec_<float, 2> {
193
+ using Type = float2;
194
+ };
195
+ template<>
196
+ struct V_vec_<float, 4> {
197
+ using Type = float4;
198
+ };
199
+ template<>
200
+ struct V_vec_<uint16_t, 2> {
201
+ using Type = uint32_t;
202
+ };
203
+ template<>
204
+ struct V_vec_<uint16_t, 4> {
205
+ using Type = uint2;
206
+ };
207
+ template<>
208
+ struct V_vec_<uint16_t, 8> {
209
+ using Type = uint4;
210
+ };
211
+ #ifdef ENABLE_BF16
212
+ template<>
213
+ struct V_vec_<__nv_bfloat16, 2> {
214
+ using Type = __nv_bfloat162;
215
+ };
216
+ template<>
217
+ struct V_vec_<__nv_bfloat16, 4> {
218
+ using Type = bf16_4_t;
219
+ };
220
+ template<>
221
+ struct V_vec_<__nv_bfloat16, 8> {
222
+ using Type = bf16_8_t;
223
+ };
224
+ #endif // ENABLE_BF16
225
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
226
+
227
+ #ifdef MMHA_USE_FP32_ACUM_FOR_FMA
228
+ template<typename T>
229
+ struct Qk_vec_acum_fp32_ {
230
+ };
231
+
232
+ template<>
233
+ struct Qk_vec_acum_fp32_<float> {
234
+ using Type = float;
235
+ };
236
+ template<>
237
+ struct Qk_vec_acum_fp32_<float2> {
238
+ using Type = float2;
239
+ };
240
+ template<>
241
+ struct Qk_vec_acum_fp32_<float4> {
242
+ using Type = float4;
243
+ };
244
+ // template<> struct Qk_vec_acum_fp32_<uint16_t> { using Type = float; };
245
+ template<>
246
+ struct Qk_vec_acum_fp32_<uint32_t> {
247
+ using Type = float2;
248
+ };
249
+ template<>
250
+ struct Qk_vec_acum_fp32_<uint2> {
251
+ using Type = Float4_;
252
+ };
253
+ template<>
254
+ struct Qk_vec_acum_fp32_<uint4> {
255
+ using Type = Float8_;
256
+ };
257
+ template<>
258
+ struct Qk_vec_acum_fp32_<__nv_bfloat16> {
259
+ using Type = float;
260
+ };
261
+ template<>
262
+ struct Qk_vec_acum_fp32_<__nv_bfloat162> {
263
+ using Type = float2;
264
+ };
265
+ template<>
266
+ struct Qk_vec_acum_fp32_<bf16_4_t> {
267
+ using Type = Float4_;
268
+ };
269
+ template<>
270
+ struct Qk_vec_acum_fp32_<bf16_8_t> {
271
+ using Type = Float8_;
272
+ };
273
+
274
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
275
+
276
+ template<typename T>
277
+ struct K_vec_acum_fp32_ {
278
+ };
279
+
280
+ template<>
281
+ struct K_vec_acum_fp32_<float> {
282
+ using Type = float;
283
+ };
284
+ template<>
285
+ struct K_vec_acum_fp32_<float2> {
286
+ using Type = float2;
287
+ };
288
+ template<>
289
+ struct K_vec_acum_fp32_<float4> {
290
+ using Type = float4;
291
+ };
292
+ template<>
293
+ struct K_vec_acum_fp32_<uint32_t> {
294
+ using Type = float2;
295
+ };
296
+ template<>
297
+ struct K_vec_acum_fp32_<uint2> {
298
+ using Type = Float4_;
299
+ };
300
+ template<>
301
+ struct K_vec_acum_fp32_<uint4> {
302
+ using Type = Float8_;
303
+ };
304
+ template<>
305
+ struct K_vec_acum_fp32_<__nv_bfloat16> {
306
+ using Type = float;
307
+ };
308
+ template<>
309
+ struct K_vec_acum_fp32_<__nv_bfloat162> {
310
+ using Type = float2;
311
+ };
312
+ template<>
313
+ struct K_vec_acum_fp32_<bf16_4_t> {
314
+ using Type = Float4_;
315
+ };
316
+ template<>
317
+ struct K_vec_acum_fp32_<bf16_8_t> {
318
+ using Type = Float8_;
319
+ };
320
+ #endif
321
+
322
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
323
+
324
+ #ifdef MMHA_USE_FP32_ACUM_FOR_OUT
325
+ template<typename T>
326
+ struct V_vec_acum_fp32_ {
327
+ };
328
+
329
+ template<>
330
+ struct V_vec_acum_fp32_<float> {
331
+ using Type = float;
332
+ };
333
+ template<>
334
+ struct V_vec_acum_fp32_<float2> {
335
+ using Type = float2;
336
+ };
337
+ template<>
338
+ struct V_vec_acum_fp32_<float4> {
339
+ using Type = float4;
340
+ };
341
+ template<>
342
+ struct V_vec_acum_fp32_<uint32_t> {
343
+ using Type = float2;
344
+ };
345
+ template<>
346
+ struct V_vec_acum_fp32_<uint2> {
347
+ using Type = Float4_;
348
+ };
349
+ template<>
350
+ struct V_vec_acum_fp32_<uint4> {
351
+ using Type = Float8_;
352
+ };
353
+ #ifdef ENABLE_BF16
354
+ template<>
355
+ struct V_vec_acum_fp32_<__nv_bfloat162> {
356
+ using Type = float2;
357
+ };
358
+ template<>
359
+ struct V_vec_acum_fp32_<bf16_4_t> {
360
+ using Type = Float4_;
361
+ };
362
+ template<>
363
+ struct V_vec_acum_fp32_<bf16_8_t> {
364
+ using Type = Float8_;
365
+ };
366
+ #endif // ENABLE_BF16
367
+ #endif
368
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
369
+
370
+ template<int THREADS_PER_KEY, typename K_vec, int N>
371
+ inline __device__ float qk_dot_(const K_vec (&q)[N], const K_vec (&k)[N])
372
+ {
373
+ #ifdef MMHA_USE_FP32_ACUM_FOR_FMA
374
+ using K_vec_acum = typename K_vec_acum_fp32_<K_vec>::Type;
375
+ #else
376
+ using K_vec_acum = K_vec;
377
+ #endif
378
+ // Compute the parallel products for Q*K^T (treat vector lanes separately).
379
+ K_vec_acum qk_vec = mul<K_vec_acum, K_vec, K_vec>(q[0], k[0]);
380
+ #pragma unroll
381
+ for (int ii = 1; ii < N; ++ii) {
382
+ qk_vec = fma(q[ii], k[ii], qk_vec);
383
+ }
384
+
385
+ // Finalize the reduction across lanes.
386
+ float qk = sum(qk_vec);
387
+ #pragma unroll
388
+ for (int mask = THREADS_PER_KEY / 2; mask >= 1; mask /= 2) {
389
+ qk += __shfl_xor_sync(uint32_t(-1), qk, mask);
390
+ }
391
+ return qk;
392
+ }
393
+
394
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
395
+
396
+ template<typename T, int THREADS_PER_KEY>
397
+ struct Qk_dot {
398
+ template<typename K_vec, int N>
399
+ static inline __device__ float dot(const K_vec (&q)[N], const K_vec (&k)[N])
400
+ {
401
+ return qk_dot_<THREADS_PER_KEY>(q, k);
402
+ }
403
+ };
404
+
405
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
406
+
407
+ inline __device__ float4 hmma_fp32(const uint2& a, uint32_t b)
408
+ {
409
+ float4 c;
410
+ float zero = 0.f;
411
+ asm volatile("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 \n"
412
+ " {%0, %1, %2, %3}, \n"
413
+ " {%4, %5}, \n"
414
+ " {%6}, \n"
415
+ " {%7, %7, %7, %7}; \n"
416
+
417
+ : "=f"(c.x), "=f"(c.y), "=f"(c.z), "=f"(c.w)
418
+ : "r"(a.x) "r"(a.y), "r"(b), "f"(zero));
419
+ return c;
420
+ }
421
+
422
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
423
+
424
+ template<int N>
425
+ inline __device__ float qk_hmma_dot_(const uint32_t (&q)[N], const uint32_t (&k)[N])
426
+ {
427
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 750
428
+ #ifdef MMHA_USE_FP32_ACUM_FOR_FMA
429
+ using K_vec_acum = typename K_vec_acum_fp32_<uint32_t>::Type;
430
+ #else
431
+ using K_vec_acum = uint32_t;
432
+ #endif
433
+ K_vec_acum qk_vec = mul<K_vec_acum, uint32_t, uint32_t>(q[0], k[0]);
434
+ #pragma unroll
435
+ for (int ii = 1; ii < N; ++ii) {
436
+ qk_vec = fma(q[ii], k[ii], qk_vec);
437
+ }
438
+ #ifdef MMHA_USE_FP32_ACUM_FOR_FMA
439
+ uint32_t qk_vec_ = float2_to_half2(qk_vec);
440
+ return hmma_fp32(make_uint2(qk_vec_, 0u), 0x3c003c00u).x;
441
+ #else
442
+ return hmma_fp32(make_uint2(qk_vec, 0u), 0x3c003c00u).x;
443
+ #endif
444
+ #else
445
+ return 0.f;
446
+ #endif
447
+ }
448
+
449
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
450
+
451
+ template<>
452
+ struct Qk_dot<uint16_t, 4> {
453
+ template<int N>
454
+ static inline __device__ float dot(const uint32_t (&q)[N], const uint32_t (&k)[N])
455
+ {
456
+ #if __CUDA_ARCH__ >= 750 && defined(MMHA_USE_HMMA_FOR_REDUCTION)
457
+ return qk_hmma_dot_(q, k);
458
+ #else
459
+ return qk_dot_<4>(q, k);
460
+ #endif // defined MMHA_USE_HMMA_FOR_REDUCTION
461
+ }
462
+ };
463
+
464
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
465
+
466
+ template<int WARPS_PER_BLOCK, int WARP_SIZE = 32>
467
+ inline __device__ float block_sum(float* red_smem, float sum)
468
+ {
469
+
470
+ // Decompose the thread index into warp / lane.
471
+ int warp = threadIdx.x / WARP_SIZE;
472
+ int lane = threadIdx.x % WARP_SIZE;
473
+
474
+ // Compute the sum per warp.
475
+ #pragma unroll
476
+ for (int mask = WARP_SIZE / 2; mask >= 1; mask /= 2) {
477
+ sum += __shfl_xor_sync(uint32_t(-1), sum, mask);
478
+ }
479
+
480
+ // Warp leaders store the data to shared memory.
481
+ if (lane == 0) {
482
+ red_smem[warp] = sum;
483
+ }
484
+
485
+ // Make sure the data is in shared memory.
486
+ __syncthreads();
487
+
488
+ // The warps compute the final sums.
489
+ if (lane < WARPS_PER_BLOCK) {
490
+ sum = red_smem[lane];
491
+ }
492
+
493
+ // Parallel reduction inside the warp.
494
+ #pragma unroll
495
+ for (int mask = WARPS_PER_BLOCK / 2; mask >= 1; mask /= 2) {
496
+ sum += __shfl_xor_sync(uint32_t(-1), sum, mask);
497
+ }
498
+
499
+ // Broadcast to other threads.
500
+ return __shfl_sync(uint32_t(-1), sum, 0);
501
+ }
502
+
503
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
504
+
505
+ inline __device__ void convert_from_float(float& dst, float src)
506
+ {
507
+ dst = src;
508
+ }
509
+
510
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
511
+
512
+ inline __device__ void convert_from_float(uint16_t& dst, float src)
513
+ {
514
+ dst = float_to_half(src);
515
+ }
516
+
517
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
518
+
519
+ inline __device__ void convert_from_float(uint32_t& dst, float2 src)
520
+ {
521
+ dst = float2_to_half2(src);
522
+ }
523
+
524
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
525
+ #ifdef ENABLE_BF16
526
+ inline __device__ void convert_from_float(__nv_bfloat16& dst, float src)
527
+ {
528
+ dst = __float2bfloat16(src);
529
+ }
530
+
531
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
532
+
533
+ inline __device__ void convert_from_float(__nv_bfloat162& dst, float2 src)
534
+ {
535
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
536
+ dst = __float22bfloat162_rn(src);
537
+ #else
538
+ dst = __floats2bfloat162_rn(src.x, src.y);
539
+ #endif
540
+ }
541
+ #endif // ENABLE_BF16
542
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
543
+
544
+ inline __device__ void convert_from_float(uint2& dst, Float4_ src)
545
+ {
546
+ dst.x = float2_to_half2(src.x);
547
+ dst.y = float2_to_half2(src.y);
548
+ }
549
+
550
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
551
+
552
+ inline __device__ void convert_from_float(uint2& dst, float4 src)
553
+ {
554
+ convert_from_float(dst, Float4_{make_float2(src.x, src.y), make_float2(src.z, src.w)});
555
+ }
556
+
557
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
558
+
559
+ inline __device__ void convert_from_float(uint4& dst, Float8_ src)
560
+ {
561
+ dst.x = float2_to_half2(src.x);
562
+ dst.y = float2_to_half2(src.y);
563
+ dst.z = float2_to_half2(src.z);
564
+ dst.w = float2_to_half2(src.w);
565
+ }
566
+
567
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
568
+
569
+ #ifdef ENABLE_BF16
570
+ inline __device__ void convert_from_float(bf16_4_t& dst, Float4_ src)
571
+ {
572
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
573
+ dst.x = __float22bfloat162_rn(src.x);
574
+ dst.y = __float22bfloat162_rn(src.y);
575
+ #else
576
+ dst.x = __floats2bfloat162_rn(src.x.x, src.x.y);
577
+ dst.y = __floats2bfloat162_rn(src.y.x, src.y.y);
578
+ #endif
579
+ }
580
+
581
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
582
+
583
+ inline __device__ void convert_from_float(bf16_4_t& dst, float4 src)
584
+ {
585
+ convert_from_float(dst, Float4_{make_float2(src.x, src.y), make_float2(src.z, src.w)});
586
+ }
587
+
588
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
589
+
590
+ inline __device__ void convert_from_float(bf16_8_t& dst, Float8_ src)
591
+ {
592
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
593
+ dst.x = __float22bfloat162_rn(src.x);
594
+ dst.y = __float22bfloat162_rn(src.y);
595
+ dst.z = __float22bfloat162_rn(src.z);
596
+ dst.w = __float22bfloat162_rn(src.w);
597
+ #else
598
+ dst.x = __floats2bfloat162_rn(src.x.x, src.x.y);
599
+ dst.y = __floats2bfloat162_rn(src.y.x, src.y.y);
600
+ dst.z = __floats2bfloat162_rn(src.z.x, src.z.y);
601
+ dst.w = __floats2bfloat162_rn(src.w.x, src.w.y);
602
+ #endif
603
+ }
604
+ #endif // ENABLE_BF16
605
+
606
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
607
+
608
+ inline __device__ void convert_from_float(float2& dst, float2 src)
609
+ {
610
+ dst = src;
611
+ }
612
+
613
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
614
+
615
+ inline __device__ void convert_from_float(float4& dst, float4 src)
616
+ {
617
+ dst = src;
618
+ }
619
+
620
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
621
+
622
+ inline __device__ float convert_to_float(float4 u)
623
+ {
624
+ return u.x;
625
+ }
626
+
627
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
628
+
629
+ inline __device__ float convert_to_float(uint4 u)
630
+ {
631
+ float2 tmp = half2_to_float2(u.x);
632
+ return tmp.x;
633
+ }
634
+
635
+ #if defined(MMHA_USE_FP32_ACUM_FOR_LOGITS)
636
+
637
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
638
+
639
+ inline __device__ float cast_to_float(float u)
640
+ {
641
+ return u;
642
+ }
643
+
644
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
645
+
646
+ inline __device__ float2 cast_to_float(float2 u)
647
+ {
648
+ return u;
649
+ }
650
+
651
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
652
+
653
+ inline __device__ float4 cast_to_float(float4 u)
654
+ {
655
+ return u;
656
+ }
657
+
658
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
659
+
660
+ inline __device__ Float4_ cast_to_float(Float4_ u)
661
+ {
662
+ return u;
663
+ }
664
+
665
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
666
+
667
+ inline __device__ Float8_ cast_to_float(Float8_ u)
668
+ {
669
+ return u;
670
+ }
671
+
672
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
673
+
674
+ inline __device__ float2 cast_to_float(uint32_t u)
675
+ {
676
+ return half2_to_float2(u);
677
+ }
678
+
679
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
680
+
681
+ inline __device__ Float4_ cast_to_float(uint2 u)
682
+ {
683
+ Float4_ tmp;
684
+ tmp.x = half2_to_float2(u.x);
685
+ tmp.y = half2_to_float2(u.y);
686
+ return tmp;
687
+ }
688
+
689
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
690
+
691
+ inline __device__ Float8_ cast_to_float(uint4 u)
692
+ {
693
+ Float8_ tmp;
694
+ tmp.x = half2_to_float2(u.x);
695
+ tmp.y = half2_to_float2(u.y);
696
+ tmp.z = half2_to_float2(u.z);
697
+ tmp.w = half2_to_float2(u.w);
698
+ return tmp;
699
+ }
700
+
701
+ #endif
702
+
703
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
704
+
705
+ inline __device__ float float_from_int8(int8_t u)
706
+ {
707
+ return u;
708
+ }
709
+
710
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
711
+
712
+ inline __device__ float2 float_from_int8(int16_t u)
713
+ {
714
+ union {
715
+ int16_t int16;
716
+ int8_t int8[2];
717
+ };
718
+ int16 = u;
719
+ return make_float2(int8[0], int8[1]);
720
+ }
721
+
722
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
723
+
724
+ inline __device__ float4 float_from_int8(int32_t u)
725
+ {
726
+ union {
727
+ int32_t int32;
728
+ int8_t int8[4];
729
+ };
730
+ int32 = u;
731
+ return make_float4(int8[0], int8[1], int8[2], int8[3]);
732
+ }
733
+
734
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
735
+
736
+ // clang-format off
737
+ inline __device__ Float8_ float_from_int8(int64_t u)
738
+ {
739
+ union {
740
+ int64_t int64;
741
+ int16_t int16[4];
742
+ };
743
+ int64 = u;
744
+ return Float8_ {float_from_int8(int16[0]),
745
+ float_from_int8(int16[1]),
746
+ float_from_int8(int16[2]),
747
+ float_from_int8(int16[3])};
748
+ }
749
+ // clang-format on
750
+
751
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
752
+
753
+ inline __device__ int8_t cast_to_int8(float val)
754
+ {
755
+ union {
756
+ int8_t int8[2];
757
+ int16_t int16;
758
+ };
759
+ asm volatile("cvt.rni.sat.s8.f32 %0, %1;" : "=h"(int16) : "f"(val));
760
+ return int8[0];
761
+ }
762
+
763
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
764
+
765
+ inline __device__ int32_t cast_to_int8(float4 val)
766
+ {
767
+ union {
768
+ int8_t int8[4];
769
+ int32_t int32;
770
+ };
771
+ int8[0] = cast_to_int8(val.x);
772
+ int8[1] = cast_to_int8(val.y);
773
+ int8[2] = cast_to_int8(val.z);
774
+ int8[3] = cast_to_int8(val.w);
775
+ return int32;
776
+ }
777
+
778
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
779
+
780
+ inline __device__ int64_t cast_to_int8(Float8_ val)
781
+ {
782
+ union {
783
+ int8_t int8[8];
784
+ int64_t int64;
785
+ };
786
+ int8[0] = cast_to_int8(val.x.x);
787
+ int8[1] = cast_to_int8(val.x.y);
788
+ int8[2] = cast_to_int8(val.y.x);
789
+ int8[3] = cast_to_int8(val.y.y);
790
+ int8[4] = cast_to_int8(val.z.x);
791
+ int8[5] = cast_to_int8(val.z.y);
792
+ int8[6] = cast_to_int8(val.w.x);
793
+ int8[7] = cast_to_int8(val.w.y);
794
+ return int64;
795
+ }
796
+
797
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
798
+
799
+ template<typename T>
800
+ inline __device__ __host__ T div_up(T m, T n)
801
+ {
802
+ return (m + n - 1) / n;
803
+ }
804
+
805
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
806
+
807
+ template<typename T, bool DO_CROSS_ATTENTION>
808
+ inline size_t smem_size_in_bytes(const Multihead_attention_params<T, DO_CROSS_ATTENTION>& params,
809
+ int threads_per_value,
810
+ int threads_per_block)
811
+ {
812
+ // The amount of shared memory needed to store the Q*K^T values in float.
813
+ const int max_timesteps = min(params.timestep, params.memory_max_len);
814
+ size_t qk_sz = (DO_CROSS_ATTENTION) ? div_up(params.memory_max_len + 1, 4) * 16 : div_up(max_timesteps + 1, 4) * 16;
815
+
816
+ // The extra memory needed if we are not using floats for the final logits.
817
+ size_t logits_sz = 0;
818
+ #ifndef MMHA_USE_FP32_ACUM_FOR_LOGITS
819
+ if (sizeof(T) != 4) {
820
+ // TDOD
821
+ logits_sz = (DO_CROSS_ATTENTION) ? div_up(params.memory_max_len + 1, 4) * 4 * sizeof(T) :
822
+ div_up(max_timesteps + 1, 4) * 4 * sizeof(T);
823
+ }
824
+ #endif
825
+
826
+ // The total size needed during softmax.
827
+ size_t softmax_sz = qk_sz + logits_sz;
828
+
829
+ // The number of partial rows to reduce in the final reduction.
830
+ int rows_per_red = threads_per_block / threads_per_value;
831
+ // The amount of storage needed to finalize the outputs.
832
+ size_t red_sz = rows_per_red * params.hidden_size_per_head * sizeof(T) / 2;
833
+
834
+ size_t transpose_rotary_size = 0;
835
+ if (params.rotary_embedding_dim > 0 && params.neox_rotary_style) {
836
+ transpose_rotary_size = 2 * params.rotary_embedding_dim * sizeof(T);
837
+ }
838
+
839
+ // The max.
840
+ return max(max(softmax_sz, red_sz), transpose_rotary_size);
841
+ }
842
+
843
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
844
+
845
+ inline __device__ constexpr uint32_t shfl_mask(int threads)
846
+ {
847
+ return threads == 32 ? uint32_t(-1) : (1u << threads) - 1u;
848
+ }
849
+
850
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
851
+
852
+ template<
853
+ // The type of the inputs. Supported types: float and half.
854
+ typename T,
855
+ // The hidden dimension per head.
856
+ int Dh,
857
+ int Dh_MAX,
858
+ // The number of threads per key.
859
+ int THREADS_PER_KEY,
860
+ // The number of threads per value.
861
+ int THREADS_PER_VALUE,
862
+ // The number of threads in a threadblock.
863
+ int THREADS_PER_BLOCK,
864
+ bool DO_CROSS_ATTENTION>
865
+ __global__ void masked_multihead_attention_kernel(Multihead_attention_params<T, DO_CROSS_ATTENTION> params)
866
+ {
867
+
868
+ // Make sure the hidden dimension per head is a multiple of the number of threads per key.
869
+ static_assert(Dh_MAX % THREADS_PER_KEY == 0, "");
870
+ // Make sure the hidden dimension per head is a multiple of the number of threads per value.
871
+ static_assert(Dh_MAX % THREADS_PER_VALUE == 0, "");
872
+
873
+ // The size of a warp.
874
+ constexpr int WARP_SIZE = 32;
875
+ // The number of warps in a threadblock.
876
+ constexpr int WARPS_PER_BLOCK = THREADS_PER_BLOCK / WARP_SIZE;
877
+
878
+ // Use smem_size_in_bytes (above) to determine the amount of shared memory.
879
+ extern __shared__ char smem_[];
880
+
881
+ // The shared memory for the Q*K^T values and partial logits in softmax.
882
+ float* qk_smem = reinterpret_cast<float*>(smem_);
883
+
884
+ // The shared memory for the logits. For FP32, that's the same buffer as qk_smem.
885
+ char* logits_smem_ = smem_;
886
+ #ifndef MMHA_USE_FP32_ACUM_FOR_LOGITS
887
+ if (sizeof(T) != 4) {
888
+ // TODO - change to tlength
889
+ const int max_timesteps = min(params.timestep, params.memory_max_len);
890
+ logits_smem_ +=
891
+ (DO_CROSS_ATTENTION) ? div_up(params.memory_max_len + 1, 4) * 16 : div_up(max_timesteps + 1, 4) * 16;
892
+ }
893
+ T* logits_smem = reinterpret_cast<T*>(logits_smem_);
894
+ #else
895
+ float* logits_smem = reinterpret_cast<float*>(logits_smem_);
896
+ #endif
897
+
898
+ // The shared memory to do the final reduction for the output values. Reuse qk_smem.
899
+ T* out_smem = reinterpret_cast<T*>(smem_);
900
+
901
+ // The shared memory buffers for the block-wide reductions. One for max, one for sum.
902
+ __shared__ float red_smem[WARPS_PER_BLOCK * 2];
903
+
904
+ // A vector of Q or K elements for the current timestep.
905
+ using Qk_vec = typename Qk_vec_<T, Dh_MAX>::Type;
906
+
907
+ // Use alignment for safely casting the shared buffers as Qk_vec.
908
+ // Shared memory to store Q inputs.
909
+ __shared__ __align__(sizeof(Qk_vec)) T q_smem[Dh_MAX];
910
+
911
+ // This is one of the reasons we should have a separate kernel for cross attention
912
+ __shared__ __align__(sizeof(Qk_vec)) T bias_smem[DO_CROSS_ATTENTION ? Dh_MAX : 1];
913
+
914
+ // A vector of Q or K elements for the current timestep.
915
+ using Qk_vec = typename Qk_vec_<T, Dh_MAX>::Type;
916
+ // The number of elements per vector.
917
+ constexpr int QK_VEC_SIZE = sizeof(Qk_vec) / sizeof(T);
918
+ // Make sure the hidden size per head is a multiple of the vector size.
919
+ static_assert(Dh_MAX % QK_VEC_SIZE == 0, "");
920
+ // We will use block wide reduction if needed
921
+ // static_assert(Dh_MAX / QK_VEC_SIZE <= WARP_SIZE, "");
922
+ // The number of vectors per warp.
923
+ constexpr int QK_VECS_PER_WARP = Dh_MAX / QK_VEC_SIZE;
924
+
925
+ // The layout of the cache is [B, H, Dh/x, L, x] with x == 4/8 for FP32/FP16. Since each thread
926
+ // owns x elements, we have to decompose the linear index into chunks of x values and the posi-
927
+ // tion of the thread in that chunk.
928
+
929
+ // The number of elements in a chunk of 16B (that's the x in the above formula).
930
+ constexpr int QK_ELTS_IN_16B = 16 / sizeof(T);
931
+ // The number of K vectors in 16B.
932
+ constexpr int QK_VECS_IN_16B = 16 / sizeof(Qk_vec);
933
+
934
+ // The batch/beam idx
935
+ const int bi = blockIdx.y;
936
+ if (params.finished != nullptr && params.finished[bi] == true) {
937
+ return;
938
+ }
939
+ // The beam idx
940
+ const int beami = bi % params.beam_width;
941
+ // The "beam-aware" batch idx
942
+ const int bbi = bi / params.beam_width;
943
+ // The head.
944
+ const int num_kv_heads = params.num_kv_heads;
945
+ const int kv_rep = (params.num_heads / num_kv_heads);
946
+ const int hi = blockIdx.x;
947
+ const int hi_kv = hi / kv_rep;
948
+
949
+ // Combine the batch and the head indices.
950
+ const int bhi = bi * params.num_heads + hi;
951
+ const int bhi_kv = bi * (params.num_heads / kv_rep) + hi_kv;
952
+ // Combine the "beam-aware" batch idx and the head indices.
953
+ const int bbhi = bbi * params.beam_width * params.num_heads + hi;
954
+ const int bbhi_kv = bbi * params.beam_width * (params.num_heads / kv_rep) + hi_kv;
955
+ // The thread in the block.
956
+ const int tidx = threadIdx.x;
957
+
958
+ const bool handle_kv = !DO_CROSS_ATTENTION || (DO_CROSS_ATTENTION && params.timestep == 0);
959
+ // Every kv_rep threads have the same kv_cache values. So only the first one writes back.
960
+ const int write_kv_cache = handle_kv && (hi % kv_rep == 0);
961
+
962
+ // While doing the product Q*K^T for the different keys we track the max.
963
+ float qk_max = -FLT_MAX;
964
+
965
+ float qk = 0.0F;
966
+
967
+ // int qkv_base_offset = (params.stride == 0) ? bhi * Dh : bi * params.stride + hi * Dh;
968
+ const int q_base_offset = bi * params.stride + hi * Dh;
969
+ const int k_base_offset = bi * params.stride + hi_kv * Dh;
970
+ const int v_base_offset = k_base_offset;
971
+
972
+ const size_t bi_seq_len_offset = bi * params.memory_max_len;
973
+
974
+ // int tlength = (DO_CROSS_ATTENTION)? params.memory_length_per_sample[bi] - 1 : params.timestep;
975
+ int tlength = (DO_CROSS_ATTENTION) ? params.memory_length_per_sample[bi] - 1 :
976
+ (params.length_per_sample == nullptr) ?
977
+ params.timestep :
978
+ params.length_per_sample[bi] + params.max_prefix_prompt_length;
979
+ const int first_step = max(0, tlength + 1 - params.memory_max_len);
980
+ const int tlength_circ = tlength % params.memory_max_len;
981
+
982
+ // First QK_VECS_PER_WARP load Q and K + the bias values for the current timestep.
983
+ const bool is_masked = tidx >= QK_VECS_PER_WARP;
984
+
985
+ // The offset in the Q and K buffer also accounts for the batch.
986
+ // int qk_offset = qkv_base_offset + tidx * QK_VEC_SIZE;
987
+ int q_offset = q_base_offset + tidx * QK_VEC_SIZE;
988
+ int k_offset = k_base_offset + tidx * QK_VEC_SIZE;
989
+ int v_offset = k_offset;
990
+
991
+ // The offset in the bias buffer.
992
+ // int qk_bias_offset = hi * Dh + tidx * QK_VEC_SIZE;
993
+ int q_bias_offset = hi * Dh + tidx * QK_VEC_SIZE;
994
+ int k_bias_offset = hi_kv * Dh + tidx * QK_VEC_SIZE;
995
+ int v_bias_offset = k_bias_offset;
996
+
997
+ const bool do_ia3 = handle_kv && params.ia3_tasks != nullptr;
998
+ const int ia3_task_id = do_ia3 ? params.ia3_tasks[bbi] : 0;
999
+
1000
+ // Trigger the loads from the Q and K buffers.
1001
+ Qk_vec q;
1002
+ zero(q);
1003
+ if (!is_masked && (Dh == Dh_MAX || tidx * QK_VEC_SIZE < Dh)) {
1004
+ if (params.int8_mode == 2) {
1005
+ using Packed_Int8_t = typename packed_type<int8_t, num_elems<Qk_vec>::value>::type;
1006
+ using Packed_Float_t = typename packed_type<float, num_elems<Qk_vec>::value>::type;
1007
+ const auto q_scaling = params.qkv_scale_out[0];
1008
+ const auto q_quant =
1009
+ *reinterpret_cast<const Packed_Int8_t*>(&reinterpret_cast<const int8_t*>(params.q)[q_offset]);
1010
+
1011
+ convert_from_float(q, mul<Packed_Float_t, float>(q_scaling, float_from_int8(q_quant)));
1012
+ }
1013
+ else {
1014
+ q = *reinterpret_cast<const Qk_vec*>(&params.q[q_offset]);
1015
+ }
1016
+ }
1017
+
1018
+ Qk_vec k;
1019
+ zero(k);
1020
+ if (DO_CROSS_ATTENTION) {
1021
+ // The 16B chunk written by the thread.
1022
+ int co = tidx / QK_VECS_IN_16B;
1023
+ // The position of the thread in that 16B chunk.
1024
+ int ci = tidx % QK_VECS_IN_16B * QK_VEC_SIZE;
1025
+
1026
+ // Two chunks are separated by L * x elements. A thread write QK_VEC_SIZE elements.
1027
+ int offset = bhi_kv * params.memory_max_len * Dh + co * params.memory_max_len * QK_ELTS_IN_16B +
1028
+ // params.timestep*QK_ELTS_IN_16B +
1029
+ tlength * QK_ELTS_IN_16B + ci;
1030
+ k = !is_masked && (Dh == Dh_MAX || tidx * QK_VEC_SIZE < Dh) ?
1031
+ *reinterpret_cast<const Qk_vec*>(&params.k_cache[offset]) :
1032
+ k;
1033
+ }
1034
+ else {
1035
+ if (!is_masked && (Dh == Dh_MAX || tidx * QK_VEC_SIZE < Dh)) {
1036
+ if (params.int8_mode == 2) {
1037
+ using Packed_Int8_t = typename packed_type<int8_t, num_elems<Qk_vec>::value>::type;
1038
+ using Packed_Float_t = typename packed_type<float, num_elems<Qk_vec>::value>::type;
1039
+ const auto k_scaling = params.qkv_scale_out[1];
1040
+ const auto k_quant =
1041
+ *reinterpret_cast<const Packed_Int8_t*>(&reinterpret_cast<const int8_t*>(params.k)[k_offset]);
1042
+
1043
+ convert_from_float(k, mul<Packed_Float_t, float>(k_scaling, float_from_int8(k_quant)));
1044
+ }
1045
+ else {
1046
+ k = *reinterpret_cast<const Qk_vec*>(&params.k[k_offset]);
1047
+ }
1048
+ }
1049
+ }
1050
+
1051
+ // Trigger the loads from the Q and K bias buffers.
1052
+ Qk_vec q_bias;
1053
+ zero(q_bias);
1054
+ q_bias = (!is_masked && Dh == Dh_MAX || tidx * QK_VEC_SIZE < Dh) && params.q_bias != nullptr ?
1055
+ *reinterpret_cast<const Qk_vec*>(&params.q_bias[q_bias_offset]) :
1056
+ q_bias;
1057
+
1058
+ Qk_vec k_bias;
1059
+ zero(k_bias);
1060
+ if (handle_kv) {
1061
+ k_bias = !is_masked && (Dh == Dh_MAX || tidx * QK_VEC_SIZE < Dh) && params.k_bias != nullptr ?
1062
+ *reinterpret_cast<const Qk_vec*>(&params.k_bias[k_bias_offset]) :
1063
+ k_bias;
1064
+ }
1065
+
1066
+ // Computes the Q/K values with bias.
1067
+ q = add(q, q_bias);
1068
+ if (handle_kv) {
1069
+ k = add(k, k_bias);
1070
+ }
1071
+ if (do_ia3 && !is_masked) {
1072
+ k = mul<Qk_vec, Qk_vec, Qk_vec>(
1073
+ k,
1074
+ *reinterpret_cast<const Qk_vec*>(
1075
+ &params.ia3_key_weights[(ia3_task_id * params.num_heads + hi) * Dh + tidx * QK_VEC_SIZE]));
1076
+ }
1077
+
1078
+ // Padded len
1079
+ const int padd_len = (params.total_padding_tokens == nullptr) ? 0 : params.total_padding_tokens[bi];
1080
+ if (params.rotary_embedding_dim > 0 && !params.neox_rotary_style) {
1081
+ if (handle_kv) {
1082
+ apply_rotary_embedding(q, k, tidx, params.rotary_embedding_dim, tlength - padd_len, params.rotary_base, params.rotary_scale);
1083
+ }
1084
+ else {
1085
+ apply_rotary_embedding(q, tidx, params.rotary_embedding_dim, tlength - padd_len, params.rotary_base, params.rotary_scale);
1086
+ }
1087
+ }
1088
+ else if (params.rotary_embedding_dim > 0 && params.neox_rotary_style) {
1089
+ const bool do_rotary = !is_masked && QK_VEC_SIZE * tidx < params.rotary_embedding_dim;
1090
+
1091
+ T* q_smem = reinterpret_cast<T*>(smem_);
1092
+ T* k_smem = q_smem + params.rotary_embedding_dim;
1093
+
1094
+ const int half_rotary_dim = params.rotary_embedding_dim / 2;
1095
+ const int half_idx = (tidx * QK_VEC_SIZE) / half_rotary_dim;
1096
+ const int intra_half_idx = (tidx * QK_VEC_SIZE) % half_rotary_dim;
1097
+ const int smem_pitch = half_rotary_dim; // TODO: adjust for bank conflicts
1098
+
1099
+ assert(half_rotary_dim % QK_VEC_SIZE == 0);
1100
+
1101
+ if (do_rotary) {
1102
+ *reinterpret_cast<Qk_vec*>(q_smem + half_idx * smem_pitch + intra_half_idx) = q;
1103
+
1104
+ if (handle_kv) {
1105
+ *reinterpret_cast<Qk_vec*>(k_smem + half_idx * smem_pitch + intra_half_idx) = k;
1106
+ }
1107
+ }
1108
+
1109
+ __syncthreads();
1110
+
1111
+ const int transpose_idx = half_idx * (half_rotary_dim / 2) + intra_half_idx / 2;
1112
+ constexpr int tidx_factor = (QK_VEC_SIZE > 1) ? QK_VEC_SIZE / 2 : 1;
1113
+ if (do_rotary) {
1114
+ mmha::vec_from_smem_transpose(q, q_smem, transpose_idx, smem_pitch);
1115
+
1116
+ if (handle_kv) {
1117
+ mmha::vec_from_smem_transpose(k, k_smem, transpose_idx, smem_pitch);
1118
+
1119
+ mmha::apply_rotary_embedding(
1120
+ q, k, transpose_idx / tidx_factor, params.rotary_embedding_dim, tlength - padd_len, params.rotary_base, params.rotary_scale);
1121
+
1122
+ mmha::write_smem_transpose(k, k_smem, transpose_idx, smem_pitch);
1123
+ }
1124
+ else {
1125
+ mmha::apply_rotary_embedding(
1126
+ q, transpose_idx / tidx_factor, params.rotary_embedding_dim, tlength, params.rotary_base, params.rotary_scale);
1127
+ }
1128
+ mmha::write_smem_transpose(q, q_smem, transpose_idx, smem_pitch);
1129
+ }
1130
+
1131
+ __syncthreads();
1132
+
1133
+ if (do_rotary) {
1134
+ q = *reinterpret_cast<Qk_vec*>(q_smem + half_idx * smem_pitch + intra_half_idx);
1135
+ if (handle_kv) {
1136
+ k = *reinterpret_cast<Qk_vec*>(k_smem + half_idx * smem_pitch + intra_half_idx);
1137
+ }
1138
+ }
1139
+
1140
+ __syncthreads();
1141
+ }
1142
+
1143
+ if (!is_masked) {
1144
+ // Store the Q values to shared memory.
1145
+ *reinterpret_cast<Qk_vec*>(&q_smem[tidx * QK_VEC_SIZE]) = q;
1146
+
1147
+ // Store Dh values of k_bias into smem, since will need to add later
1148
+ // if params.timestep == 0
1149
+ if (DO_CROSS_ATTENTION && params.timestep == 0) {
1150
+ *reinterpret_cast<Qk_vec*>(&bias_smem[tidx * QK_VEC_SIZE]) = k_bias;
1151
+ }
1152
+
1153
+ // Write the K values to the global memory cache.
1154
+ //
1155
+ // NOTE: The stores are uncoalesced as we have multiple chunks of 16B spread across the memory
1156
+ // system. We designed it this way as it allows much better memory loads (and there are many
1157
+ // more loads) + the stores are really "write and forget" since we won't need the ack before
1158
+ // the end of the kernel. There's plenty of time for the transactions to complete.
1159
+
1160
+ // The 16B chunk written by the thread.
1161
+ int co = tidx / QK_VECS_IN_16B;
1162
+ // The position of the thread in that 16B chunk.
1163
+ int ci = tidx % QK_VECS_IN_16B * QK_VEC_SIZE;
1164
+
1165
+ // Two chunks are separated by L * x elements. A thread write QK_VEC_SIZE elements.
1166
+ int offset = bhi_kv * params.memory_max_len * Dh + co * params.memory_max_len * QK_ELTS_IN_16B +
1167
+ // params.timestep*QK_ELTS_IN_16B +
1168
+ tlength_circ * QK_ELTS_IN_16B + ci;
1169
+
1170
+ if (write_kv_cache) {
1171
+ // Trigger the stores to global memory.
1172
+ if (Dh == Dh_MAX || co < Dh / QK_ELTS_IN_16B) {
1173
+ *reinterpret_cast<Qk_vec*>(&params.k_cache[offset]) = k;
1174
+ }
1175
+ }
1176
+
1177
+ // Compute \sum_i Q[i] * K^T[i] for the current timestep.
1178
+ #ifdef MMHA_USE_FP32_ACUM_FOR_FMA
1179
+ using Qk_vec_acum = typename Qk_vec_acum_fp32_<Qk_vec>::Type;
1180
+ #else
1181
+ using Qk_vec_acum = Qk_vec;
1182
+ #endif
1183
+ qk = dot<Qk_vec_acum, Qk_vec>(q, k);
1184
+ if (QK_VECS_PER_WARP <= WARP_SIZE) {
1185
+ #pragma unroll
1186
+ for (int mask = QK_VECS_PER_WARP / 2; mask >= 1; mask /= 2) {
1187
+ qk += __shfl_xor_sync(shfl_mask(QK_VECS_PER_WARP), qk, mask);
1188
+ }
1189
+ }
1190
+ }
1191
+
1192
+ if (QK_VECS_PER_WARP > WARP_SIZE) {
1193
+ constexpr int WARPS_PER_RED = (QK_VECS_PER_WARP + WARP_SIZE - 1) / WARP_SIZE;
1194
+ qk = block_sum<WARPS_PER_RED>(&red_smem[WARPS_PER_RED], qk);
1195
+ }
1196
+
1197
+ // Store that value in shared memory. Keep the Q*K^T value in register for softmax.
1198
+ if (tidx == 0) {
1199
+ // Normalize qk.
1200
+ qk *= params.inv_sqrt_dh;
1201
+ if (params.relative_attention_bias != nullptr) {
1202
+ // TODO (Haotian): check whether we should replace hi with hi_kv,
1203
+ // although params.relative_attention_bias is usually not used.
1204
+ qk = add(qk,
1205
+ params.relative_attention_bias[hi * params.relative_attention_bias_stride
1206
+ * params.relative_attention_bias_stride
1207
+ + (tlength - padd_len) * params.relative_attention_bias_stride
1208
+ + (tlength - padd_len)]);
1209
+ }
1210
+ // Add alibi positional encoding
1211
+ // qk += (alibi_slope != 0) ? alibi_slope * (params.timestep - params.memory_max_len) : 0;
1212
+ // We don't need to apply the linear position bias here since qi - ki = 0 yields the position bias 0.
1213
+
1214
+ qk_max = qk;
1215
+ qk_smem[tlength - first_step] = qk;
1216
+ // qk_smem[params.timestep] = qk;
1217
+ }
1218
+
1219
+ // Make sure the data is in shared memory.
1220
+ __syncthreads();
1221
+
1222
+ // The type of queries and keys for the math in the Q*K^T product.
1223
+ using K_vec = typename K_vec_<T, THREADS_PER_KEY>::Type;
1224
+ // The number of elements per vector.
1225
+ constexpr int K_VEC_SIZE = sizeof(K_vec) / sizeof(T);
1226
+ // Make sure the hidden size per head is a multiple of the vector size.
1227
+ static_assert(Dh_MAX % K_VEC_SIZE == 0, "");
1228
+ // The number of elements per thread.
1229
+ constexpr int K_ELTS_PER_THREAD = Dh_MAX / THREADS_PER_KEY;
1230
+ // The number of vectors per thread.
1231
+ constexpr int K_VECS_PER_THREAD = K_ELTS_PER_THREAD / K_VEC_SIZE;
1232
+
1233
+ // The position the first key loaded by each thread from the cache buffer (for this B * H).
1234
+ int ko = tidx / THREADS_PER_KEY;
1235
+ // The position of the thread in the chunk of keys.
1236
+ int ki = tidx % THREADS_PER_KEY * K_VEC_SIZE;
1237
+
1238
+ static_assert(Dh_MAX == THREADS_PER_KEY * K_VEC_SIZE * K_VECS_PER_THREAD);
1239
+
1240
+ // Load the Q values from shared memory. The values are reused during the loop on K.
1241
+ K_vec q_vec[K_VECS_PER_THREAD];
1242
+ #pragma unroll
1243
+ for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) {
1244
+ q_vec[ii] = *reinterpret_cast<const K_vec*>(&q_smem[ki + ii * THREADS_PER_KEY * K_VEC_SIZE]);
1245
+ }
1246
+
1247
+ K_vec k_bias_vec[DO_CROSS_ATTENTION ? K_VECS_PER_THREAD : 1];
1248
+ if (DO_CROSS_ATTENTION && params.timestep == 0) {
1249
+ #pragma unroll
1250
+ for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) {
1251
+ k_bias_vec[ii] = *reinterpret_cast<const K_vec*>(&bias_smem[ki + ii * THREADS_PER_KEY * K_VEC_SIZE]);
1252
+ }
1253
+ }
1254
+
1255
+ // The number of timesteps loaded per iteration.
1256
+ constexpr int K_PER_ITER = THREADS_PER_BLOCK / THREADS_PER_KEY;
1257
+ // The number of keys per warp.
1258
+ constexpr int K_PER_WARP = WARP_SIZE / THREADS_PER_KEY;
1259
+
1260
+ // The base pointer for the key in the cache buffer.
1261
+ T* k_cache = &params.k_cache[bhi_kv * params.memory_max_len * Dh + ki];
1262
+ // Base pointer for the beam's batch, before offsetting with indirection buffer
1263
+ T* k_cache_batch = &params.k_cache[bbhi_kv * params.memory_max_len * Dh + ki];
1264
+
1265
+ // Pick a number of keys to make sure all the threads of a warp enter (due to shfl_sync).
1266
+ // int ti_end = div_up(params.timestep, K_PER_WARP) * K_PER_WARP;
1267
+ int ti_end = div_up(tlength - first_step, K_PER_WARP) * K_PER_WARP + first_step;
1268
+
1269
+ // prefix prompt length if has
1270
+ const int prefix_prompt_length = (params.prefix_prompt_lengths == nullptr) ? 0 : params.prefix_prompt_lengths[bi];
1271
+
1272
+ // Iterate over the keys/timesteps to compute the various (Q*K^T)_{ti} values.
1273
+ const bool has_beams = params.cache_indir != nullptr;
1274
+ const int* beam_indices = has_beams ? &params.cache_indir[bi_seq_len_offset] : nullptr;
1275
+
1276
+ for (int ti = first_step + ko; ti < ti_end; ti += K_PER_ITER) {
1277
+ const int ti_circ = ti % params.memory_max_len;
1278
+
1279
+ // The keys loaded from the key cache.
1280
+ K_vec k[K_VECS_PER_THREAD];
1281
+ K_vec k_vec_zero;
1282
+ zero(k_vec_zero);
1283
+ #pragma unroll
1284
+ for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) {
1285
+ int jj = ii * params.memory_max_len + ti_circ;
1286
+ // if( ti < params.timestep ) {
1287
+ const bool within_bounds = (Dh == Dh_MAX || jj * QK_ELTS_IN_16B < Dh * params.memory_max_len);
1288
+ if (ti < tlength) {
1289
+ if (!within_bounds) {
1290
+ k[ii] = k_vec_zero;
1291
+ }
1292
+ else {
1293
+ if (has_beams) {
1294
+ const int beam_offset = beam_indices[ti_circ] * params.num_heads * params.memory_max_len * Dh;
1295
+ k[ii] = *reinterpret_cast<const K_vec*>(&k_cache_batch[beam_offset + jj * QK_ELTS_IN_16B]);
1296
+ }
1297
+ else {
1298
+ k[ii] = *reinterpret_cast<const K_vec*>(&k_cache_batch[jj * QK_ELTS_IN_16B]);
1299
+ }
1300
+ }
1301
+ // add bias and update k_cache
1302
+ if (DO_CROSS_ATTENTION && params.timestep == 0) {
1303
+ k[ii] = add(k[ii], k_bias_vec[ii]);
1304
+
1305
+ if (do_ia3) {
1306
+ k[ii] = mul<K_vec, K_vec, K_vec>(
1307
+ k[ii],
1308
+ *reinterpret_cast<const K_vec*>(
1309
+ &params.ia3_key_weights[(ia3_task_id * params.num_heads + hi) * Dh + ki
1310
+ + ii * THREADS_PER_KEY * K_VEC_SIZE]));
1311
+ }
1312
+
1313
+ if (Dh == Dh_MAX || jj * QK_ELTS_IN_16B < Dh * params.memory_max_len) {
1314
+ *reinterpret_cast<K_vec*>(&k_cache[jj * QK_ELTS_IN_16B]) = k[ii];
1315
+ }
1316
+ }
1317
+ }
1318
+ }
1319
+
1320
+ // Perform the dot product and normalize qk.
1321
+ //
1322
+ // WARNING: ALL THE THREADS OF A WARP MUST ENTER!!!
1323
+ float qk = Qk_dot<T, THREADS_PER_KEY>::dot(q_vec, k) * params.inv_sqrt_dh;
1324
+ bool is_mask = (params.masked_tokens != nullptr) && params.masked_tokens[bi_seq_len_offset + ti];
1325
+
1326
+ // Store the product to shared memory. There's one qk value per timestep. Update the max.
1327
+ // if( ti < params.timestep && tidx % THREADS_PER_KEY == 0 ) {
1328
+ if (ti < tlength && tidx % THREADS_PER_KEY == 0) {
1329
+ if (params.relative_attention_bias != nullptr) {
1330
+ qk = add(qk,
1331
+ params.relative_attention_bias[hi * params.relative_attention_bias_stride
1332
+ * params.relative_attention_bias_stride
1333
+ + tlength * params.relative_attention_bias_stride + ti]);
1334
+ }
1335
+ if (params.linear_bias_slopes != nullptr) {
1336
+ // Apply the linear position bias: (ki - qi) * slope[hi].
1337
+ // The padding token locates between the input context and the generated tokens.
1338
+ // We need to remove the number of padding tokens in the distance computation.
1339
+ // ti : 0 1 2 3 4 5 6 7 8 9(tlength)
1340
+ // token: i i i i p p p o o o where i=input, p=pad, o=output.
1341
+ // e.g. ti = 2, dist = (9 - 3) - 2 = 4.
1342
+ int max_context_length = params.max_prefix_prompt_length + params.max_input_length;
1343
+ float dist = (ti < max_context_length ? ti + padd_len : ti) - tlength;
1344
+
1345
+ qk += mul<float, float, float>(params.linear_bias_slopes[hi], dist);
1346
+ }
1347
+ // Add alibi positional encoding
1348
+ // qk += (alibi_slope != 0) ? alibi_slope * (params.timestep - params.memory_max_len) : 0;
1349
+ qk_max = is_mask ? qk_max : fmaxf(qk_max, qk);
1350
+ qk_smem[ti - first_step] = qk;
1351
+ }
1352
+ }
1353
+
1354
+ // Perform the final reduction to compute the max inside each warp.
1355
+ //
1356
+ // NOTE: In a group of THREADS_PER_KEY threads, the leader already has the max value for the
1357
+ // group so it's not needed to run the reduction inside the group (again).
1358
+ #pragma unroll
1359
+ for (int mask = WARP_SIZE / 2; mask >= THREADS_PER_KEY; mask /= 2) {
1360
+ qk_max = fmaxf(qk_max, __shfl_xor_sync(uint32_t(-1), qk_max, mask));
1361
+ }
1362
+
1363
+ // Decompose the thread index into warp and lane.
1364
+ const int warp = tidx / WARP_SIZE;
1365
+ const int lane = tidx % WARP_SIZE;
1366
+
1367
+ // The warp leader writes the max to shared memory.
1368
+ if (lane == 0) {
1369
+ red_smem[warp] = qk_max;
1370
+ }
1371
+
1372
+ // Make sure the products are in shared memory.
1373
+ __syncthreads();
1374
+
1375
+ // The warps finalize the reduction.
1376
+ qk_max = lane < WARPS_PER_BLOCK ? red_smem[lane] : -FLT_MAX;
1377
+ #pragma unroll
1378
+ for (int mask = WARPS_PER_BLOCK / 2; mask >= 1; mask /= 2) {
1379
+ qk_max = fmaxf(qk_max, __shfl_xor_sync(uint32_t(-1), qk_max, mask));
1380
+ }
1381
+
1382
+ // Broadcast to all the threads in the warp.
1383
+ qk_max = __shfl_sync(uint32_t(-1), qk_max, 0);
1384
+
1385
+ // Compute the logits and start the sum.
1386
+ float sum = 0.f;
1387
+ // for( int ti = tidx; ti <= params.timestep; ti += THREADS_PER_BLOCK ) {
1388
+ for (int ti = first_step + tidx; ti <= tlength; ti += THREADS_PER_BLOCK) {
1389
+ bool is_mask = (params.masked_tokens != nullptr) && params.masked_tokens[bi_seq_len_offset + ti];
1390
+ float logit = is_mask ? 0.f : __expf(qk_smem[ti - first_step] - qk_max);
1391
+ sum += logit;
1392
+ qk_smem[ti - first_step] = logit;
1393
+ }
1394
+
1395
+ // Compute the sum.
1396
+ sum = block_sum<WARPS_PER_BLOCK>(&red_smem[WARPS_PER_BLOCK], sum);
1397
+
1398
+ // Normalize the logits.
1399
+ float inv_sum = __fdividef(1.f, sum + 1.e-6f);
1400
+ // for( int ti = tidx; ti <= params.timestep; ti += THREADS_PER_BLOCK ) {
1401
+ const size_t cross_attention_out_offset =
1402
+ params.is_return_cross_attentions ?
1403
+ bhi_kv * params.max_decoder_seq_len * params.memory_max_len + params.timestep * params.memory_max_len :
1404
+ 0;
1405
+ for (int ti = first_step + tidx; ti <= tlength; ti += THREADS_PER_BLOCK) {
1406
+ float logit = qk_smem[ti - first_step] * inv_sum;
1407
+ if (params.is_return_cross_attentions) {
1408
+ params.cross_attention_out[cross_attention_out_offset + ti] = logit;
1409
+ }
1410
+ convert_from_float(logits_smem[ti - first_step], logit);
1411
+ }
1412
+
1413
+ // Put Values part below so we leverage __syncthreads
1414
+ // from the previous step
1415
+
1416
+ // The number of elements per vector.
1417
+ constexpr int V_VEC_SIZE = Dh_MAX / THREADS_PER_VALUE;
1418
+ // A vector of V elements for the current timestep.
1419
+ using V_vec = typename V_vec_<T, V_VEC_SIZE>::Type;
1420
+
1421
+ // The value computed by this thread.
1422
+ int vo = tidx / THREADS_PER_VALUE;
1423
+ // The hidden dimensions computed by this particular thread.
1424
+ int vi = tidx % THREADS_PER_VALUE * V_VEC_SIZE;
1425
+
1426
+ // The base pointer for the value in the cache buffer.
1427
+ T* v_cache = &params.v_cache[bhi_kv * params.memory_max_len * Dh + vi];
1428
+ // Base pointer for the beam's batch, before offsetting with indirection buffer
1429
+ T* v_cache_batch = &params.v_cache[bbhi_kv * params.memory_max_len * Dh + vi];
1430
+
1431
+ // The number of values processed per iteration of the loop.
1432
+ constexpr int V_PER_ITER = THREADS_PER_BLOCK / THREADS_PER_VALUE;
1433
+
1434
+ // One group of threads computes the product(s) for the current timestep.
1435
+ V_vec v_bias;
1436
+ zero(v_bias);
1437
+ // if( vo == params.timestep % V_PER_ITER ) {
1438
+ if (Dh == Dh_MAX || vi < Dh) {
1439
+ if (handle_kv) {
1440
+ if (vo == tlength % V_PER_ITER) {
1441
+ // Trigger the loads from the V bias buffer.
1442
+ if (params.v_bias != nullptr) {
1443
+ v_bias = *reinterpret_cast<const V_vec*>(&params.v_bias[hi_kv * Dh + vi]);
1444
+ }
1445
+ if (DO_CROSS_ATTENTION) {
1446
+ *reinterpret_cast<V_vec*>(&bias_smem[vi]) = v_bias;
1447
+ }
1448
+ }
1449
+ }
1450
+ }
1451
+
1452
+ // From previous, before values, step
1453
+ // Also make sure the logits are in shared memory.
1454
+ __syncthreads();
1455
+
1456
+ // Values continued
1457
+ #ifdef MMHA_USE_FP32_ACUM_FOR_OUT
1458
+ using V_vec_acum = typename V_vec_acum_fp32_<V_vec>::Type;
1459
+ #else
1460
+ using V_vec_acum = V_vec;
1461
+ #endif
1462
+ // The partial outputs computed by each thread.
1463
+ V_vec_acum out;
1464
+ zero(out);
1465
+
1466
+ // Loop over the timesteps to compute the partial outputs.
1467
+ // for( int ti = vo; ti < params.timestep; ti += V_PER_ITER ) {
1468
+ if (Dh == Dh_MAX || vi < Dh) {
1469
+ for (int ti = first_step + vo; ti < tlength; ti += V_PER_ITER) {
1470
+ const int ti_circ = ti % params.memory_max_len;
1471
+
1472
+ // Fetch offset based on cache_indir when beam sampling
1473
+ const int beam_src = (params.cache_indir != nullptr) ? params.cache_indir[bi_seq_len_offset + ti_circ] : 0;
1474
+ const int beam_offset = beam_src * params.num_heads * params.memory_max_len * Dh;
1475
+ // Load the values from the cache.
1476
+ V_vec v = *reinterpret_cast<const V_vec*>(&v_cache_batch[beam_offset + ti_circ * Dh]);
1477
+ if (DO_CROSS_ATTENTION && params.timestep == 0) {
1478
+ v = add(v, *reinterpret_cast<V_vec*>(&bias_smem[vi]));
1479
+ if (do_ia3) {
1480
+ v = mul<V_vec, V_vec, V_vec>(
1481
+ v,
1482
+ *reinterpret_cast<const V_vec*>(
1483
+ &params.ia3_value_weights[(ia3_task_id * params.num_heads + hi) * Dh + vi]));
1484
+ }
1485
+ *reinterpret_cast<V_vec*>(&v_cache[ti * Dh]) = v;
1486
+ }
1487
+ // Load the logits from shared memory.
1488
+ #if defined(MMHA_USE_FP32_ACUM_FOR_LOGITS)
1489
+ float logit = logits_smem[ti - first_step];
1490
+ out = fma(logit, cast_to_float(v), out);
1491
+ #else
1492
+ T logit = logits_smem[ti - first_step];
1493
+
1494
+ // Update the partial sums.
1495
+ out = fma(logit, v, out);
1496
+ #endif
1497
+ }
1498
+ }
1499
+
1500
+ // One group of threads computes the product(s) for the current timestep.
1501
+ // if( vo == params.timestep % V_PER_ITER ) {
1502
+ if (vo == tlength % V_PER_ITER && (Dh == Dh_MAX || vi < Dh)) {
1503
+
1504
+ V_vec v;
1505
+ if (DO_CROSS_ATTENTION) {
1506
+ v = *reinterpret_cast<const V_vec*>(&v_cache[tlength * Dh]);
1507
+ }
1508
+ else {
1509
+ // Trigger the loads from the V buffer.
1510
+ const auto v_offset = v_base_offset + vi;
1511
+ if (params.int8_mode == 2) {
1512
+ using Packed_Int8_t = typename packed_type<int8_t, num_elems<V_vec>::value>::type;
1513
+ using Packed_Float_t = typename packed_type<float, num_elems<V_vec>::value>::type;
1514
+ const auto v_scaling = params.qkv_scale_out[2];
1515
+ const auto v_quant =
1516
+ *reinterpret_cast<const Packed_Int8_t*>(&reinterpret_cast<const int8_t*>(params.v)[v_offset]);
1517
+
1518
+ convert_from_float(v, mul<Packed_Float_t, float>(v_scaling, float_from_int8(v_quant)));
1519
+ }
1520
+ else {
1521
+ v = *reinterpret_cast<const V_vec*>(&params.v[v_offset]);
1522
+ }
1523
+ // Trigger the loads from the V bias buffer.
1524
+ // V_vec v_bias = *reinterpret_cast<const V_vec*>(&params.v_bias[hi*Dh + vi]);
1525
+ }
1526
+
1527
+ // Compute the V values with bias.
1528
+ v = add(v, v_bias);
1529
+ if (write_kv_cache) {
1530
+
1531
+ if (do_ia3) {
1532
+ v = mul<V_vec, V_vec, V_vec>(
1533
+ v,
1534
+ *reinterpret_cast<const V_vec*>(
1535
+ &params.ia3_value_weights[(ia3_task_id * params.num_heads + hi) * Dh + vi]));
1536
+ }
1537
+
1538
+ // Store the values with bias back to global memory in the cache for V.
1539
+ //*reinterpret_cast<V_vec*>(&v_cache[params.timestep*Dh]) = v;
1540
+ *reinterpret_cast<V_vec*>(&v_cache[tlength_circ * Dh]) = v;
1541
+ }
1542
+
1543
+ // Initialize the output value with the current timestep.
1544
+ #if defined(MMHA_USE_FP32_ACUM_FOR_LOGITS)
1545
+ // out = fma(logits_smem[params.timestep], cast_to_float(v), out);
1546
+ out = fma(logits_smem[tlength - first_step], cast_to_float(v), out);
1547
+ #else
1548
+ // out = fma(logits_smem[params.timestep], v, out);
1549
+ out = fma(logits_smem[tlength - first_step], v, out);
1550
+ #endif
1551
+ }
1552
+
1553
+ // Make sure we can start writing to shared memory.
1554
+ __syncthreads();
1555
+
1556
+ // Run the final reduction amongst the different groups computing different partial outputs.
1557
+ if (Dh == Dh_MAX || vi < Dh) {
1558
+ #pragma unroll
1559
+ for (int active_groups = V_PER_ITER; active_groups >= 2; active_groups /= 2) {
1560
+
1561
+ // The midpoint in the number of active groups.
1562
+ int midpoint = active_groups / 2;
1563
+
1564
+ // The upper part of active threads store to shared memory.
1565
+ if (vo >= midpoint && vo < active_groups && (Dh == Dh_MAX || vi < Dh)) {
1566
+ #ifdef MMHA_USE_FP32_ACUM_FOR_OUT
1567
+ convert_from_float(*reinterpret_cast<V_vec*>(&out_smem[(vo - midpoint) * Dh + vi]), out);
1568
+ #else
1569
+ *reinterpret_cast<V_vec*>(&out_smem[(vo - midpoint) * Dh + vi]) = out;
1570
+ #endif
1571
+ }
1572
+ __syncthreads();
1573
+
1574
+ // The bottom warps update their values.
1575
+ if (vo < midpoint && (Dh == Dh_MAX || vi < Dh)) {
1576
+ out = add(*reinterpret_cast<const V_vec*>(&out_smem[vo * Dh + vi]), out);
1577
+ }
1578
+ __syncthreads();
1579
+ }
1580
+ }
1581
+
1582
+ // Output the final values.
1583
+ if (vo == 0 && (Dh == Dh_MAX || vi < Dh)) {
1584
+ #ifdef MMHA_USE_FP32_ACUM_FOR_OUT
1585
+ if (params.int8_mode == 2) {
1586
+ using Packed_Int8_t = typename packed_type<int8_t, num_elems<V_vec_acum>::value>::type;
1587
+ out = mul<V_vec_acum, float>(*params.attention_out_scale, out);
1588
+ *reinterpret_cast<Packed_Int8_t*>(&(reinterpret_cast<int8_t*>(params.out)[bhi * Dh + vi])) =
1589
+ cast_to_int8(out);
1590
+ }
1591
+ else {
1592
+ convert_from_float(*reinterpret_cast<V_vec*>(&params.out[bhi * Dh + vi]), out);
1593
+ }
1594
+ #else
1595
+ // TODO: support int8_mode?
1596
+ *reinterpret_cast<V_vec*>(&params.out[bhi * Dh + vi]) = out;
1597
+ #endif
1598
+ }
1599
+ }
1600
+
1601
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
1602
+
1603
+ } // namespace mmha
1604
+
1605
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
1606
+
1607
+ template<typename T, int Dh, int Dh_MAX, typename KERNEL_PARAMS_TYPE>
1608
+ void mmha_launch_kernel(const KERNEL_PARAMS_TYPE& params, const cudaStream_t& stream);
llm-awq/awq/kernels/csrc/attention/setup.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from https://github.com/NVIDIA/apex/blob/master/setup.py
2
+ import sys
3
+ import warnings
4
+ import os
5
+ from packaging.version import parse, Version
6
+
7
+ from setuptools import setup, find_packages
8
+ import subprocess
9
+
10
+ import torch
11
+ from torch.utils.cpp_extension import (
12
+ BuildExtension,
13
+ CppExtension,
14
+ CUDAExtension,
15
+ CUDA_HOME,
16
+ )
17
+
18
+
19
+ # ninja build does not work unless include_dirs are abs path
20
+ this_dir = os.path.dirname(os.path.abspath(__file__))
21
+
22
+
23
+ def get_cuda_bare_metal_version(cuda_dir):
24
+ raw_output = subprocess.check_output(
25
+ [cuda_dir + "/bin/nvcc", "-V"], universal_newlines=True
26
+ )
27
+ output = raw_output.split()
28
+ release_idx = output.index("release") + 1
29
+ bare_metal_version = parse(output[release_idx].split(",")[0])
30
+
31
+ return raw_output, bare_metal_version
32
+
33
+
34
+ def check_cuda_torch_binary_vs_bare_metal(cuda_dir):
35
+ raw_output, bare_metal_version = get_cuda_bare_metal_version(cuda_dir)
36
+ torch_binary_version = parse(torch.version.cuda)
37
+
38
+ print("\nCompiling cuda extensions with")
39
+ print(raw_output + "from " + cuda_dir + "/bin\n")
40
+
41
+ if bare_metal_version != torch_binary_version:
42
+ raise RuntimeError(
43
+ "Cuda extensions are being compiled with a version of Cuda that does "
44
+ "not match the version used to compile Pytorch binaries. "
45
+ "Pytorch binaries were compiled with Cuda {}.\n".format(torch.version.cuda)
46
+ + "In some cases, a minor-version mismatch will not cause later errors: "
47
+ "https://github.com/NVIDIA/apex/pull/323#discussion_r287021798. "
48
+ "You can try commenting out this check (at your own risk)."
49
+ )
50
+
51
+
52
+ def raise_if_cuda_home_none(global_option: str) -> None:
53
+ if CUDA_HOME is not None:
54
+ return
55
+ raise RuntimeError(
56
+ f"{global_option} was requested, but nvcc was not found. Are you sure your environment has nvcc available? "
57
+ "If you're installing within a container from https://hub.docker.com/r/pytorch/pytorch, "
58
+ "only images whose names contain 'devel' will provide nvcc."
59
+ )
60
+
61
+
62
+ def append_nvcc_threads(nvcc_extra_args):
63
+ _, bare_metal_version = get_cuda_bare_metal_version(CUDA_HOME)
64
+ if bare_metal_version >= Version("11.2"):
65
+ return nvcc_extra_args + ["--threads", "4"]
66
+ return nvcc_extra_args
67
+
68
+
69
+ if not torch.cuda.is_available():
70
+ # https://github.com/NVIDIA/apex/issues/486
71
+ # Extension builds after https://github.com/pytorch/pytorch/pull/23408 attempt to query torch.cuda.get_device_capability(),
72
+ # which will fail if you are compiling in an environment without visible GPUs (e.g. during an nvidia-docker build command).
73
+ print(
74
+ "\nWarning: Torch did not find available GPUs on this system.\n",
75
+ "If your intention is to cross-compile, this is not an error.\n"
76
+ "By default, Apex will cross-compile for Pascal (compute capabilities 6.0, 6.1, 6.2),\n"
77
+ "Volta (compute capability 7.0), Turing (compute capability 7.5),\n"
78
+ "and, if the CUDA version is >= 11.0, Ampere (compute capability 8.0).\n"
79
+ "If you wish to cross-compile for a single specific architecture,\n"
80
+ 'export TORCH_CUDA_ARCH_LIST="compute capability" before running setup.py.\n',
81
+ )
82
+ if os.environ.get("TORCH_CUDA_ARCH_LIST", None) is None and CUDA_HOME is not None:
83
+ _, bare_metal_version = get_cuda_bare_metal_version(CUDA_HOME)
84
+ if bare_metal_version >= Version("11.8"):
85
+ os.environ["TORCH_CUDA_ARCH_LIST"] = "6.0;6.1;6.2;7.0;7.5;8.0;8.6;9.0"
86
+ elif bare_metal_version >= Version("11.1"):
87
+ os.environ["TORCH_CUDA_ARCH_LIST"] = "6.0;6.1;6.2;7.0;7.5;8.0;8.6"
88
+ elif bare_metal_version == Version("11.0"):
89
+ os.environ["TORCH_CUDA_ARCH_LIST"] = "6.0;6.1;6.2;7.0;7.5;8.0"
90
+ else:
91
+ os.environ["TORCH_CUDA_ARCH_LIST"] = "6.0;6.1;6.2;7.0;7.5"
92
+
93
+
94
+ print("\n\ntorch.__version__ = {}\n\n".format(torch.__version__))
95
+ TORCH_MAJOR = int(torch.__version__.split(".")[0])
96
+ TORCH_MINOR = int(torch.__version__.split(".")[1])
97
+
98
+ cmdclass = {}
99
+ ext_modules = []
100
+
101
+ # Check, if ATen/CUDAGeneratorImpl.h is found, otherwise use ATen/cuda/CUDAGeneratorImpl.h
102
+ # See https://github.com/pytorch/pytorch/pull/70650
103
+ generator_flag = []
104
+ torch_dir = torch.__path__[0]
105
+ if os.path.exists(os.path.join(torch_dir, "include", "ATen", "CUDAGeneratorImpl.h")):
106
+ generator_flag = ["-DOLD_GENERATOR_PATH"]
107
+
108
+ raise_if_cuda_home_none("--ft_attention")
109
+ # Check, if CUDA11 is installed for compute capability 8.0
110
+ cc_flag = []
111
+ _, bare_metal_version = get_cuda_bare_metal_version(CUDA_HOME)
112
+ if bare_metal_version < Version("11.0"):
113
+ raise RuntimeError("ft_attention is only supported on CUDA 11 and above")
114
+ cc_flag.append("-gencode")
115
+ cc_flag.append("arch=compute_70,code=sm_70")
116
+ cc_flag.append("-gencode")
117
+ cc_flag.append("arch=compute_80,code=sm_80")
118
+ if bare_metal_version >= Version("11.8"):
119
+ cc_flag.append("-gencode")
120
+ cc_flag.append("arch=compute_90,code=sm_90")
121
+
122
+ ext_modules.append(
123
+ CUDAExtension(
124
+ name="ft_attention",
125
+ sources=[
126
+ "ft_attention.cpp",
127
+ "decoder_masked_multihead_attention.cu",
128
+ ],
129
+ extra_compile_args={
130
+ "cxx": ["-O3", "-DENABLE_BF16"] + generator_flag,
131
+ "nvcc": append_nvcc_threads(
132
+ [
133
+ "-DENABLE_BF16", # TODO
134
+ "-O3",
135
+ "-U__CUDA_NO_HALF_OPERATORS__",
136
+ "-U__CUDA_NO_HALF_CONVERSIONS__",
137
+ "-U__CUDA_NO_BFLOAT16_OPERATORS__",
138
+ "-U__CUDA_NO_BFLOAT16_CONVERSIONS__",
139
+ "-U__CUDA_NO_BFLOAT162_OPERATORS__",
140
+ "-U__CUDA_NO_BFLOAT162_CONVERSIONS__",
141
+ "--expt-relaxed-constexpr",
142
+ "--expt-extended-lambda",
143
+ "--use_fast_math",
144
+ ]
145
+ + generator_flag
146
+ + cc_flag
147
+ ),
148
+ },
149
+ include_dirs=[this_dir],
150
+ )
151
+ )
152
+
153
+ setup(
154
+ name="ft_attention",
155
+ version="0.1",
156
+ description="Attention for single query from FasterTransformer",
157
+ ext_modules=ext_modules,
158
+ cmdclass={"build_ext": BuildExtension} if ext_modules else {},
159
+ )
llm-awq/awq/kernels/csrc/layernorm/layernorm.h ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #include <torch/extension.h>
2
+
3
+ void layernorm_forward_cuda(torch::Tensor _input, torch::Tensor _gamma, torch::Tensor _out, float eps);
llm-awq/awq/kernels/csrc/layernorm/reduction.cuh ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Adapted from NVIDIA FasterTransformer:
4
+ https://github.com/NVIDIA/FasterTransformer/blob/main/src/fastertransformer/kernels/reduce_kernel_utils.cuh
5
+ */
6
+
7
+ #pragma once
8
+ #include <assert.h>
9
+ #if ((__CUDACC_VER_MAJOR__ > 11) || (__CUDACC_VER_MAJOR__ == 11 && __CUDACC_VER_MINOR__ >= 0))
10
+ #include <cooperative_groups/reduce.h>
11
+ #else
12
+ #include <cooperative_groups.h>
13
+ #endif
14
+ #include <cuda_fp16.h>
15
+ #include <cuda_runtime.h>
16
+ #include <float.h>
17
+ #include <type_traits>
18
+
19
+ static const float HALF_FLT_MAX = 65504.F;
20
+ #define FINAL_MASK 0xffffffff
21
+
22
+
23
+ template<typename T>
24
+ inline __device__ T add(T a, T b) {
25
+ return a + b;
26
+ }
27
+
28
+ template<>
29
+ inline __device__ half2 add(half2 a, half2 b) {
30
+ return __hadd2(a, b);
31
+ }
32
+
33
+ template<>
34
+ inline __device__ half add(half a, half b) {
35
+ return __hadd(a, b);
36
+ }
37
+
38
+ template<typename T>
39
+ __inline__ __device__ T warpReduceSum(T val)
40
+ {
41
+ #pragma unroll
42
+ for (int mask = 16; mask > 0; mask >>= 1)
43
+ val = add(val, __shfl_xor_sync(FINAL_MASK, val, mask, 32)); //__shfl_sync bf16 return float when sm < 80
44
+ return val;
45
+ }
46
+
47
+ /* Calculate the sum of all elements in a block */
48
+ template<typename T>
49
+ __inline__ __device__ T blockReduceSum(T val)
50
+ {
51
+ static __shared__ T shared[32];
52
+ int lane = threadIdx.x & 0x1f;
53
+ int wid = threadIdx.x >> 5;
54
+
55
+ val = warpReduceSum<T>(val);
56
+
57
+ if (lane == 0)
58
+ shared[wid] = val;
59
+
60
+ __syncthreads();
61
+
62
+ // Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
63
+ // blockDim.x is not divided by 32
64
+ val = (threadIdx.x < (blockDim.x / 32.f)) ? shared[lane] : (T)(0.0f);
65
+ val = warpReduceSum<T>(val);
66
+
67
+ return val;
68
+ }
69
+
70
+
71
+ template<typename T>
72
+ __device__ __forceinline__ T clamp_inf_for_half(const float input)
73
+ {
74
+ return input;
75
+ }
76
+
77
+ template<>
78
+ __device__ __forceinline__ half clamp_inf_for_half(const float input)
79
+ {
80
+ // clamp inf values to enable fp16 training
81
+ return input > 0.0f ? __float2half(min(input, HALF_FLT_MAX - 1000)) : __float2half(max(input, -HALF_FLT_MAX + 1000));
82
+ }
llm-awq/awq/kernels/csrc/position_embedding/pos_encoding_kernels.cu ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+
3
+ Adapted from the VLLM project:
4
+ https://github.com/vllm-project/vllm/blob/main/csrc/pos_encoding_kernels.cu
5
+
6
+ */
7
+
8
+ #include <torch/extension.h>
9
+ #include <ATen/cuda/CUDAContext.h>
10
+ #include "pos_encoding.h"
11
+
12
+ template<typename scalar_t>
13
+ __global__ void rotary_embedding_neox_kernel(
14
+ const int64_t* __restrict__ positions, // [num_tokens]
15
+ scalar_t* __restrict__ query, // [num_tokens, num_heads, head_size]
16
+ scalar_t* __restrict__ key, // [num_tokens, num_heads, head_size]
17
+ const scalar_t* __restrict__ cos_sin_cache, // [max_position, 2, rot_dim // 2]
18
+ const int rot_dim,
19
+ const int stride,
20
+ const int num_heads,
21
+ const int head_size) {
22
+ // Each thread block is responsible for one token.
23
+ const int token_idx = blockIdx.x;
24
+ int64_t pos = positions[token_idx];
25
+ const scalar_t* cache_ptr = cos_sin_cache + pos * rot_dim;
26
+
27
+ const int embed_dim = rot_dim / 2;
28
+ const int n = num_heads * embed_dim;
29
+ for (int i = threadIdx.x; i < n; i += blockDim.x) {
30
+ const int head_idx = i / embed_dim;
31
+ const int token_head = token_idx * stride + head_idx * head_size;
32
+
33
+ const int rot_offset = i % embed_dim;
34
+ const int x_index = rot_offset;
35
+ const int y_index = embed_dim + rot_offset;
36
+
37
+ const int out_x = token_idx * stride + head_idx * head_size + x_index;
38
+ const int out_y = token_idx * stride + head_idx * head_size + y_index;
39
+
40
+ const scalar_t cos = __ldg(cache_ptr + x_index);
41
+ const scalar_t sin = __ldg(cache_ptr + y_index);
42
+
43
+ const scalar_t q_x = query[token_head + x_index];
44
+ const scalar_t q_y = query[token_head + y_index];
45
+ query[out_x] = q_x * cos - q_y * sin;
46
+ query[out_y] = q_y * cos + q_x * sin;
47
+
48
+ const scalar_t k_x = key[token_head + x_index];
49
+ const scalar_t k_y = key[token_head + y_index];
50
+ key[out_x] = k_x * cos - k_y * sin;
51
+ key[out_y] = k_y * cos + k_x * sin;
52
+ }
53
+ }
54
+
55
+ void rotary_embedding_neox(
56
+ torch::Tensor& positions, // [b, num_tokens]
57
+ torch::Tensor& query, // [b, num_tokens, 1, num_heads, head_size]
58
+ torch::Tensor& key, // [b, num_tokens, 1, num_heads, head_size]
59
+ int head_size,
60
+ torch::Tensor& cos_sin_cache) // [max_position, rot_dim]
61
+ {
62
+ int num_tokens = query.size(0) * query.size(1);
63
+ int rot_dim = cos_sin_cache.size(1);
64
+ int num_heads = query.size(-2);
65
+ int stride = num_heads * head_size;
66
+ // TORCH_CHECK(stride == key.stride(0));
67
+
68
+ dim3 grid(num_tokens);
69
+ dim3 block(std::min(num_heads * rot_dim / 2, 512));
70
+ const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
71
+ AT_DISPATCH_FLOATING_TYPES_AND2(
72
+ at::ScalarType::Half,
73
+ at::ScalarType::BFloat16,
74
+ query.scalar_type(),
75
+ "rotary_embedding_neox",
76
+ [&] {
77
+ rotary_embedding_neox_kernel<scalar_t><<<grid, block, 0, stream>>>(
78
+ positions.data_ptr<int64_t>(),
79
+ query.data_ptr<scalar_t>(),
80
+ key.data_ptr<scalar_t>(),
81
+ cos_sin_cache.data_ptr<scalar_t>(),
82
+ rot_dim,
83
+ stride,
84
+ num_heads,
85
+ head_size);
86
+ });
87
+ }
88
+
llm-awq/awq/kernels/csrc/quantization/dequantize.cuh ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Modified from NVIDIA FasterTransformer: https://github.com/NVIDIA/FasterTransformer/blob/main/src/fastertransformer/cutlass_extensions/include/cutlass_extensions/interleaved_numeric_conversion.h
3
+
4
+ @article{lin2023awq,
5
+ title={AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration},
6
+ author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Dang, Xingyu and Han, Song},
7
+ journal={arXiv},
8
+ year={2023}
9
+ }
10
+ */
11
+
12
+ #pragma once
13
+
14
+
15
+ __device__ uint4 dequantize_s4_to_fp16x2(uint32_t const& source)
16
+ {
17
+ uint4 result;
18
+
19
+ uint32_t* h = reinterpret_cast<uint32_t*>(&result);
20
+ uint32_t const i4s = reinterpret_cast<uint32_t const&>(source);
21
+
22
+ // First, we extract the i4s and construct an intermediate fp16 number.
23
+ static constexpr uint32_t immLut = (0xf0 & 0xcc) | 0xaa;
24
+ static constexpr uint32_t BOTTOM_MASK = 0x000f000f;
25
+ static constexpr uint32_t TOP_MASK = 0x00f000f0;
26
+ static constexpr uint32_t I4s_TO_F16s_MAGIC_NUM = 0x64006400;
27
+
28
+ // Note that the entire sequence only requires 1 shift instruction. This is thanks to the register packing
29
+ // format and the fact that we force our integers to be unsigned, and account for this in the fp16 subtractions.
30
+ // In addition, I exploit the fact that sub and fma have the same throughput in order to convert elt_23 and
31
+ // elt_67 to fp16 without having to shift them to the bottom bits before hand.
32
+
33
+ // Shift right by 8 to now consider elt_45 and elt_67. Issue first to hide RAW dependency if we issue
34
+ // immediately before required.
35
+ const uint32_t top_i4s = i4s >> 8;
36
+ // Extract elt_01 - (i4s & 0x000f000f) | 0x64006400
37
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
38
+ : "=r"(h[0])
39
+ : "r"(i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
40
+ // Extract elt_23 (i4s & 0x00f000f0) | 0x64006400
41
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
42
+ : "=r"(h[1])
43
+ : "r"(i4s), "n"(TOP_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
44
+ // Extract elt_45 (top_i4s & 0x000f000f) | 0x64006400
45
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
46
+ : "=r"(h[2])
47
+ : "r"(top_i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
48
+ // Extract elt_67 (top_i4s & 0x00f000f0) | 0x64006400
49
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
50
+ : "=r"(h[3])
51
+ : "r"(top_i4s), "n"(TOP_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
52
+
53
+ // I use inline PTX below because I am not sure if the compiler will emit float2half instructions if I use the
54
+ // half2 ctor. In this case, I chose performance reliability over code readability.
55
+
56
+ // This is the half2 {1032, 1032} represented as an integer.
57
+ // static constexpr uint32_t FP16_TOP_MAGIC_NUM = 0x64086408;
58
+ // Haotian: subtract {1024, 1024} instead, we do not need to map to [-8, 7]
59
+ static constexpr uint32_t FP16_TOP_MAGIC_NUM = 0x64006400;
60
+ // This is the half2 {1 / 16, 1 / 16} represented as an integer.
61
+ static constexpr uint32_t ONE_SIXTEENTH = 0x2c002c00;
62
+ // This is the half2 {-72, -72} represented as an integer.
63
+ // static constexpr uint32_t NEG_72 = 0xd480d480;
64
+ // Haotian: Let's use {-64, -64}.
65
+ static constexpr uint32_t NEG_64 = 0xd400d400;
66
+
67
+ // Finally, we construct the output numbers.
68
+ // Convert elt_01
69
+ asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(h[0]) : "r"(h[0]), "r"(FP16_TOP_MAGIC_NUM));
70
+ // Convert elt_23
71
+ asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n" : "=r"(h[1]) : "r"(h[1]), "r"(ONE_SIXTEENTH), "r"(NEG_64));
72
+ // Convert elt_45
73
+ asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(h[2]) : "r"(h[2]), "r"(FP16_TOP_MAGIC_NUM));
74
+ // Convert elt_67
75
+ asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n" : "=r"(h[3]) : "r"(h[3]), "r"(ONE_SIXTEENTH), "r"(NEG_64));
76
+
77
+ return result;
78
+ }
79
+
llm-awq/awq/kernels/csrc/quantization/gemm_cuda.h ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #include <torch/extension.h>
2
+
3
+ torch::Tensor gemm_forward_cuda(torch::Tensor _in_feats, torch::Tensor _kernel,
4
+ torch::Tensor _scaling_factors, torch::Tensor _zeros, int group_size, int split_k_iters);
llm-awq/awq/kernels/csrc/quantization/gemm_cuda_gen.cu ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Inspired by NVIDIA's FasterTransformer
2
+ /*
3
+
4
+ @article{lin2023awq,
5
+ title={AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration},
6
+ author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Dang, Xingyu and Han, Song},
7
+ journal={arXiv},
8
+ year={2023}
9
+ }
10
+
11
+ */
12
+
13
+ #include <torch/extension.h>
14
+ #include "gemm_cuda.h"
15
+ #include <cuda_fp16.h>
16
+ #include <c10/cuda/CUDAGuard.h>
17
+
18
+
19
+ // Pack two half values.
20
+ static inline __device__ __host__ unsigned
21
+ __pack_half2(const half x, const half y) {
22
+ unsigned v0 = *((unsigned short *)&x);
23
+ unsigned v1 = *((unsigned short *)&y);
24
+ return (v1 << 16) | v0;
25
+ }
26
+
27
+ __device__ __forceinline__ int make_divisible(int c, int divisor){
28
+ return (c + divisor - 1) / divisor;
29
+ }
30
+
31
+ template <int G>
32
+ __global__ void __launch_bounds__(128) gemm_forward_4bit_cuda_m128n64k32(int split_k_iters, half* __restrict__ A, int* __restrict__ B, half* __restrict__ scaling_factors, int* zeros, int M, int IC, int OC, half* __restrict__ C)
33
+ {
34
+ static constexpr uint32_t ZERO = 0x0;
35
+ float C_warp[64];
36
+ __shared__ half A_shared[128 * (32 + 8)];
37
+ __shared__ half B_shared[64 * (32 + 8)];
38
+
39
+ // __shared__ half scaling_factors_shared[64];
40
+ // __shared__ half zeros_shared[64];
41
+
42
+ int j_factors1 = ((OC + 64 - 1) / 64);
43
+
44
+ int blockIdx_x = 0;
45
+ int blockIdx_y = blockIdx.x % ((M + 128 - 1) / 128 * j_factors1);
46
+ int blockIdx_z = blockIdx.x / ((M + 128 - 1) / 128 * j_factors1);
47
+
48
+ half A_shared_warp[32];
49
+ half B_shared_warp[16];
50
+ for (int i_0_3_init = 0; i_0_3_init < 4; ++i_0_3_init) {
51
+ for (int j_0_4_init = 0; j_0_4_init < 2; ++j_0_4_init) {
52
+ for (int i = 0; i < 8; ++i) {
53
+ C_warp[((i_0_3_init * 16) + (j_0_4_init * 8)) + i] = 0.0;
54
+ }
55
+ }
56
+ }
57
+
58
+ static constexpr int row_stride_warp = 32 * 8 / 32;
59
+ static constexpr int row_stride_A = 4 * 32 * 8 / 32;
60
+ static constexpr int row_stride = 4 * 32 * 8 / 32;
61
+ const int make_divisible_multipler = 128 / G;
62
+ const int zeros_w = make_divisible(make_divisible(IC / G, 8), make_divisible_multipler) * make_divisible_multipler;
63
+ const int sf_w = zeros_w * 8;
64
+
65
+ bool ld_zero_flag = (threadIdx.y * 32 + threadIdx.x) * 8 < 64;
66
+ int ld_A_row = (blockIdx_y / j_factors1 * 128 + threadIdx.y * row_stride_warp + threadIdx.x * 8 / 32); // threadIdx.y is warp_id
67
+ // bool wb_C_flag = (threadIdx.x / 4) < M;
68
+
69
+ half* A_ptr = A
70
+ + (((int)blockIdx_y) / j_factors1 * 128 + (((int)threadIdx.y) * row_stride_warp) + ((int)threadIdx.x) / (32 / 8)) * IC
71
+ + (((int)threadIdx.x) % (32 / 8)) * 8;
72
+
73
+ int* B_ptr = B
74
+ + ((int)threadIdx.y) * (IC / 8) * 8
75
+ + (((int)threadIdx.x) / (32 / 8)) * (IC / 8)
76
+ + (((int)blockIdx_y) % j_factors1) * 64 * (IC / 8)
77
+ + (((int)threadIdx.x) % (32 / 8)) * 1;
78
+
79
+ // Why * 1 in the above line?
80
+
81
+ half* A_shared_ptr = A_shared
82
+ + ((int)threadIdx.y) * row_stride_warp * (32 + 8)
83
+ + (((int)threadIdx.x) / (32 / 8)) * (32 + 8)
84
+ + (((int)threadIdx.x) % (32 / 8) ) * 8;
85
+
86
+ half* B_shared_ptr = B_shared
87
+ + ((int)threadIdx.y) * (row_stride / 4) * (32 + 8)
88
+ + (((int)threadIdx.x) / (32 / 8)) * (32 + 8)
89
+ + (((int)threadIdx.x) % (32 / 8)) * 8;
90
+
91
+
92
+ int* zeros_ptr = zeros
93
+ + ((int)threadIdx.y) * zeros_w * 8
94
+ + (((int)threadIdx.x) / (32 / 8)) * zeros_w
95
+ + (((int)blockIdx_y) % j_factors1) * 64 * zeros_w
96
+ // this term is zero
97
+ + (((int)threadIdx.x) % (32 / 8)) / G ;
98
+
99
+ half* scaling_factors_ptr = scaling_factors
100
+ + ((int)threadIdx.y) * sf_w * 8
101
+ + (((int)threadIdx.x) / (32 / 8)) * sf_w
102
+ + (((int)blockIdx_y) % j_factors1) * (64) * sf_w
103
+ // this term is zero
104
+ + (((int)threadIdx.x) % (32 / 8)) * 8 / G;
105
+
106
+
107
+ // Haotian: TBD, check, May 29 11:46 AM PST
108
+ half* C_ptr = C
109
+ + blockIdx_z * M * OC // blockIdx_z -> split_k dim
110
+ + (((int)blockIdx_y) % j_factors1) * 64
111
+ + (((int)threadIdx.y) / 2) * 32
112
+ + (((int)threadIdx.x) % 4) * 2;
113
+
114
+ // preload s.f. and zeros
115
+ int k_bound = make_divisible(IC / 32, split_k_iters); // (IC / 32 + split_k_iters - 1) / split_k_iters;
116
+ if ((k_bound - 1) * 32 + blockIdx_z >= IC) k_bound -= 1;
117
+
118
+ // TODO (Haotian): load scales and zero points to smem
119
+
120
+ for (int _k_0_0 = 0; _k_0_0 < k_bound; ++_k_0_0) {
121
+ int k_0_0 = _k_0_0 * split_k_iters + blockIdx_z;
122
+ __syncthreads();
123
+ // TODO: Haotian: Here we assume M % cta_M = 0.
124
+ for (int ax0_ax1_fused_0 = 0; ax0_ax1_fused_0 < 4; ++ax0_ax1_fused_0)
125
+ {
126
+ if (ld_A_row + ax0_ax1_fused_0 * row_stride_A < M)
127
+ {
128
+ *(uint4*)(A_shared_ptr + ax0_ax1_fused_0 * row_stride_A * 40) = *(uint4*)(A_ptr + (ax0_ax1_fused_0 * row_stride_A * IC) + (k_0_0 * 32));
129
+ }
130
+ else
131
+ {
132
+ *(uint4*)(A_shared_ptr + ax0_ax1_fused_0 * row_stride_A * 40) = make_uint4(0, 0, 0, 0);
133
+ }
134
+ }
135
+
136
+
137
+ int* zeros_ptr_local = zeros_ptr + k_0_0 * 32 / G / 8;
138
+ half* scaling_factors_ptr_local = scaling_factors_ptr + k_0_0 * 32 / G;
139
+
140
+ // uint4 B_loaded_scale = make_uint4(0, 0, 0, 0);
141
+ int* B_ptr_local = B_ptr + k_0_0 * (32 / 8);
142
+
143
+ for (int ax0_ax1_fused_0 = 0; ax0_ax1_fused_0 < 2; ++ax0_ax1_fused_0) {
144
+
145
+ // B: 32 x 136 (128+8) float16
146
+ // each warp: 32 x 4
147
+ // each thr: read 32 bit -> convert to 8xFP16 (a UINT4) -> scale and minus zero -> WB UINT4
148
+ // row stride in shared memory: (NWARPS * 32 * 8 / cta_N)
149
+ int B_loaded_current = *(B_ptr_local + ax0_ax1_fused_0 * row_stride * (IC / 8));
150
+ int zeros_loaded = *(zeros_ptr_local + ax0_ax1_fused_0 * row_stride * zeros_w);
151
+ zeros_loaded >>= ((k_0_0 * 32 / G) % 8) * 4;
152
+ float current_zeros = (float)(zeros_loaded & 0xF);
153
+ half scaling_factors_loaded = *(scaling_factors_ptr_local + ax0_ax1_fused_0 * row_stride * sf_w);
154
+ half B_loaded_fp16[8];
155
+ #pragma unroll
156
+ for (int ic_1 = 0; ic_1 < 8; ic_1++){
157
+ float current_single_weight_fp = (float)(B_loaded_current & 0xF);
158
+ half dequantized_weight = __float2half(__half2float(scaling_factors_loaded) * (current_single_weight_fp - current_zeros));
159
+ B_loaded_current = B_loaded_current >> 4;
160
+ B_loaded_fp16[ic_1] = dequantized_weight;
161
+ }
162
+ // write back
163
+ *(uint4*)(B_shared_ptr + ax0_ax1_fused_0 * row_stride * (32 + 8)) = *reinterpret_cast<uint4*>(B_loaded_fp16);
164
+ }
165
+ __syncthreads();
166
+ for (int k_0_1 = 0; k_0_1 < 2; ++k_0_1) {
167
+ for (int ax0_0 = 0; ax0_0 < 4; ++ax0_0) {
168
+ {
169
+ unsigned int addr;
170
+ __asm__ __volatile__(
171
+ "{ .reg .u64 addr; cvta.to.shared.u64 addr, %1; cvt.u32.u64 %0, addr; }\n"
172
+ : "=r"(addr)
173
+ : "l"((void *)((&(A_shared[((((((int)threadIdx.y) & 1) * 2560) + (ax0_0 * 640)) + (k_0_1 * 16))])) + (((((int)threadIdx.x) & 15) * 40) + ((((int)threadIdx.x) >> 4) * 8))))
174
+ );
175
+ __asm__ __volatile__(
176
+ "ldmatrix.sync.aligned.m8n8.x4.shared.b16"
177
+ "{%0, %1, %2, %3}, [%4];\n"
178
+ : "=r"(((unsigned *)(A_shared_warp + (ax0_0 * 8)))[0]), "=r"(((unsigned *)(A_shared_warp + (ax0_0 * 8)))[1]), "=r"(((unsigned *)(A_shared_warp + (ax0_0 * 8)))[2]), "=r"(((unsigned *)(A_shared_warp + (ax0_0 * 8)))[3])
179
+ : "r"(addr)
180
+ );
181
+ }
182
+ }
183
+
184
+ for (int ax0_0_1 = 0; ax0_0_1 < 2; ++ax0_0_1) {
185
+ {
186
+ unsigned int addr;
187
+ __asm__ __volatile__(
188
+ "{ .reg .u64 addr; cvta.to.shared.u64 addr, %1; cvt.u32.u64 %0, addr; }\n"
189
+ : "=r"(addr)
190
+ : "l"((void *)((&(B_shared[((((((int)threadIdx.y) >> 1) * 1280) + (ax0_0_1 * 640)) + (k_0_1 * 16))])) + ((((((int)threadIdx.x) >> 4) * 320) + ((((int)threadIdx.x) & 7) * 40)) + (((((int)threadIdx.x) & 15) >> 3) * 8))))
191
+ );
192
+ __asm__ __volatile__(
193
+ "ldmatrix.sync.aligned.m8n8.x4.shared.b16"
194
+ "{%0, %1, %2, %3}, [%4];\n"
195
+ : "=r"(((unsigned *)(B_shared_warp + (ax0_0_1 * 8)))[0]), "=r"(((unsigned *)(B_shared_warp + (ax0_0_1 * 8)))[1]), "=r"(((unsigned *)(B_shared_warp + (ax0_0_1 * 8)))[2]), "=r"(((unsigned *)(B_shared_warp + (ax0_0_1 * 8)))[3])
196
+ : "r"(addr)
197
+ );
198
+ }
199
+ }
200
+
201
+ for (int i_0_3 = 0; i_0_3 < 4; ++i_0_3) {
202
+ for (int j_0_4 = 0; j_0_4 < 2; ++j_0_4) {
203
+
204
+ {
205
+ __asm__ __volatile__(
206
+ "mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32"
207
+ "{%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%10, %11, %12, %13};\n"
208
+ : "=f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[0]), "=f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[1]), "=f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[2]), "=f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[3])
209
+ : "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[0]), "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[1]), "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[2]), "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[3]), "r"(((unsigned *)(B_shared_warp + (j_0_4 * 8)))[0]), "r"(((unsigned *)(B_shared_warp + (j_0_4 * 8)))[1]), "f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[0]), "f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[1]), "f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[2]), "f"(((float *)(C_warp + ((i_0_3 * 16) + (j_0_4 * 8))))[3]));
210
+ }
211
+
212
+ {
213
+ __asm__ __volatile__(
214
+ "mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32"
215
+ "{%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%10, %11, %12, %13};\n"
216
+ : "=f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[0]), "=f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[1]), "=f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[2]), "=f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[3])
217
+ : "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[0]), "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[1]), "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[2]), "r"(((unsigned *)(A_shared_warp + (i_0_3 * 8)))[3]), "r"(((unsigned *)(B_shared_warp + ((j_0_4 * 8) + 4)))[0]), "r"(((unsigned *)(B_shared_warp + ((j_0_4 * 8) + 4)))[1]), "f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[0]), "f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[1]), "f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[2]), "f"(((float *)(C_warp + (((i_0_3 * 16) + (j_0_4 * 8)) + 4)))[3]));
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ // Haotian: Here (May 29 11:46AM PST)
225
+ // TODO: Shang: Hoist loop invariance.
226
+ for (int ax0_0_2 = 0; ax0_0_2 < 4; ++ax0_0_2) {
227
+ for (int ax1_0 = 0; ax1_0 < 2; ++ax1_0) {
228
+ for (int local_id = 0; local_id < 8; ++local_id) {
229
+ int row_offset = (((int)blockIdx_y) / j_factors1) * 128 + (threadIdx.y % 2) * 64 + ax0_0_2 * 16 + (local_id % 4) / 2 * 8 + ((int)threadIdx.x) / 4;
230
+ if (row_offset < M)
231
+ {
232
+ *(C_ptr + ax1_0 * 16 + row_offset * OC + (local_id / 4) * 8 + local_id % 2) = __float2half(C_warp[(ax0_0_2 * 16) + (ax1_0 * 8) + local_id]);
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }
238
+
239
+ // in_feats: M, IC [float16]
240
+ // kernel: IC, OC // 8 [int32] -> cast to IC, OC [uint4b]
241
+ // scaling_factors: IC // G, OC [float16]
242
+ // zeros: IC // G, OC // 8 [int32] -> cast to IC // G, OC [uint4b]
243
+ // assume that batch_size < 16 for now
244
+
245
+ torch::Tensor gemm_forward_cuda(
246
+ torch::Tensor _in_feats,
247
+ torch::Tensor _kernel,
248
+ torch::Tensor _scaling_factors,
249
+ torch::Tensor _zeros,
250
+ int group_size,
251
+ int split_k_iters)
252
+ {
253
+ int num_in_feats = _in_feats.size(0);
254
+ int num_in_channels = _in_feats.size(1);
255
+ const at::cuda::OptionalCUDAGuard device_guard(device_of(_in_feats));
256
+
257
+ auto options = torch::TensorOptions().dtype(_in_feats.dtype()).device(_in_feats.device());
258
+ // for int4, need _kernel.size(1) * 8
259
+ at::Tensor _out_feats = torch::empty({split_k_iters, num_in_feats, _kernel.size(0)}, options);
260
+ int num_out_feats = _out_feats.size(-2);
261
+ int num_out_channels = _out_feats.size(-1);
262
+
263
+ auto in_feats = reinterpret_cast<half*>(_in_feats.data_ptr<at::Half>());
264
+ auto kernel = reinterpret_cast<int*>(_kernel.data_ptr<int>());
265
+ auto out_feats = reinterpret_cast<half*>(_out_feats.data_ptr<at::Half>());
266
+ auto scaling_factors = reinterpret_cast<half*>(_scaling_factors.data_ptr<at::Half>());
267
+ auto zeros = reinterpret_cast<int*>(_zeros.data_ptr<int>());
268
+
269
+ // blockIdx_x: i_factors[0] * j_factors[0]
270
+ // blockIdx_y: i_factors[1] * j_factors[1]
271
+
272
+ if (num_out_channels % 64 != 0)
273
+ throw std::invalid_argument("OC is not multiple of cta_N = 64");
274
+ if (num_out_channels % 8 != 0)
275
+ throw std::invalid_argument("OC is not multiple of pack_num = 8");
276
+ int j_factors1 = num_out_channels / 64 / 1;
277
+ dim3 num_blocks((num_out_feats + 128 - 1) / 128 * j_factors1 * split_k_iters);
278
+
279
+ // threadIdx.x: 32
280
+ // threadIdx.y: i_factors[2] * j_factors[2]
281
+ dim3 threads_per_block(32, 4);
282
+ if (group_size == 128)
283
+ {
284
+ gemm_forward_4bit_cuda_m128n64k32<128><<<num_blocks, threads_per_block>>>(
285
+ split_k_iters, in_feats, kernel, scaling_factors, zeros, num_in_feats, num_in_channels, num_out_channels, out_feats);
286
+ }
287
+ else if (group_size == 64)
288
+ {
289
+ gemm_forward_4bit_cuda_m128n64k32<64><<<num_blocks, threads_per_block>>>(
290
+ split_k_iters, in_feats, kernel, scaling_factors, zeros, num_in_feats, num_in_channels, num_out_channels, out_feats);
291
+ }
292
+ else
293
+ {
294
+ throw std::invalid_argument("Group size temporarily not supported.");
295
+ }
296
+ return _out_feats.sum(0);
297
+ }
298
+
llm-awq/awq/kernels/csrc/quantization/gemv_cuda.h ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+ #include <torch/extension.h>
3
+
4
+ torch::Tensor gemv_forward_cuda(
5
+ torch::Tensor _in_feats,
6
+ torch::Tensor _kernel,
7
+ torch::Tensor _scaling_factors,
8
+ torch::Tensor _zeros,
9
+ int group_size);
llm-awq/awq/kernels/csrc/quantization_new/dequantize.cuh ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Modified from NVIDIA FasterTransformer: https://github.com/NVIDIA/FasterTransformer/blob/main/src/fastertransformer/cutlass_extensions/include/cutlass_extensions/interleaved_numeric_conversion.h
3
+
4
+ @article{lin2023awq,
5
+ title={AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration},
6
+ author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Dang, Xingyu and Han, Song},
7
+ journal={arXiv},
8
+ year={2023}
9
+ }
10
+ */
11
+ #include <cuda_fp16.h>
12
+ #include <cuda_bf16.h>
13
+ #pragma once
14
+
15
+ template <typename T = half>
16
+ __inline__ __device__ void dequantize_s4_to_fp16x2(half2 const &source, uint4 *result);
17
+
18
+ template <>
19
+ __inline__ __device__ void dequantize_s4_to_fp16x2<half>(half2 const &source, uint4 *result)
20
+ {
21
+ // uint4 result;
22
+
23
+ uint32_t *h = reinterpret_cast<uint32_t *>(result);
24
+ uint32_t const i4s = reinterpret_cast<uint32_t const &>(source);
25
+
26
+ // First, we extract the i4s and construct an intermediate fp16 number.
27
+ constexpr uint32_t immLut = (0xf0 & 0xcc) | 0xaa;
28
+ constexpr uint32_t BOTTOM_MASK = 0x000f000f;
29
+ constexpr uint32_t TOP_MASK = 0x00f000f0;
30
+ constexpr uint32_t I4s_TO_F16s_MAGIC_NUM = 0x64006400;
31
+
32
+ // Note that the entire sequence only requires 1 shift instruction. This is thanks to the register packing
33
+ // format and the fact that we force our integers to be unsigned, and account for this in the fp16 subtractions.
34
+ // In addition, I exploit the fact that sub and fma have the same throughput in order to convert elt_23 and
35
+ // elt_67 to fp16 without having to shift them to the bottom bits before hand.
36
+
37
+ // Shift right by 8 to now consider elt_45 and elt_67. Issue first to hide RAW dependency if we issue
38
+ // immediately before required.
39
+ const uint32_t top_i4s = i4s >> 8;
40
+ // Extract elt_01 - (i4s & 0x000f000f) | 0x64006400
41
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
42
+ : "=r"(h[0])
43
+ : "r"(i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
44
+ // Extract elt_23 (i4s & 0x00f000f0) | 0x64006400
45
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
46
+ : "=r"(h[1])
47
+ : "r"(i4s), "n"(TOP_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
48
+ // Extract elt_45 (top_i4s & 0x000f000f) | 0x64006400
49
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
50
+ : "=r"(h[2])
51
+ : "r"(top_i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
52
+ // Extract elt_67 (top_i4s & 0x00f000f0) | 0x64006400
53
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
54
+ : "=r"(h[3])
55
+ : "r"(top_i4s), "n"(TOP_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
56
+
57
+ // I use inline PTX below because I am not sure if the compiler will emit float2half instructions if I use the
58
+ // half2 ctor. In this case, I chose performance reliability over code readability.
59
+
60
+ // This is the half2 {1032, 1032} represented as an integer.
61
+ // static constexpr uint32_t FP16_TOP_MAGIC_NUM = 0x64086408;
62
+ // Haotian: subtract {1024, 1024} instead, we do not need to map to [-8, 7]
63
+ static constexpr uint32_t FP16_TOP_MAGIC_NUM = 0x64006400;
64
+ // This is the half2 {1 / 16, 1 / 16} represented as an integer.
65
+ static constexpr uint32_t ONE_SIXTEENTH = 0x2c002c00;
66
+ // This is the half2 {-72, -72} represented as an integer.
67
+ // static constexpr uint32_t NEG_72 = 0xd480d480;
68
+ // Haotian: Let's use {-64, -64}.
69
+ static constexpr uint32_t NEG_64 = 0xd400d400;
70
+
71
+ // Finally, we construct the output numbers.
72
+ // Convert elt_01
73
+ asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(h[0]) : "r"(h[0]), "r"(FP16_TOP_MAGIC_NUM));
74
+ // Convert elt_23
75
+ asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n" : "=r"(h[1]) : "r"(h[1]), "r"(ONE_SIXTEENTH), "r"(NEG_64));
76
+ // Convert elt_45
77
+ asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(h[2]) : "r"(h[2]), "r"(FP16_TOP_MAGIC_NUM));
78
+ // Convert elt_67
79
+ asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n" : "=r"(h[3]) : "r"(h[3]), "r"(ONE_SIXTEENTH), "r"(NEG_64));
80
+ }
81
+
82
+ template <>
83
+ __inline__ __device__ void dequantize_s4_to_fp16x2<nv_bfloat16>(half2 const &source, uint4 *result)
84
+ {
85
+ // uint4 result;
86
+
87
+ uint32_t *h = reinterpret_cast<uint32_t *>(result);
88
+ uint32_t const i4s = reinterpret_cast<uint32_t const &>(source);
89
+
90
+ // First, we extract the i4s and construct an intermediate bf16 number.
91
+ constexpr uint32_t immLut = (0xf0 & 0xcc) | 0xaa;
92
+ constexpr uint32_t BOTTOM_MASK = 0x000f000f;
93
+ constexpr uint32_t I4s_TO_BF16s_MAGIC_NUM = 0x43004300;
94
+
95
+ // Shift right by 4, 8, 12 to consider elt_23, elt_45 and elt_67.
96
+ const uint32_t i4s1 = i4s >> 4;
97
+ const uint32_t i4s2 = i4s >> 8;
98
+ const uint32_t i4s3 = i4s >> 12;
99
+ // Extract elt_01 - (i4s & 0x000f000f) | 0x43004300
100
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
101
+ : "=r"(h[0])
102
+ : "r"(i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_BF16s_MAGIC_NUM), "n"(immLut));
103
+ // Extract elt_23 - (i4s & 0x000f000f) | 0x43004300
104
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
105
+ : "=r"(h[1])
106
+ : "r"(i4s1), "n"(BOTTOM_MASK), "n"(I4s_TO_BF16s_MAGIC_NUM), "n"(immLut));
107
+ // Extract elt_45 - (i4s & 0x000f000f) | 0x43004300
108
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
109
+ : "=r"(h[2])
110
+ : "r"(i4s2), "n"(BOTTOM_MASK), "n"(I4s_TO_BF16s_MAGIC_NUM), "n"(immLut));
111
+ // Extract elt_67 - (i4s & 0x000f000f) | 0x43004300
112
+ asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
113
+ : "=r"(h[3])
114
+ : "r"(i4s3), "n"(BOTTOM_MASK), "n"(I4s_TO_BF16s_MAGIC_NUM), "n"(immLut));
115
+
116
+ // This is the nv_bfloat162 {128, 128} represented as an integer
117
+ static constexpr uint32_t BF16_TOP_MAGIC_NUM = 0x43004300;
118
+
119
+ reinterpret_cast<__nv_bfloat162*>(h)[0] = __hsub2(reinterpret_cast<__nv_bfloat162*>(h)[0], reinterpret_cast<const __nv_bfloat162&>(BF16_TOP_MAGIC_NUM));
120
+ reinterpret_cast<__nv_bfloat162*>(h)[1] = __hsub2(reinterpret_cast<__nv_bfloat162*>(h)[1], reinterpret_cast<const __nv_bfloat162&>(BF16_TOP_MAGIC_NUM));
121
+ reinterpret_cast<__nv_bfloat162*>(h)[2] = __hsub2(reinterpret_cast<__nv_bfloat162*>(h)[2], reinterpret_cast<const __nv_bfloat162&>(BF16_TOP_MAGIC_NUM));
122
+ reinterpret_cast<__nv_bfloat162*>(h)[3] = __hsub2(reinterpret_cast<__nv_bfloat162*>(h)[3], reinterpret_cast<const __nv_bfloat162&>(BF16_TOP_MAGIC_NUM));
123
+ }
llm-awq/awq/kernels/csrc/quantization_new/dispatch_utils.cuh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+ #include <torch/extension.h>
3
+ #include <cstdint>
4
+ #include <sstream>
5
+ #include <stdexcept>
6
+
7
+ #define DISPATCH_PYTORCH_DTYPE_TO_CTYPE_FP16(pytorch_dtype, c_type, ...) \
8
+ if (pytorch_dtype == at::ScalarType::Half) { \
9
+ using c_type = half; \
10
+ __VA_ARGS__ \
11
+ } else if (pytorch_dtype == at::ScalarType::BFloat16) { \
12
+ using c_type = nv_bfloat16; \
13
+ __VA_ARGS__ \
14
+ } else { \
15
+ std::ostringstream oss; \
16
+ oss << __PRETTY_FUNCTION__ << " failed to dispatch data type " << pytorch_dtype; \
17
+ TORCH_CHECK(false, oss.str()); \
18
+ }
llm-awq/awq/kernels/csrc/quantization_new/gemm/gemm_cuda.cu ADDED
@@ -0,0 +1,1236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <cuda_fp16.h>
2
+ #include "semaphore.h"
3
+ #include "gemm_cuda.h"
4
+ #include "../dequantize.cuh"
5
+ #include "../dispatch_utils.cuh"
6
+ #include <torch/extension.h>
7
+ #include <cuda_pipeline_primitives.h>
8
+
9
+ #define kInterleave 4
10
+ #define OP_M 16
11
+ #define OP_N 8
12
+ #define OP_K 16
13
+ #define INTRIN_M 16
14
+ #define INTRIN_N 16
15
+ #define INTRIN_K 16
16
+ #define WARP_SIZE 32
17
+ #define SMEM_PAD_A 0
18
+ #define SMEM_PAD_B 0
19
+ #define PACK_SIZE 8
20
+ #if (__CUDACC_VER_MAJOR__ >= 11) && (__CUDACC_VER_MINOR__ >= 4)
21
+ #define L2_CACHEHINT(size) ".L2::" #size "B"
22
+ #else
23
+ #define L2_CACHEHINT(size)
24
+ #endif
25
+
26
+ #define KERNEL_LAUNCH_CODE \
27
+ int num_mn_tiles = (num_in_feats + CTA_M - 1) / CTA_M * (num_out_channels + CTA_N - 1) / CTA_N; \
28
+ torch::Tensor _semaphores = torch::empty({num_mn_tiles}, options_int); \
29
+ auto semaphores = reinterpret_cast<int *>(_semaphores.data_ptr<int>()); \
30
+ constexpr int NUM_WARPS = (CTA_M / WARP_M) * (CTA_N / WARP_N) * (CTA_K / WARP_K); \
31
+ constexpr int SCALES_SMEM_SIZE = (G >= CTA_K) ? (CTA_N / (G / CTA_K) * STAGES * 2) : (CTA_N * (CTA_K / G) * STAGES * 2); \
32
+ constexpr int kSmemByteSize = (CTA_M * (CTA_K + SMEM_PAD_A) + CTA_N * (CTA_K + SMEM_PAD_B) / kInterleave + SCALES_SMEM_SIZE) * STAGES * sizeof(ctype); \
33
+ if (kSmemByteSize >= 99 * 1024) \
34
+ { \
35
+ printf("This kernel requires %d Bytes of shared memory, which exceeds device limit.\n", kSmemByteSize); \
36
+ return _out_feats; \
37
+ } \
38
+ int j_factors1 = num_out_channels / CTA_N / 1; \
39
+ dim3 num_blocks((num_out_feats + CTA_M - 1) / CTA_M * j_factors1 * SPLITK); \
40
+ dim3 threads_per_block(WARP_SIZE, NUM_WARPS); \
41
+ auto kernel_func = gemm_w4a16_T1<CTA_M, CTA_N, CTA_K, WARP_M, WARP_N, WARP_K, STAGES, G, SPLITK, ctype>; \
42
+ cudaFuncSetAttribute(kernel_func, cudaFuncAttributeMaxDynamicSharedMemorySize, kSmemByteSize); \
43
+ kernel_func<<<num_blocks, threads_per_block, kSmemByteSize>>>( \
44
+ in_feats, kernel, scales, zeros, out_feats, semaphores, num_in_feats, num_out_channels, num_in_channels);
45
+
46
+ template <int N>
47
+ __inline__ __host__ __device__ int get_log_tile(int n)
48
+ {
49
+ if (N >= 8 && n >= 6)
50
+ return 3;
51
+ else if (N >= 4 && n >= 3)
52
+ return 2;
53
+ else if (N >= 2 && n >= 2)
54
+ return 1;
55
+ else
56
+ return 0;
57
+ }
58
+
59
+ __inline__ __device__ uint2 get_block_idx_mapping(int blockIdx_x, int blockIdx_y, int log_tile)
60
+ {
61
+ return make_uint2((blockIdx_x >> log_tile), (blockIdx_y << log_tile) + ((blockIdx_x) & ((1 << (log_tile)) - 1)));
62
+ }
63
+
64
+ template <int SLICES, int NUM_WARPS_MN>
65
+ __device__ void sync_slice(int slice_id)
66
+ {
67
+ if constexpr (SLICES == 1)
68
+ {
69
+ __syncthreads();
70
+ }
71
+ else
72
+ {
73
+ constexpr int SLICE_GROUP = (SLICES + 7) / 8;
74
+ constexpr uint32_t num_threads = NUM_WARPS_MN * WARP_SIZE;
75
+ const uint32_t barrier_id = slice_id / SLICE_GROUP + 1;
76
+ asm volatile("bar.sync %0, %1;" : : "r"(barrier_id), "n"(num_threads));
77
+ }
78
+ }
79
+
80
+ __inline__ __device__ uint32_t cast_smem_ptr_to_uint(void const *const ptr)
81
+ {
82
+ uint32_t smem_int_ptr;
83
+
84
+ asm("{.reg .u64 smem_ptr; cvta.to.shared.u64 smem_ptr, %1; cvt.u32.u64 %0, smem_ptr; }\n"
85
+ : "=r"(smem_int_ptr)
86
+ : "l"(ptr));
87
+
88
+ return smem_int_ptr;
89
+ }
90
+
91
+ template <typename T>
92
+ __inline__ __device__ void ldmatrix_m8n8_x4_b16(T *shared_warp, int ax0_0, uint32_t addr)
93
+ {
94
+ __asm__ __volatile__(
95
+ "ldmatrix.sync.aligned.m8n8.x4.shared.b16"
96
+ "{%0, %1, %2, %3}, [%4];"
97
+ : "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[0]), "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[1]), "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[2]), "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[3])
98
+ : "r"(addr));
99
+ }
100
+
101
+ template <typename T>
102
+ __inline__ __device__ void ldmatrix_m8n8_x4_trans_b16(T *shared_warp, int ax0_0, uint32_t addr)
103
+ {
104
+ __asm__ __volatile__(
105
+ "ldmatrix.sync.aligned.m8n8.x4.trans.shared.b16"
106
+ "{%0, %1, %2, %3}, [%4];"
107
+ : "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[0]), "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[1]), "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[2]), "=r"(((unsigned *)(shared_warp + (ax0_0 * 8)))[3])
108
+ : "r"(addr));
109
+ }
110
+
111
+ __inline__ __device__ void cp_async_cg_A(uint32_t smem_int_ptr, const uint4 *__restrict__ src, bool mask)
112
+ {
113
+ const int cp_size = 16;
114
+ asm volatile("{"
115
+ " .reg .pred p;"
116
+ " setp.ne.b32 p, %0, 0;"
117
+ " @p cp.async.cg.shared.global" L2_CACHEHINT(128) " [%1], [%2], %3;"
118
+ "}" ::"r"((int)mask),
119
+ "r"(smem_int_ptr),
120
+ "l"(src),
121
+ "n"(cp_size));
122
+ }
123
+
124
+ __device__ __inline__ void mma_m16n8k16_f16f16f16(half *C_warp, half *A_shared_warp, half *B_shared_warp)
125
+ {
126
+ __asm__ __volatile__(
127
+ "mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16"
128
+ "{%0, %1}, {%2, %3, %4, %5}, {%6, %7}, {%8, %9};"
129
+ : "=r"(((unsigned *)C_warp)[0]), "=r"(((unsigned *)C_warp)[1])
130
+ : "r"(((unsigned *)A_shared_warp)[0]), "r"(((unsigned *)A_shared_warp)[1]), "r"(((unsigned *)A_shared_warp)[2]), "r"(((unsigned *)A_shared_warp)[3]), "r"(((unsigned *)B_shared_warp)[0]), "r"(((unsigned *)B_shared_warp)[1]), "r"(((unsigned *)C_warp)[0]), "r"(((unsigned *)C_warp)[1]));
131
+ }
132
+
133
+ __device__ __inline__ void mma_m16n8k16_bf16bf16f32(float *C_warp, nv_bfloat16 *A_shared_warp, nv_bfloat16 *B_shared_warp)
134
+ {
135
+
136
+ __asm__ __volatile__(
137
+ "mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32"
138
+ "{%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%10, %11, %12, %13};"
139
+ : "=f"(C_warp[0]), "=f"(C_warp[1]), "=f"(C_warp[2]), "=f"(C_warp[3])
140
+ : "r"(((unsigned *)A_shared_warp)[0]), "r"(((unsigned *)A_shared_warp)[1]), "r"(((unsigned *)A_shared_warp)[2]), "r"(((unsigned *)A_shared_warp)[3]), "r"(((unsigned *)B_shared_warp)[0]), "r"(((unsigned *)B_shared_warp)[1]), "f"(C_warp[0]), "f"(C_warp[1]), "f"(C_warp[2]), "f"(C_warp[3]));
141
+ }
142
+
143
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int SHARED_K_ITERS, int STAGES, typename T>
144
+ __device__ __inline__ void global_to_share_one_stage_A(T *src, T *dst, int global_nrows, int global_ncols, int cta_offset_m, int cta_offset_n, int cta_offset_k, int global_iter_k, int shared_iter_k, bool mask)
145
+ {
146
+ constexpr int threads_needed = (CTA_M * CTA_K) / PACK_SIZE / SHARED_K_ITERS;
147
+ constexpr int threads_used = threads_needed < CTA_SIZE ? threads_needed : CTA_SIZE;
148
+ constexpr int total_global_iters = (CTA_M * CTA_K) / PACK_SIZE / threads_used;
149
+ constexpr int partial_global_iters = (total_global_iters + SHARED_K_ITERS - 1) / SHARED_K_ITERS;
150
+ constexpr int cta_step_m_or_n = (threads_used * PACK_SIZE) / CTA_K;
151
+ constexpr int warp_step_m_or_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
152
+ constexpr int threads_per_row = CTA_K / PACK_SIZE;
153
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_A;
154
+ bool local_mask = mask & (threadIdx.y * WARP_SIZE + threadIdx.x < threads_used);
155
+ int ld_col = (threadIdx.x % threads_per_row);
156
+ #pragma unroll
157
+ for (int _global_iter = 0; _global_iter < partial_global_iters; ++_global_iter)
158
+ {
159
+ int global_iter = shared_iter_k * partial_global_iters + _global_iter;
160
+ int ld_row = global_iter * cta_step_m_or_n + threadIdx.y * warp_step_m_or_n + (threadIdx.x / threads_per_row);
161
+ int ld_col_swizzled = (ld_col ^ (ld_row) & 7) * PACK_SIZE;
162
+ void *dst_ptr = (void *)(dst + ld_row * kSmemCol + ld_col_swizzled);
163
+ uint4 *src_ptr = (uint4 *)(src + (ld_row + cta_offset_m) * global_ncols + ld_col * PACK_SIZE + global_iter_k * CTA_K + cta_offset_k); // cta_offset_m * global_ncols + global_iter * cta_step_m_or_n * global_ncols + threadIdx.y * warp_step_m_or_n * global_ncols + (threadIdx.x / threads_per_row) * global_ncols + global_iter_k * CTA_K + (threadIdx.x % threads_per_row) * PACK_SIZE);
164
+ if constexpr (STAGES > 1)
165
+ {
166
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
167
+ cp_async_cg_A(addr, src_ptr, local_mask & (ld_row + cta_offset_m < global_nrows));
168
+ }
169
+ else
170
+ {
171
+ if (local_mask & (ld_row + cta_offset_m < global_nrows))
172
+ *(uint4 *)dst_ptr = *src_ptr;
173
+ }
174
+ }
175
+ }
176
+
177
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int SHARED_K_ITERS, int STAGES, typename T>
178
+ __device__ __inline__ void global_to_share_one_stage_B(T *src, T *dst, int global_ncols, int cta_offset_m, int cta_offset_n, int cta_offset_k, int global_iter_k, int shared_iter_k, bool mask)
179
+ {
180
+ constexpr int threads_needed = (CTA_N / kInterleave * CTA_K) / PACK_SIZE / SHARED_K_ITERS;
181
+ constexpr int threads_used = threads_needed < CTA_SIZE ? threads_needed : CTA_SIZE;
182
+ constexpr int total_global_iters = (CTA_N / kInterleave * CTA_K) / PACK_SIZE / threads_used;
183
+ constexpr int partial_global_iters = (total_global_iters + SHARED_K_ITERS - 1) / SHARED_K_ITERS;
184
+ constexpr int cta_step_m_or_n = (threads_used * PACK_SIZE) / CTA_K;
185
+ constexpr int warp_step_m_or_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
186
+ constexpr int threads_per_row = CTA_K / PACK_SIZE;
187
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_B;
188
+ bool local_mask = mask & (threadIdx.y * WARP_SIZE + threadIdx.x < threads_used);
189
+ #pragma unroll
190
+ for (int _global_iter = 0; _global_iter < partial_global_iters; ++_global_iter)
191
+ {
192
+ int global_iter = shared_iter_k * partial_global_iters + _global_iter;
193
+
194
+ int ld_row = global_iter * cta_step_m_or_n + threadIdx.y * warp_step_m_or_n + (threadIdx.x / threads_per_row);
195
+ int ld_col = (threadIdx.x % threads_per_row);
196
+ int ld_col_swizzled = ld_col ^ (ld_row % 2) & 7;
197
+ void *dst_ptr = (void *)(dst + (ld_row * kSmemCol + ld_col_swizzled * PACK_SIZE));
198
+ uint4 *src_ptr = (uint4 *)(src + global_iter_k * CTA_K + cta_offset_n / kInterleave * global_ncols + ld_row * global_ncols + ld_col * PACK_SIZE + cta_offset_k);
199
+ if constexpr (STAGES > 1)
200
+ {
201
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
202
+ cp_async_cg_A(addr, src_ptr, local_mask);
203
+ }
204
+ else
205
+ {
206
+ if (local_mask)
207
+ *(uint4 *)dst_ptr = *src_ptr;
208
+ }
209
+ }
210
+ }
211
+
212
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int STAGES, int G, typename T>
213
+ __device__ __inline__ void global_to_share_one_stage_scales(T *src, T *dst, T *src_z, T *dst_z, int global_ncols, int cta_offset_m, int cta_offset_n, int cta_offset_k, int global_iter_k, int shared_iter_k, bool mask)
214
+ {
215
+ constexpr int LD_AMOUNT = (G >= CTA_K) ? CTA_N : CTA_N * CTA_K / G;
216
+ constexpr int threads_needed = LD_AMOUNT / PACK_SIZE / 1;
217
+ constexpr int threads_used = threads_needed < CTA_SIZE ? threads_needed : CTA_SIZE;
218
+ constexpr int total_global_iters = LD_AMOUNT / PACK_SIZE / threads_used;
219
+ constexpr int threads_per_row = CTA_N / PACK_SIZE;
220
+ constexpr int kSmemCol = CTA_N;
221
+ bool local_mask = mask & (threadIdx.y * WARP_SIZE + threadIdx.x < threads_used);
222
+ int g_idx = (cta_offset_k + global_iter_k * CTA_K) / G;
223
+
224
+ void *dst_ptr = (void *)(dst + (threadIdx.x / threads_per_row) * kSmemCol + (threadIdx.x % threads_per_row) * PACK_SIZE);
225
+ uint4 *src_ptr = (uint4 *)(src + g_idx * global_ncols + cta_offset_n + (threadIdx.x / threads_per_row) * global_ncols + (threadIdx.x % threads_per_row) * PACK_SIZE);
226
+ void *dst_ptr_z = (void *)(dst_z + (threadIdx.x / threads_per_row) * kSmemCol + (threadIdx.x % threads_per_row) * PACK_SIZE);
227
+ uint4 *src_ptr_z = (uint4 *)(src_z + g_idx * global_ncols + cta_offset_n + (threadIdx.x / threads_per_row) * global_ncols + (threadIdx.x % threads_per_row) * PACK_SIZE);
228
+ if (STAGES > 1)
229
+ {
230
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
231
+ cp_async_cg_A(addr, src_ptr, local_mask);
232
+ uint32_t addr_z = cast_smem_ptr_to_uint(dst_ptr_z);
233
+ cp_async_cg_A(addr_z, src_ptr_z, local_mask);
234
+ }
235
+ else
236
+ {
237
+ if (local_mask)
238
+ {
239
+ *(uint4 *)dst_ptr = *src_ptr;
240
+ *(uint4 *)dst_ptr_z = *src_ptr_z;
241
+ }
242
+ }
243
+ }
244
+
245
+ template <int CTA_M, int CTA_N, int CTA_K, int STAGES, int shared_iters, typename T>
246
+ __device__ __inline__ void share_to_reg_one_stage_A(T *src, T *dst, int warp_offset_m, int warp_offset_n, int warp_offset_k, int k_0_1)
247
+ {
248
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_A;
249
+
250
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
251
+ {
252
+
253
+ int ld_row = warp_offset_m + shared_iter * OP_M + (threadIdx.x % 16);
254
+ int ld_col = k_0_1 * 16 + (threadIdx.x / 16) * 8 + warp_offset_k;
255
+ int ld_col_swizzled = ((ld_col / PACK_SIZE) ^ (ld_row) & 7) * PACK_SIZE;
256
+ void *addr_ptr = (void *)(src + ld_row * kSmemCol + ld_col_swizzled);
257
+
258
+ uint32_t addr = cast_smem_ptr_to_uint(addr_ptr);
259
+ ldmatrix_m8n8_x4_b16(dst, shared_iter, addr);
260
+ }
261
+ }
262
+
263
+ template <int CTA_M, int CTA_N, int CTA_K, int STAGES, bool ldmatrix, int shared_iters, int G, typename T>
264
+ __device__ __inline__ void share_to_reg_one_stage_B(T *src, T *src_scales, T *src_zeros, T *dst, T *dst_fp16, int warp_offset_m, int warp_offset_n, int warp_offset_k, int k_0_1)
265
+ {
266
+ using T2 = typename std::conditional<std::is_same<T, half>::value, half2, nv_bfloat162>::type;
267
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_B;
268
+ int r0 = ((threadIdx.x / 8 / 2) * 8 + threadIdx.x % 8);
269
+ int c0 = ((threadIdx.x / 8) % 2) * 8;
270
+ int r = r0 / 4;
271
+ int c = (r0 % 4) * 16 + c0;
272
+ int c_swizzled = ((c / PACK_SIZE) ^ (r % 2) & 7) * PACK_SIZE;
273
+
274
+ if constexpr (ldmatrix)
275
+ {
276
+ #pragma unroll
277
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
278
+ {
279
+ void *addr_ptr = (void *)(src + warp_offset_n / kInterleave * kSmemCol + shared_iter * 16 / kInterleave * kSmemCol + k_0_1 * 16 + r * kSmemCol + c_swizzled + warp_offset_k);
280
+ uint32_t addr = cast_smem_ptr_to_uint(addr_ptr);
281
+ ldmatrix_m8n8_x4_b16(dst, shared_iter, addr);
282
+ }
283
+ }
284
+
285
+ #pragma unroll
286
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
287
+ {
288
+ T scale = src_scales[(warp_offset_k / G) * CTA_N + warp_offset_n + 16 * shared_iter + 8 * (k_0_1 % 2) + threadIdx.x / 4];
289
+ T zero = src_zeros[(warp_offset_k / G) * CTA_N + warp_offset_n + 16 * shared_iter + 8 * (k_0_1 % 2) + threadIdx.x / 4];
290
+ T2 scale2, zero2;
291
+ if constexpr (std::is_same<T, half>::value)
292
+ {
293
+ scale2 = __half2half2(scale);
294
+ zero2 = __half2half2(zero);
295
+ }
296
+ else
297
+ {
298
+ scale2 = __bfloat162bfloat162(scale);
299
+ zero2 = __bfloat162bfloat162(zero);
300
+ }
301
+ T2 loaded[4];
302
+ dequantize_s4_to_fp16x2<T>(*reinterpret_cast<half2 *>(dst + (k_0_1 % 2) * 4 + (k_0_1 / 2 * 2) + shared_iter * 8), reinterpret_cast<uint4 *>(loaded));
303
+ #pragma unroll
304
+ for (int i = 0; i < 4; i++)
305
+ {
306
+ loaded[i] = __hfma2(loaded[i], scale2, zero2);
307
+ }
308
+ *reinterpret_cast<uint4 *>(dst_fp16 + shared_iter * 16 + 8 * (k_0_1 % 2)) = *reinterpret_cast<uint4 *>(loaded);
309
+ }
310
+ }
311
+
312
+ template <int CTA_M, int CTA_N, int CTA_K, int WARP_M, int WARP_N, int WARP_K, int STAGES, int G, int SPLITK, typename T>
313
+ __global__ void gemm_w4a16_T1(T *__restrict__ A, T *__restrict__ B, T *__restrict__ scales, T *__restrict__ zeros, T *__restrict__ C, int *__restrict__ semaphores, int M, int N, int K)
314
+ {
315
+ using DTypeAccum = typename std::conditional<std::is_same<T, half>::value, half, float>::type;
316
+ constexpr int NUM_WARPS_MN = CTA_M / WARP_M * CTA_N / WARP_N;
317
+ constexpr int NUM_WARPS = NUM_WARPS_MN * CTA_K / WARP_K;
318
+ constexpr int CTA_SIZE = NUM_WARPS * WARP_SIZE;
319
+ constexpr int CTA_SIZE_MN = NUM_WARPS_MN * WARP_SIZE;
320
+ constexpr int SLICES = CTA_K / WARP_K;
321
+ int num_blocks_n = (N + CTA_N - 1) / CTA_N;
322
+ int num_blocks_m = (M + CTA_M - 1) / CTA_M;
323
+ int blockIdx_x = 0;
324
+ int blockIdx_y = blockIdx.x % (num_blocks_m * num_blocks_n);
325
+ int blockIdx_z = blockIdx.x / (num_blocks_m * num_blocks_n);
326
+ const int log_tile = get_log_tile<1>((N + CTA_N - 1) / CTA_N);
327
+ int blockIdx_m = blockIdx_y / (num_blocks_n >> log_tile);
328
+ int blockIdx_n = blockIdx_y % (num_blocks_n >> log_tile);
329
+ const uint2 block_idx_mapping = get_block_idx_mapping(blockIdx_m, blockIdx_n, log_tile);
330
+ blockIdx_m = block_idx_mapping.x;
331
+ blockIdx_n = block_idx_mapping.y;
332
+
333
+ DTypeAccum C_warp[CTA_M * CTA_N / CTA_SIZE_MN];
334
+ constexpr int kSmemPadKA = CTA_K + SMEM_PAD_A;
335
+ constexpr int kSmemPadKB = CTA_K + SMEM_PAD_B;
336
+ constexpr int kSmemSizeAPerStage = CTA_M * kSmemPadKA;
337
+ constexpr int kSmemSizeBPerStage = CTA_N / kInterleave * kSmemPadKB;
338
+ constexpr int kSmemSizeA = kSmemSizeAPerStage * STAGES;
339
+ constexpr int kSmemSizeB = kSmemSizeBPerStage * STAGES;
340
+ constexpr int scales_load_interval = G >= CTA_K ? G / CTA_K : 1;
341
+ constexpr int scales_per_load = G < CTA_K ? CTA_K / G : 1;
342
+ constexpr int kSmemSizeScales = CTA_N * STAGES / scales_load_interval * scales_per_load;
343
+ constexpr int kSmemSizeZeros = CTA_N * STAGES / scales_load_interval * scales_per_load;
344
+ extern __shared__ half mem_shared[];
345
+ T *A_shared = (T*)mem_shared;
346
+ T *B_shared = (T*)mem_shared + kSmemSizeA;
347
+ T *scales_shared = (T*)mem_shared + kSmemSizeA + kSmemSizeB;
348
+ T *zeros_shared = (T*)mem_shared + kSmemSizeA + kSmemSizeB + kSmemSizeScales;
349
+ T *C_shared = (T*)(mem_shared);
350
+ T A_shared_warp_[2][WARP_M * INTRIN_K /
351
+ WARP_SIZE];
352
+ T B_shared_warp_[2][WARP_N * 32 /
353
+ WARP_SIZE];
354
+ T B_shared_warp_tmp_[2][WARP_N * 16 /
355
+ WARP_SIZE];
356
+ int cta_offset_m = blockIdx_m * CTA_M;
357
+ int cta_offset_n = blockIdx_n * CTA_N;
358
+ int cta_offset_k = blockIdx_z * (K / SPLITK);
359
+ int warp_mn = threadIdx.y % NUM_WARPS_MN;
360
+ int slice_id = threadIdx.y / NUM_WARPS_MN;
361
+ int warp_offset_n = (warp_mn % (CTA_N / WARP_N)) * WARP_N;
362
+ int warp_offset_m = (warp_mn / (CTA_N / WARP_N)) * WARP_M;
363
+ int warp_offset_k = slice_id * WARP_K;
364
+
365
+ for (int i = 0; i < CTA_M * CTA_N / CTA_SIZE_MN; i++)
366
+ C_warp[i] = 0.0;
367
+
368
+ int gemm_iters = (K + CTA_K - 1) / CTA_K / SPLITK;
369
+ int k_0_0_ld = 0;
370
+ int k_0_0 = 0;
371
+ constexpr int prologue_stages = STAGES == 1 ? 1 : STAGES - 1;
372
+ #pragma unroll
373
+ for (k_0_0_ld = 0; k_0_0_ld < prologue_stages; ++k_0_0_ld)
374
+ {
375
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(A, A_shared + k_0_0_ld * kSmemSizeAPerStage, M, K, cta_offset_m, cta_offset_n, cta_offset_k, k_0_0_ld, 0, true);
376
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(B, B_shared + k_0_0_ld * kSmemSizeBPerStage, K, cta_offset_m, cta_offset_n, cta_offset_k, k_0_0_ld, 0, true);
377
+ global_to_share_one_stage_scales<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES, G>(
378
+ scales, scales_shared + (k_0_0_ld / scales_load_interval * scales_per_load) * CTA_N,
379
+ zeros, zeros_shared + (k_0_0_ld / scales_load_interval * scales_per_load) * CTA_N,
380
+ N, cta_offset_m, cta_offset_n, cta_offset_k,
381
+ k_0_0_ld, 0, k_0_0_ld < gemm_iters && k_0_0_ld % scales_load_interval == 0);
382
+ if constexpr (STAGES > 1)
383
+ __pipeline_commit();
384
+ }
385
+ if constexpr (STAGES > 1)
386
+ __pipeline_wait_prior(STAGES - 2);
387
+ __syncthreads();
388
+
389
+ share_to_reg_one_stage_A<CTA_M, CTA_N, CTA_K, STAGES, WARP_M / INTRIN_M>(A_shared, A_shared_warp_[0], warp_offset_m, warp_offset_n, warp_offset_k, 0);
390
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, STAGES, true, WARP_N / INTRIN_N, G>(B_shared, scales_shared, zeros_shared, B_shared_warp_tmp_[0], B_shared_warp_[0], warp_offset_m, warp_offset_n, warp_offset_k, 0);
391
+ constexpr int SHARED_K_ITERS = WARP_K / INTRIN_K;
392
+
393
+ for (; k_0_0 < gemm_iters; ++k_0_0, ++k_0_0_ld)
394
+ {
395
+ int ld_stage = k_0_0_ld % STAGES;
396
+ int compute_stage = k_0_0 % STAGES;
397
+ T *A_shared_this_compute_stage;
398
+ T *B_shared_this_compute_stage;
399
+ T *scales_shared_this_compute_stage;
400
+ T *zeros_shared_this_compute_stage;
401
+
402
+ #pragma unroll
403
+ for (int iter_k = 0; iter_k < SHARED_K_ITERS; ++iter_k)
404
+ {
405
+ A_shared_this_compute_stage = A_shared + compute_stage * kSmemSizeAPerStage;
406
+ B_shared_this_compute_stage = B_shared + compute_stage * kSmemSizeBPerStage;
407
+ scales_shared_this_compute_stage = scales_shared + (compute_stage / scales_load_interval * scales_per_load) * CTA_N;
408
+ zeros_shared_this_compute_stage = zeros_shared + (compute_stage / scales_load_interval * scales_per_load) * CTA_N;
409
+ share_to_reg_one_stage_A<CTA_M, CTA_N, CTA_K, STAGES, WARP_M / INTRIN_M>(A_shared_this_compute_stage, A_shared_warp_[(iter_k + 1) % 2], warp_offset_m, warp_offset_n, warp_offset_k, (iter_k + 1) % SHARED_K_ITERS);
410
+ if ((iter_k + 1) % kInterleave == 0)
411
+ {
412
+ if (compute_stage % 2 == 1)
413
+ {
414
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, STAGES, true, WARP_N / INTRIN_N, G>(
415
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
416
+ B_shared_warp_tmp_[1], B_shared_warp_[((iter_k + 1) / 2) % 2],
417
+ warp_offset_m, warp_offset_n, warp_offset_k, (iter_k + 1) % SHARED_K_ITERS);
418
+ }
419
+ else
420
+ {
421
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, STAGES, true, WARP_N / INTRIN_N, G>(
422
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
423
+ B_shared_warp_tmp_[0], B_shared_warp_[((iter_k + 1) / 2) % 2],
424
+ warp_offset_m, warp_offset_n, warp_offset_k, (iter_k + 1) % SHARED_K_ITERS);
425
+ }
426
+ }
427
+ else
428
+ {
429
+ if (compute_stage % 2 == 1)
430
+ {
431
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, STAGES, false, WARP_N / INTRIN_N, G>(
432
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
433
+ B_shared_warp_tmp_[1], B_shared_warp_[((iter_k + 1) / 2) % 2],
434
+ warp_offset_m, warp_offset_n, warp_offset_k, (iter_k + 1) % SHARED_K_ITERS);
435
+ }
436
+ else
437
+ {
438
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, STAGES, false, WARP_N / INTRIN_N, G>(
439
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
440
+ B_shared_warp_tmp_[0], B_shared_warp_[((iter_k + 1) / 2) % 2],
441
+ warp_offset_m, warp_offset_n, warp_offset_k, (iter_k + 1) % SHARED_K_ITERS);
442
+ }
443
+ }
444
+ T *A_shared_warp = A_shared_warp_[iter_k % 2];
445
+ T *B_shared_warp = B_shared_warp_[(iter_k / 2) % 2];
446
+
447
+ for (int i_0_3 = 0; i_0_3 < WARP_M / INTRIN_M; ++i_0_3)
448
+ {
449
+ for (int j_0_4 = 0; j_0_4 < WARP_N / INTRIN_N; ++j_0_4)
450
+ {
451
+ if constexpr (std::is_same<T, half>::value)
452
+ {
453
+ mma_m16n8k16_f16f16f16(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4);
454
+ mma_m16n8k16_f16f16f16(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8 + 4, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4 + 8);
455
+ }
456
+ else
457
+ {
458
+ mma_m16n8k16_bf16bf16f32(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4);
459
+ mma_m16n8k16_bf16bf16f32(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8 + 4, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4 + 8);
460
+ }
461
+ }
462
+ }
463
+
464
+ if (iter_k < WARP_K / INTRIN_K - 1)
465
+ {
466
+ if constexpr (STAGES == 1)
467
+ __syncthreads();
468
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(A, A_shared + ld_stage * kSmemSizeAPerStage, M, K, cta_offset_m, cta_offset_n, cta_offset_k, k_0_0_ld, iter_k, k_0_0_ld < gemm_iters);
469
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(B, B_shared + ld_stage * kSmemSizeBPerStage, K, cta_offset_m, cta_offset_n, cta_offset_k, k_0_0_ld, iter_k, k_0_0_ld < gemm_iters);
470
+ }
471
+
472
+ if (iter_k == WARP_K / INTRIN_K - 2)
473
+ {
474
+ if constexpr (STAGES == 1 && WARP_K / INTRIN_K > 2)
475
+ {
476
+ __syncthreads();
477
+ }
478
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(A, A_shared + ld_stage * kSmemSizeAPerStage, M, K, cta_offset_m, cta_offset_n, cta_offset_k, k_0_0_ld, iter_k + 1, k_0_0_ld < gemm_iters);
479
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(B, B_shared + ld_stage * kSmemSizeBPerStage, K, cta_offset_m, cta_offset_n, cta_offset_k, k_0_0_ld, iter_k + 1, k_0_0_ld < gemm_iters);
480
+ global_to_share_one_stage_scales<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES, G>(
481
+ scales, scales_shared + (ld_stage / scales_load_interval * scales_per_load) * CTA_N,
482
+ zeros, zeros_shared + (ld_stage / scales_load_interval * scales_per_load) * CTA_N,
483
+ N, cta_offset_m, cta_offset_n, cta_offset_k,
484
+ k_0_0_ld, iter_k, k_0_0_ld < gemm_iters && k_0_0_ld % scales_load_interval == 0);
485
+ if constexpr (STAGES > 1)
486
+ {
487
+ __pipeline_commit();
488
+ __pipeline_wait_prior(STAGES - 2);
489
+ }
490
+ compute_stage = (k_0_0 + 1) % STAGES;
491
+ __syncthreads();
492
+ }
493
+ }
494
+ }
495
+ __pipeline_commit();
496
+ __pipeline_wait_prior(0);
497
+ __syncthreads();
498
+
499
+ if constexpr (std::is_same<T, half>::value)
500
+ {
501
+ if constexpr (SLICES > 1)
502
+ {
503
+ #pragma unroll
504
+ for (int z = 0; z < SLICES; ++z)
505
+ {
506
+ if (slice_id == z)
507
+ {
508
+ #pragma unroll
509
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
510
+ {
511
+ #pragma unroll
512
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
513
+ {
514
+ #pragma unroll
515
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
516
+ {
517
+ if (z > 0)
518
+ {
519
+ C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] += C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
520
+ }
521
+ C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2] = C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id];
522
+ };
523
+ }
524
+ }
525
+ }
526
+ __syncthreads();
527
+ }
528
+ if (slice_id == 0)
529
+ {
530
+ #pragma unroll
531
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
532
+ {
533
+ #pragma unroll
534
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
535
+ {
536
+ #pragma unroll
537
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
538
+ {
539
+ C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] = C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
540
+ };
541
+ }
542
+ }
543
+ }
544
+ }
545
+
546
+ if (slice_id == 0)
547
+ {
548
+ Semaphore semaphore(semaphores + blockIdx_y, threadIdx.x);
549
+
550
+ if constexpr (SPLITK > 1)
551
+ {
552
+ semaphore.fetch();
553
+ }
554
+
555
+ if (blockIdx_z != 0)
556
+ {
557
+ semaphore.wait(blockIdx_z);
558
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
559
+ {
560
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
561
+ {
562
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
563
+ {
564
+ int write_row = cta_offset_m + warp_offset_m + ax0_0_1 * OP_M + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4));
565
+
566
+ if (write_row < M)
567
+ {
568
+ half2 *existing_psum_ptr = reinterpret_cast<half2 *>(
569
+ C + write_row * N +
570
+ cta_offset_n + warp_offset_n + ax1_0_1 * 16 +
571
+ (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2);
572
+
573
+ *existing_psum_ptr = __hadd2(*existing_psum_ptr,
574
+ *reinterpret_cast<half2 *>(C_warp + ax0_0_1 * WARP_N / INTRIN_N * 8 +
575
+ ax1_0_1 * 8 + local_id));
576
+ }
577
+ };
578
+ }
579
+ }
580
+ }
581
+ else
582
+ {
583
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
584
+ {
585
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
586
+ {
587
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
588
+ {
589
+ int write_row = cta_offset_m + warp_offset_m + ax0_0_1 * OP_M + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4));
590
+ if (write_row < M)
591
+ {
592
+ *reinterpret_cast<half2 *>(
593
+ C + write_row * N +
594
+ cta_offset_n + warp_offset_n + ax1_0_1 * 16 +
595
+ (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2) =
596
+ *reinterpret_cast<half2 *>(C_warp + ax0_0_1 * WARP_N / INTRIN_N * 8 +
597
+ ax1_0_1 * 8 + local_id);
598
+ }
599
+ };
600
+ }
601
+ }
602
+ }
603
+
604
+ if constexpr (SPLITK > 1)
605
+ {
606
+
607
+ int lock = 0;
608
+ if (SPLITK == blockIdx_z + 1)
609
+ {
610
+
611
+ lock = 0;
612
+ }
613
+ else
614
+ {
615
+ lock = blockIdx_z + 1;
616
+ }
617
+ semaphore.release(lock);
618
+ }
619
+ }
620
+ }
621
+ else
622
+ {
623
+ // first convert fp32 to bf16
624
+ nv_bfloat16 C_warp16[CTA_M * CTA_N / CTA_SIZE_MN];
625
+ #pragma unroll
626
+ for (int i = 0; i < CTA_M * CTA_N / CTA_SIZE_MN / 2; ++i)
627
+ {
628
+ ((nv_bfloat162*)C_warp16)[i] = __float22bfloat162_rn(((float2*)C_warp)[i]);
629
+ }
630
+
631
+ // the following is the same as fp16. Maybe there is a neat way to implement this.
632
+ if constexpr (SLICES > 1)
633
+ {
634
+ #pragma unroll
635
+ for (int z = 0; z < SLICES; ++z)
636
+ {
637
+ if (slice_id == z)
638
+ {
639
+ #pragma unroll
640
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
641
+ {
642
+ #pragma unroll
643
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
644
+ {
645
+ #pragma unroll
646
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
647
+ {
648
+ if (z > 0)
649
+ {
650
+ C_warp16[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] += C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
651
+ }
652
+ C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2] = C_warp16[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id];
653
+ };
654
+ }
655
+ }
656
+ }
657
+ __syncthreads();
658
+ }
659
+ if (slice_id == 0)
660
+ {
661
+ #pragma unroll
662
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
663
+ {
664
+ #pragma unroll
665
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
666
+ {
667
+ #pragma unroll
668
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
669
+ {
670
+ C_warp16[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] = C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
671
+ };
672
+ }
673
+ }
674
+ }
675
+ }
676
+
677
+ if (slice_id == 0)
678
+ {
679
+ Semaphore semaphore(semaphores + blockIdx_y, threadIdx.x);
680
+
681
+ if constexpr (SPLITK > 1)
682
+ {
683
+ semaphore.fetch();
684
+ }
685
+
686
+ if (blockIdx_z != 0)
687
+ {
688
+ semaphore.wait(blockIdx_z);
689
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
690
+ {
691
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
692
+ {
693
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
694
+ {
695
+ int write_row = cta_offset_m + warp_offset_m + ax0_0_1 * OP_M + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4));
696
+
697
+ if (write_row < M)
698
+ {
699
+ nv_bfloat162 *existing_psum_ptr = reinterpret_cast<nv_bfloat162 *>(
700
+ C + write_row * N +
701
+ cta_offset_n + warp_offset_n + ax1_0_1 * 16 +
702
+ (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2);
703
+
704
+ *existing_psum_ptr = __hadd2(*existing_psum_ptr,
705
+ *reinterpret_cast<nv_bfloat162 *>(C_warp16 + ax0_0_1 * WARP_N / INTRIN_N * 8 +
706
+ ax1_0_1 * 8 + local_id));
707
+ }
708
+ };
709
+ }
710
+ }
711
+ }
712
+ else
713
+ {
714
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
715
+ {
716
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
717
+ {
718
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
719
+ {
720
+ int write_row = cta_offset_m + warp_offset_m + ax0_0_1 * OP_M + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4));
721
+ if (write_row < M)
722
+ {
723
+ *reinterpret_cast<nv_bfloat162 *>(
724
+ C + write_row * N +
725
+ cta_offset_n + warp_offset_n + ax1_0_1 * 16 +
726
+ (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2) =
727
+ *reinterpret_cast<nv_bfloat162 *>(C_warp16 + ax0_0_1 * WARP_N / INTRIN_N * 8 +
728
+ ax1_0_1 * 8 + local_id);
729
+ }
730
+ };
731
+ }
732
+ }
733
+ }
734
+
735
+ if constexpr (SPLITK > 1)
736
+ {
737
+
738
+ int lock = 0;
739
+ if (SPLITK == blockIdx_z + 1)
740
+ {
741
+
742
+ lock = 0;
743
+ }
744
+ else
745
+ {
746
+ lock = blockIdx_z + 1;
747
+ }
748
+ semaphore.release(lock);
749
+ }
750
+ }
751
+ }
752
+ }
753
+
754
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int SHARED_K_ITERS, int STAGES, typename T>
755
+ __device__ __inline__ void global_to_share_one_stage_A_T2(T *src, T *dst, int global_nrows, int global_ncols, int cta_offset_m, int cta_offset_n, int global_iter_k, int shared_iter_k, bool mask)
756
+ {
757
+ constexpr int threads_needed = (CTA_M * CTA_K) / PACK_SIZE / SHARED_K_ITERS;
758
+ constexpr int threads_used = threads_needed < CTA_SIZE ? threads_needed : CTA_SIZE;
759
+ constexpr int total_global_iters = (CTA_M * CTA_K) / PACK_SIZE / threads_used;
760
+ constexpr int partial_global_iters = (total_global_iters + SHARED_K_ITERS - 1) / SHARED_K_ITERS;
761
+ constexpr int cta_step_m_or_n = (threads_used * PACK_SIZE) / CTA_K;
762
+ constexpr int warp_step_m_or_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
763
+ constexpr int threads_per_row = CTA_K / PACK_SIZE;
764
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_A;
765
+ bool local_mask = mask & (threadIdx.y * WARP_SIZE + threadIdx.x < threads_used);
766
+ int ld_col = (threadIdx.x % threads_per_row);
767
+ #pragma unroll
768
+ for (int _global_iter = 0; _global_iter < partial_global_iters; ++_global_iter)
769
+ {
770
+ int global_iter = shared_iter_k * partial_global_iters + _global_iter;
771
+ int ld_row = global_iter * cta_step_m_or_n + threadIdx.y * warp_step_m_or_n + (threadIdx.x / threads_per_row);
772
+ int ld_col_swizzled = (ld_col ^ (ld_row) & 7) * PACK_SIZE;
773
+ void *dst_ptr = (void *)(dst + ld_row * kSmemCol + ld_col_swizzled);
774
+ uint4 *src_ptr = (uint4 *)(src + (ld_row + cta_offset_m) * global_ncols + ld_col * PACK_SIZE + global_iter_k * CTA_K); // cta_offset_m * global_ncols + global_iter * cta_step_m_or_n * global_ncols + threadIdx.y * warp_step_m_or_n * global_ncols + (threadIdx.x / threads_per_row) * global_ncols + global_iter_k * CTA_K + (threadIdx.x % threads_per_row) * PACK_SIZE);
775
+ if constexpr (STAGES > 1)
776
+ {
777
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
778
+ cp_async_cg_A(addr, src_ptr, local_mask & (ld_row + cta_offset_m < global_nrows));
779
+ }
780
+ else
781
+ {
782
+ if (local_mask & (ld_row + cta_offset_m < global_nrows))
783
+ *(uint4 *)dst_ptr = *src_ptr;
784
+ }
785
+ }
786
+ }
787
+
788
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int SHARED_K_ITERS, int STAGES, typename T>
789
+ __device__ __inline__ void global_to_share_one_stage_B_T2(T *src, T *dst, int global_ncols, int cta_offset_m, int cta_offset_n, int global_iter_k, int shared_iter_k, bool mask)
790
+ {
791
+ constexpr int threads_needed = (CTA_N / kInterleave * CTA_K) / PACK_SIZE / SHARED_K_ITERS;
792
+ constexpr int threads_used = threads_needed < CTA_SIZE ? threads_needed : CTA_SIZE;
793
+ constexpr int total_global_iters = (CTA_N / kInterleave * CTA_K) / PACK_SIZE / threads_used;
794
+ constexpr int partial_global_iters = (total_global_iters + SHARED_K_ITERS - 1) / SHARED_K_ITERS;
795
+ constexpr int cta_step_m_or_n = (threads_used * PACK_SIZE) / CTA_K;
796
+ constexpr int warp_step_m_or_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
797
+ constexpr int threads_per_row = CTA_K / PACK_SIZE;
798
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_B;
799
+ bool local_mask = mask & (threadIdx.y * WARP_SIZE + threadIdx.x < threads_used);
800
+ #pragma unroll
801
+ for (int _global_iter = 0; _global_iter < partial_global_iters; ++_global_iter)
802
+ {
803
+ int global_iter = shared_iter_k * partial_global_iters + _global_iter;
804
+
805
+ int ld_row = global_iter * cta_step_m_or_n + threadIdx.y * warp_step_m_or_n + (threadIdx.x / threads_per_row);
806
+ int ld_col = (threadIdx.x % threads_per_row);
807
+ int ld_col_swizzled = ld_col ^ (ld_row % 2) & 7;
808
+ void *dst_ptr = (void *)(dst + (ld_row * kSmemCol + ld_col_swizzled * PACK_SIZE));
809
+ uint4 *src_ptr = (uint4 *)(src + global_iter_k * CTA_K + cta_offset_n / kInterleave * global_ncols + ld_row * global_ncols + ld_col * PACK_SIZE);
810
+ if constexpr (STAGES > 1)
811
+ {
812
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
813
+ cp_async_cg_A(addr, src_ptr, local_mask);
814
+ }
815
+ else
816
+ {
817
+ if (local_mask)
818
+ *(uint4 *)dst_ptr = *src_ptr;
819
+ }
820
+ }
821
+ }
822
+
823
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int STAGES, int G, typename T>
824
+ __device__ __inline__ void global_to_share_one_stage_scales_T2(T *src, T *dst, T *src_z, T *dst_z, int global_ncols, int cta_offset_m, int cta_offset_n, int global_iter_k, int shared_iter_k, bool mask)
825
+ {
826
+ constexpr int threads_needed = CTA_N / PACK_SIZE / 1;
827
+ constexpr int threads_used = threads_needed < CTA_SIZE ? threads_needed : CTA_SIZE;
828
+ constexpr int total_global_iters = CTA_N / PACK_SIZE / threads_used;
829
+ constexpr int threads_per_row = CTA_N / PACK_SIZE;
830
+ constexpr int kSmemCol = CTA_N;
831
+ bool local_mask = mask & (threadIdx.y * WARP_SIZE + threadIdx.x < threads_used);
832
+ int g_idx = global_iter_k * CTA_K / G;
833
+
834
+ void *dst_ptr = (void *)(dst + (threadIdx.x % threads_per_row) * PACK_SIZE);
835
+ uint4 *src_ptr = (uint4 *)(src + g_idx * global_ncols + cta_offset_n + (threadIdx.x % threads_per_row) * PACK_SIZE);
836
+ void *dst_ptr_z = (void *)(dst_z + (threadIdx.x % threads_per_row) * PACK_SIZE);
837
+ uint4 *src_ptr_z = (uint4 *)(src_z + g_idx * global_ncols + cta_offset_n + (threadIdx.x % threads_per_row) * PACK_SIZE);
838
+ if (STAGES > 1)
839
+ {
840
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
841
+ cp_async_cg_A(addr, src_ptr, local_mask);
842
+ uint32_t addr_z = cast_smem_ptr_to_uint(dst_ptr_z);
843
+ cp_async_cg_A(addr_z, src_ptr_z, local_mask);
844
+ }
845
+ else
846
+ {
847
+ if (local_mask)
848
+ {
849
+ *(uint4 *)dst_ptr = *src_ptr;
850
+ *(uint4 *)dst_ptr_z = *src_ptr_z;
851
+ }
852
+ }
853
+ }
854
+
855
+ template <int CTA_M, int CTA_N, int CTA_K, int STAGES, int shared_iters, typename T>
856
+ __device__ __inline__ void share_to_reg_one_stage_A_T2(T *src, T *dst, int warp_offset_m, int warp_offset_n, int k_0_1)
857
+ {
858
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_A;
859
+
860
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
861
+ {
862
+
863
+ int ld_row = warp_offset_m + shared_iter * OP_M + (threadIdx.x % 16);
864
+ int ld_col = k_0_1 * 16 + (threadIdx.x / 16) * 8;
865
+ int ld_col_swizzled = ((ld_col / PACK_SIZE) ^ (ld_row) & 7) * PACK_SIZE;
866
+ void *addr_ptr = (void *)(src + ld_row * kSmemCol + ld_col_swizzled);
867
+
868
+ uint32_t addr = cast_smem_ptr_to_uint(addr_ptr);
869
+ ldmatrix_m8n8_x4_b16(dst, shared_iter, addr);
870
+ }
871
+ }
872
+
873
+ template <int CTA_M, int CTA_N, int CTA_K, int STAGES, bool ldmatrix, int shared_iters, int G, typename T>
874
+ __device__ __inline__ void share_to_reg_one_stage_B_T2(T *src, T *src_scales, T *src_zeros, T *dst, T *dst_fp16, int warp_offset_m, int warp_offset_n, int k_0_1)
875
+ {
876
+ using T2 = typename std::conditional<std::is_same<T, half>::value, half2, nv_bfloat162>::type;
877
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_B;
878
+ int r0 = ((threadIdx.x / 8 / 2) * 8 + threadIdx.x % 8);
879
+ int c0 = ((threadIdx.x / 8) % 2) * 8;
880
+ int r = r0 / 4;
881
+ int c = (r0 % 4) * 16 + c0;
882
+ int c_swizzled = ((c / PACK_SIZE) ^ (r % 2) & 7) * PACK_SIZE;
883
+
884
+ if constexpr (ldmatrix)
885
+ {
886
+ #pragma unroll
887
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
888
+ {
889
+ void *addr_ptr = (void *)(src + warp_offset_n / kInterleave * kSmemCol + shared_iter * 16 / kInterleave * kSmemCol + k_0_1 * 16 + r * kSmemCol + c_swizzled);
890
+ uint32_t addr = cast_smem_ptr_to_uint(addr_ptr);
891
+ ldmatrix_m8n8_x4_b16(dst, shared_iter, addr);
892
+ }
893
+ }
894
+
895
+ #pragma unroll
896
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
897
+ {
898
+ T scale = src_scales[warp_offset_n + 16 * shared_iter + 8 * (k_0_1 % 2) + threadIdx.x / 4];
899
+ T zero = src_zeros[warp_offset_n + 16 * shared_iter + 8 * (k_0_1 % 2) + threadIdx.x / 4];
900
+ T2 scale2, zero2;
901
+ if constexpr (std::is_same<T, half>::value)
902
+ {
903
+ scale2 = __half2half2(scale);
904
+ zero2 = __half2half2(zero);
905
+ }
906
+ else
907
+ {
908
+ scale2 = __bfloat162bfloat162(scale);
909
+ zero2 = __bfloat162bfloat162(zero);
910
+ }
911
+ T2 loaded[4];
912
+ dequantize_s4_to_fp16x2<T>(*reinterpret_cast<half2 *>(dst + (k_0_1 % 2) * 4 + (k_0_1 / 2 * 2) + shared_iter * 8), reinterpret_cast<uint4 *>(loaded));
913
+ #pragma unroll
914
+ for (int i = 0; i < 4; i++)
915
+ {
916
+ loaded[i] = __hfma2(loaded[i], scale2, zero2);
917
+ }
918
+ *reinterpret_cast<uint4 *>(dst_fp16 + shared_iter * 16 + 8 * (k_0_1 % 2)) = *reinterpret_cast<uint4 *>(loaded);
919
+ }
920
+ }
921
+
922
+ template <int CTA_M, int CTA_N, int CTA_K, int WARP_M, int WARP_N, int WARP_K, int STAGES, int G, typename T>
923
+ __global__ void gemm_w4a16_T2(T *__restrict__ A, T *__restrict__ B, T *__restrict__ scales, T *__restrict__ zeros, T *__restrict__ C, int M, int N, int K)
924
+ {
925
+ using DTypeAccum = typename std::conditional<std::is_same<T, half>::value, half, float>::type;
926
+ constexpr int NUM_WARPS = CTA_M / WARP_M * CTA_N / WARP_N;
927
+ constexpr int CTA_SIZE = NUM_WARPS * WARP_SIZE;
928
+ int num_blocks_n = (N + CTA_N - 1) / CTA_N;
929
+ int num_blocks_m = (M + CTA_M - 1) / CTA_M;
930
+ int blockIdx_x = 0;
931
+ int blockIdx_y = blockIdx.x % (num_blocks_m * num_blocks_n);
932
+ int blockIdx_z = blockIdx.x / (num_blocks_m * num_blocks_n);
933
+ const int log_tile = get_log_tile<1>((N + CTA_N - 1) / CTA_N);
934
+ int blockIdx_m = blockIdx_y / (num_blocks_n >> log_tile);
935
+ int blockIdx_n = blockIdx_y % (num_blocks_n >> log_tile);
936
+ const uint2 block_idx_mapping = get_block_idx_mapping(blockIdx_m, blockIdx_n, log_tile);
937
+ blockIdx_m = block_idx_mapping.x;
938
+ blockIdx_n = block_idx_mapping.y;
939
+
940
+ DTypeAccum C_warp[CTA_M * CTA_N / CTA_SIZE];
941
+ constexpr int kSmemPadKA = CTA_K + SMEM_PAD_A;
942
+ constexpr int kSmemPadKB = CTA_K + SMEM_PAD_B;
943
+ constexpr int kSmemSizeAPerStage = CTA_M * kSmemPadKA;
944
+ constexpr int kSmemSizeBPerStage = CTA_N / kInterleave * kSmemPadKB;
945
+ constexpr int kSmemSizeA = kSmemSizeAPerStage * STAGES;
946
+ constexpr int kSmemSizeB = kSmemSizeBPerStage * STAGES;
947
+ constexpr int kSmemSizeScales = CTA_N * STAGES / 2;
948
+ constexpr int kSmemSizeZeros = CTA_N * STAGES / 2;
949
+ constexpr int scales_load_interval = G / CTA_K;
950
+ extern __shared__ half mem_shared[];
951
+ T *A_shared = (T*)mem_shared;
952
+ T *B_shared = (T*)mem_shared + kSmemSizeA;
953
+ T *scales_shared = (T*)mem_shared + kSmemSizeA + kSmemSizeB;
954
+ T *zeros_shared = (T*)mem_shared + kSmemSizeA + kSmemSizeB + kSmemSizeScales;
955
+ T A_shared_warp_[2][WARP_M * INTRIN_K /
956
+ WARP_SIZE];
957
+ T B_shared_warp_[2][WARP_N * 32 /
958
+ WARP_SIZE];
959
+ T B_shared_warp_tmp_[2][WARP_N * 16 /
960
+ WARP_SIZE];
961
+ int cta_offset_m = blockIdx_m * CTA_M;
962
+ int cta_offset_n = blockIdx_n * CTA_N;
963
+ int warp_offset_m = (threadIdx.y % (CTA_M / WARP_M)) * WARP_M;
964
+ int warp_offset_n = (threadIdx.y / (CTA_M / WARP_M)) * WARP_N;
965
+
966
+ for (int i = 0; i < CTA_M * CTA_N / CTA_SIZE; i++)
967
+ C_warp[i] = 0.0;
968
+
969
+ int gemm_iters = (K + CTA_K - 1) / CTA_K;
970
+ int k_0_0_ld = 0;
971
+ int k_0_0 = 0;
972
+ constexpr int prologue_stages = STAGES == 1 ? 1 : STAGES - 1;
973
+ #pragma unroll
974
+ for (k_0_0_ld = 0; k_0_0_ld < prologue_stages; ++k_0_0_ld)
975
+ {
976
+ global_to_share_one_stage_A_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(A, A_shared + k_0_0_ld * kSmemSizeAPerStage, M, K, cta_offset_m, cta_offset_n, k_0_0_ld, 0, true);
977
+ global_to_share_one_stage_B_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(B, B_shared + k_0_0_ld * kSmemSizeBPerStage, K, cta_offset_m, cta_offset_n, k_0_0_ld, 0, true);
978
+ global_to_share_one_stage_scales_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES, G>(
979
+ scales, scales_shared + (k_0_0_ld / scales_load_interval) * CTA_N,
980
+ zeros, zeros_shared + (k_0_0_ld / scales_load_interval) * CTA_N,
981
+ N, cta_offset_m, cta_offset_n, k_0_0_ld, 0, k_0_0_ld < gemm_iters && k_0_0_ld % scales_load_interval == 0);
982
+ if constexpr (STAGES > 1)
983
+ __pipeline_commit();
984
+ }
985
+ if constexpr (STAGES > 1)
986
+ __pipeline_wait_prior(STAGES - 2);
987
+ __syncthreads();
988
+
989
+ share_to_reg_one_stage_A_T2<CTA_M, CTA_N, CTA_K, STAGES, WARP_M / INTRIN_M>(A_shared, A_shared_warp_[0], warp_offset_m, warp_offset_n, 0);
990
+ share_to_reg_one_stage_B_T2<CTA_M, CTA_N, CTA_K, STAGES, true, WARP_N / INTRIN_N, G>(B_shared, scales_shared, zeros_shared, B_shared_warp_tmp_[0], B_shared_warp_[0], warp_offset_m, warp_offset_n, 0);
991
+ constexpr int SHARED_K_ITERS = WARP_K / INTRIN_K;
992
+
993
+ for (; k_0_0 < gemm_iters; ++k_0_0, ++k_0_0_ld)
994
+ {
995
+ int ld_stage = k_0_0_ld % STAGES;
996
+ int compute_stage = k_0_0 % STAGES;
997
+ T *A_shared_this_compute_stage;
998
+ T *B_shared_this_compute_stage;
999
+ T *scales_shared_this_compute_stage;
1000
+ T *zeros_shared_this_compute_stage;
1001
+
1002
+ for (int iter_k = 0; iter_k < SHARED_K_ITERS; ++iter_k)
1003
+ {
1004
+ A_shared_this_compute_stage = A_shared + compute_stage * kSmemSizeAPerStage;
1005
+ B_shared_this_compute_stage = B_shared + compute_stage * kSmemSizeBPerStage;
1006
+ scales_shared_this_compute_stage = scales_shared + (compute_stage / scales_load_interval) * CTA_N;
1007
+ zeros_shared_this_compute_stage = zeros_shared + (compute_stage / scales_load_interval) * CTA_N;
1008
+ share_to_reg_one_stage_A_T2<CTA_M, CTA_N, CTA_K, STAGES, WARP_M / INTRIN_M>(A_shared_this_compute_stage, A_shared_warp_[(iter_k + 1) % 2], warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS);
1009
+ if ((iter_k + 1) % kInterleave == 0)
1010
+ {
1011
+ if (compute_stage % 2 == 1)
1012
+ {
1013
+ share_to_reg_one_stage_B_T2<CTA_M, CTA_N, CTA_K, STAGES, true, WARP_N / INTRIN_N, G>(
1014
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
1015
+ B_shared_warp_tmp_[1], B_shared_warp_[((iter_k + 1) / 2) % 2],
1016
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS);
1017
+ }
1018
+ else
1019
+ {
1020
+ share_to_reg_one_stage_B_T2<CTA_M, CTA_N, CTA_K, STAGES, true, WARP_N / INTRIN_N, G>(
1021
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
1022
+ B_shared_warp_tmp_[0], B_shared_warp_[((iter_k + 1) / 2) % 2],
1023
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS);
1024
+ }
1025
+ }
1026
+ else
1027
+ {
1028
+ if (compute_stage % 2 == 1)
1029
+ {
1030
+ share_to_reg_one_stage_B_T2<CTA_M, CTA_N, CTA_K, STAGES, false, WARP_N / INTRIN_N, G>(
1031
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
1032
+ B_shared_warp_tmp_[1], B_shared_warp_[((iter_k + 1) / 2) % 2],
1033
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS);
1034
+ }
1035
+ else
1036
+ {
1037
+ share_to_reg_one_stage_B_T2<CTA_M, CTA_N, CTA_K, STAGES, false, WARP_N / INTRIN_N, G>(
1038
+ B_shared_this_compute_stage, scales_shared_this_compute_stage, zeros_shared_this_compute_stage,
1039
+ B_shared_warp_tmp_[0], B_shared_warp_[((iter_k + 1) / 2) % 2],
1040
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS);
1041
+ }
1042
+ }
1043
+ __syncthreads();
1044
+ T *A_shared_warp = A_shared_warp_[iter_k % 2];
1045
+ T *B_shared_warp = B_shared_warp_[(iter_k / 2) % 2];
1046
+ for (int i_0_3 = 0; i_0_3 < WARP_M / INTRIN_M; ++i_0_3)
1047
+ {
1048
+ for (int j_0_4 = 0; j_0_4 < WARP_N / INTRIN_N; ++j_0_4)
1049
+ {
1050
+ if constexpr (std::is_same<T, half>::value)
1051
+ {
1052
+ mma_m16n8k16_f16f16f16(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4);
1053
+ mma_m16n8k16_f16f16f16(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8 + 4, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4 + 8);
1054
+ }
1055
+ else
1056
+ {
1057
+ mma_m16n8k16_bf16bf16f32(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4);
1058
+ mma_m16n8k16_bf16bf16f32(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8 + 4, A_shared_warp + i_0_3 * 8, B_shared_warp + j_0_4 * 16 + (iter_k % 2) * 4 + 8);
1059
+ }
1060
+ }
1061
+ }
1062
+
1063
+ if (iter_k < WARP_K / INTRIN_K - 1)
1064
+ {
1065
+ if constexpr (STAGES == 1)
1066
+ __syncthreads();
1067
+ global_to_share_one_stage_A_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(A, A_shared + ld_stage * kSmemSizeAPerStage, M, K, cta_offset_m, cta_offset_n, k_0_0_ld, iter_k, k_0_0_ld < gemm_iters);
1068
+ global_to_share_one_stage_B_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(B, B_shared + ld_stage * kSmemSizeBPerStage, K, cta_offset_m, cta_offset_n, k_0_0_ld, iter_k, k_0_0_ld < gemm_iters);
1069
+ }
1070
+
1071
+ if (iter_k == WARP_K / INTRIN_K - 2)
1072
+ {
1073
+ if constexpr (STAGES == 1 && WARP_K / INTRIN_K > 2)
1074
+ {
1075
+ __syncthreads();
1076
+ }
1077
+ global_to_share_one_stage_A_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(A, A_shared + ld_stage * kSmemSizeAPerStage, M, K, cta_offset_m, cta_offset_n, k_0_0_ld, iter_k + 1, k_0_0_ld < gemm_iters);
1078
+ global_to_share_one_stage_B_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, WARP_K / INTRIN_K, STAGES>(B, B_shared + ld_stage * kSmemSizeBPerStage, K, cta_offset_m, cta_offset_n, k_0_0_ld, iter_k + 1, k_0_0_ld < gemm_iters);
1079
+ global_to_share_one_stage_scales_T2<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES, G>(
1080
+ scales, scales_shared + (ld_stage / scales_load_interval) * CTA_N,
1081
+ zeros, zeros_shared + (ld_stage / scales_load_interval) * CTA_N,
1082
+ N, cta_offset_m, cta_offset_n, k_0_0_ld, iter_k, k_0_0_ld < gemm_iters && k_0_0_ld % scales_load_interval == 0);
1083
+ if constexpr (STAGES > 1)
1084
+ {
1085
+ __pipeline_commit();
1086
+ __pipeline_wait_prior(STAGES - 2);
1087
+ }
1088
+ compute_stage = (k_0_0 + 1) % STAGES;
1089
+ __syncthreads();
1090
+ }
1091
+ }
1092
+ }
1093
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
1094
+ {
1095
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
1096
+ {
1097
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
1098
+ {
1099
+ int write_row = cta_offset_m + warp_offset_m + ax0_0_1 * OP_M + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4));
1100
+ if (write_row < M)
1101
+ {
1102
+ if constexpr (std::is_same<T, half>::value)
1103
+ {
1104
+ *reinterpret_cast<half2 *>(
1105
+ C + write_row * N +
1106
+ cta_offset_n + warp_offset_n + ax1_0_1 * 16 +
1107
+ (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2) =
1108
+ (*reinterpret_cast<half2 *>(C_warp + ax0_0_1 * WARP_N / INTRIN_N * 8 +
1109
+ ax1_0_1 * 8 + local_id));
1110
+ }
1111
+ else
1112
+ {
1113
+ *reinterpret_cast<nv_bfloat162 *>(
1114
+ C + write_row * N +
1115
+ cta_offset_n + warp_offset_n + ax1_0_1 * 16 +
1116
+ (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2) =
1117
+ (__float22bfloat162_rn(*reinterpret_cast<float2 *>(C_warp + ax0_0_1 * WARP_N / INTRIN_N * 8 +
1118
+ ax1_0_1 * 8 + local_id)));
1119
+ }
1120
+ }
1121
+ };
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ torch::Tensor gemm_forward_cuda_new(
1127
+ torch::Tensor _in_feats,
1128
+ torch::Tensor _kernel,
1129
+ torch::Tensor _scales,
1130
+ torch::Tensor _zeros)
1131
+ {
1132
+ std::vector<int64_t> output_shape = _in_feats.sizes().vec();
1133
+ output_shape.back() = _kernel.size(0) * kInterleave;
1134
+ int num_in_feats = _in_feats.numel() / _in_feats.size(-1);
1135
+ int num_in_channels = _in_feats.size(-1);
1136
+ auto options =
1137
+ torch::TensorOptions().dtype(_in_feats.dtype()).device(_in_feats.device());
1138
+ auto options_int =
1139
+ torch::TensorOptions().dtype(torch::kInt32).device(_in_feats.device());
1140
+ at::Tensor _out_feats = torch::empty(output_shape, options);
1141
+ int num_out_feats = _out_feats.numel() / _out_feats.size(-1);
1142
+ int num_out_channels = _out_feats.size(-1);
1143
+
1144
+ auto data_type = _in_feats.scalar_type();
1145
+ TORCH_CHECK(_scales.scalar_type() == data_type);
1146
+ TORCH_CHECK(_zeros.scalar_type() == data_type);
1147
+
1148
+ DISPATCH_PYTORCH_DTYPE_TO_CTYPE_FP16(data_type, ctype, {
1149
+ auto in_feats = reinterpret_cast<ctype *>(_in_feats.data_ptr());
1150
+ auto kernel = reinterpret_cast<ctype *>(_kernel.data_ptr());
1151
+ auto scales = reinterpret_cast<ctype *>(_scales.data_ptr());
1152
+ auto zeros = reinterpret_cast<ctype *>(_zeros.data_ptr());
1153
+ auto out_feats = reinterpret_cast<ctype *>(_out_feats.data_ptr());
1154
+
1155
+ if (num_out_feats <= 32)
1156
+ {
1157
+ constexpr int G = 128;
1158
+ constexpr int CTA_M = 16;
1159
+ constexpr int CTA_N = 128;
1160
+ constexpr int CTA_K = 128;
1161
+ constexpr int WARP_M = 16;
1162
+ constexpr int WARP_N = 32;
1163
+ constexpr int WARP_K = 64;
1164
+ constexpr int SPLITK = 2;
1165
+ constexpr int STAGES = 4;
1166
+ KERNEL_LAUNCH_CODE
1167
+ }
1168
+ else if (num_out_feats <= 64)
1169
+ {
1170
+ constexpr int G = 128;
1171
+ constexpr int CTA_M = 16;
1172
+ constexpr int CTA_N = 128;
1173
+ constexpr int CTA_K = 128;
1174
+ constexpr int WARP_M = 16;
1175
+ constexpr int WARP_N = 32;
1176
+ constexpr int WARP_K = 64;
1177
+ constexpr int SPLITK = 1;
1178
+ constexpr int STAGES = 3;
1179
+ KERNEL_LAUNCH_CODE
1180
+ }
1181
+ else if (num_out_feats <= 128)
1182
+ {
1183
+ constexpr int G = 128;
1184
+ constexpr int CTA_M = 32;
1185
+ constexpr int CTA_N = 128;
1186
+ constexpr int CTA_K = 128;
1187
+ constexpr int WARP_M = 32;
1188
+ constexpr int WARP_N = 32;
1189
+ constexpr int WARP_K = 64;
1190
+ constexpr int SPLITK = 1;
1191
+ constexpr int STAGES = 4;
1192
+ KERNEL_LAUNCH_CODE
1193
+ }
1194
+ else if (num_out_feats <= 192)
1195
+ {
1196
+ constexpr int G = 128;
1197
+ constexpr int CTA_M = 64;
1198
+ constexpr int CTA_N = 128;
1199
+ constexpr int CTA_K = 64;
1200
+ constexpr int WARP_M = 64;
1201
+ constexpr int WARP_N = 32;
1202
+ constexpr int WARP_K = 64;
1203
+ constexpr int SPLITK = 1;
1204
+ constexpr int STAGES = 4;
1205
+ KERNEL_LAUNCH_CODE
1206
+ }
1207
+ else
1208
+ {
1209
+ constexpr int G = 128;
1210
+ constexpr int CTA_M = 64;
1211
+ constexpr int CTA_N = 128;
1212
+ constexpr int CTA_K = 64;
1213
+ constexpr int WARP_M = 64;
1214
+ constexpr int WARP_N = 32;
1215
+ constexpr int WARP_K = 64;
1216
+ constexpr int STAGES = 4;
1217
+
1218
+ constexpr int NUM_WARPS = (CTA_M / WARP_M) * (CTA_N / WARP_N);
1219
+ constexpr int kSmemByteSize = (CTA_M * (CTA_K + SMEM_PAD_A) + CTA_N * (CTA_K + SMEM_PAD_B) / kInterleave + CTA_N) * STAGES * sizeof(ctype);
1220
+ if (kSmemByteSize >= 99 * 1024)
1221
+ {
1222
+ printf("This kernel requires %d Bytes of shared memory, which exceeds device limit.\n", kSmemByteSize);
1223
+ return _out_feats;
1224
+ }
1225
+ int j_factors1 = num_out_channels / CTA_N / 1;
1226
+ dim3 num_blocks((num_out_feats + CTA_M - 1) / CTA_M * j_factors1);
1227
+ dim3 threads_per_block(WARP_SIZE, NUM_WARPS);
1228
+ auto kernel_func = gemm_w4a16_T2<CTA_M, CTA_N, CTA_K, WARP_M, WARP_N, WARP_K, STAGES, G, ctype>;
1229
+ cudaFuncSetAttribute(kernel_func, cudaFuncAttributeMaxDynamicSharedMemorySize, kSmemByteSize);
1230
+ kernel_func<<<num_blocks, threads_per_block, kSmemByteSize>>>(
1231
+ in_feats, kernel, scales, zeros, out_feats, num_in_feats, num_out_channels, num_in_channels);
1232
+ }
1233
+ });
1234
+
1235
+ return _out_feats;
1236
+ }
llm-awq/awq/kernels/csrc/quantization_new/gemm/gemm_cuda.h ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #include <torch/extension.h>
2
+
3
+ torch::Tensor gemm_forward_cuda_new(torch::Tensor _in_feats, torch::Tensor _kernel, torch::Tensor _scales, torch::Tensor _zeros);
llm-awq/awq/kernels/csrc/quantization_new/gemm/semaphore.h ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /***************************************************************************************************
2
+ * Copyright (c) 2017 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: BSD-3-Clause
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * 3. Neither the name of the copyright holder nor the names of its
16
+ * contributors may be used to endorse or promote products derived from
17
+ * this software without specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ **************************************************************************************************/
31
+ /*! \file
32
+ \brief Implementation of a CTA-wide semaphore for inter-CTA synchronization.
33
+ */
34
+
35
+ #pragma once
36
+
37
+ /////////////////////////////////////////////////////////////////////////////////////////////////
38
+
39
+ // namespace cutlass {
40
+
41
+ /////////////////////////////////////////////////////////////////////////////////////////////////
42
+
43
+ /// CTA-wide semaphore for inter-CTA synchronization.
44
+ class Semaphore
45
+ {
46
+ public:
47
+ int *lock;
48
+ bool wait_thread;
49
+ int state;
50
+
51
+ public:
52
+ /// Implements a semaphore to wait for a flag to reach a given value
53
+ __host__ __device__ Semaphore(int *lock_, int thread_id) : lock(lock_),
54
+ wait_thread(thread_id < 0 || thread_id == 0),
55
+ state(-1)
56
+ {
57
+ }
58
+
59
+ /// Permit fetching the synchronization mechanism early
60
+ __device__ void fetch()
61
+ {
62
+ if (wait_thread)
63
+ {
64
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
65
+ asm volatile("ld.global.acquire.gpu.b32 %0, [%1];\n" : "=r"(state) : "l"(lock));
66
+ #else
67
+ asm volatile("ld.global.cg.b32 %0, [%1];\n" : "=r"(state) : "l"(lock));
68
+ #endif
69
+ }
70
+ }
71
+
72
+ /// Gets the internal state
73
+ __device__ int get_state() const
74
+ {
75
+ return state;
76
+ }
77
+
78
+ /// Waits until the semaphore is equal to the given value
79
+ __device__ void wait(int status = 0)
80
+ {
81
+ while (__syncthreads_and(state != status))
82
+ {
83
+ fetch();
84
+ }
85
+
86
+ __syncthreads();
87
+ }
88
+
89
+ /// Updates the lock with the given result
90
+ __device__ void release(int status = 0)
91
+ {
92
+ __syncthreads();
93
+
94
+ if (wait_thread)
95
+ {
96
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
97
+ asm volatile("st.global.release.gpu.b32 [%0], %1;\n" : : "l"(lock), "r"(status));
98
+ #else
99
+ asm volatile("st.global.cg.b32 [%0], %1;\n" : : "l"(lock), "r"(status));
100
+ #endif
101
+ }
102
+ }
103
+ };
104
+
105
+ /////////////////////////////////////////////////////////////////////////////////////////////////
106
+
107
+ // } // namespace cutlass
108
+
109
+ /////////////////////////////////////////////////////////////////////////////////////////////////
llm-awq/awq/kernels/csrc/quantization_new/gemv/gemv_cuda.cu ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Modified from NVIDIA [TRT-LLM](https://github.com/NVIDIA/TensorRT-LLM/tree/d37b507f41a87457fe9f10f7459d08f5db235745/cpp/tensorrt_llm/kernels/weightOnlyBatchedGemv)
3
+ * Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /*
19
+ @article{lin2023awq,
20
+ title={AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration},
21
+ author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Dang, Xingyu and Han, Song},
22
+ journal={arXiv},
23
+ year={2023}
24
+ }
25
+ */
26
+
27
+ #include <cuda_fp16.h>
28
+ #include <stdio.h>
29
+ #include <torch/extension.h>
30
+ #include "gemv_cuda.h"
31
+ #include "../dequantize.cuh"
32
+ #include "../dispatch_utils.cuh"
33
+ #define PACK_FACTOR 8
34
+ #define WARP_SIZE 32
35
+ #define MEM_ACCESS_SIZE 128
36
+
37
+ // Reduce sum within the warp using the tree reduction algorithm.
38
+ template <int Num, int WarpSize, typename T>
39
+ __device__ __forceinline__ static void warp_reduce(T* psum, float (*out_smem)[Num * 4])
40
+ {
41
+ // kInterleave = 4
42
+ float fpsum[Num];
43
+ #pragma unroll
44
+ for (int i = 0; i < Num; ++i)
45
+ {
46
+ fpsum[i] = static_cast<float>(psum[i]);
47
+ }
48
+
49
+ #pragma unroll
50
+ for (int i = 0; i < Num; ++i)
51
+ {
52
+ // T0 + T1 + T8 + T9 + T16 + T17 + T24 + T25 (kInterleave = 4)
53
+ fpsum[i] += __shfl_xor_sync(~0, fpsum[i], 16);
54
+ fpsum[i] += __shfl_xor_sync(~0, fpsum[i], 8);
55
+ fpsum[i] += __shfl_xor_sync(~0, fpsum[i], 1);
56
+ }
57
+ __syncthreads();
58
+ int warp = threadIdx.x / WarpSize, lane = threadIdx.x % WarpSize;
59
+ if (lane == 0 || lane == 2 || lane == 4 || lane == 6)
60
+ {
61
+ #pragma unroll
62
+ for (int i = 0; i < Num; ++i)
63
+ {
64
+ out_smem[warp][i * 4 + lane / 2] = fpsum[i];
65
+ }
66
+ }
67
+ __syncthreads();
68
+ };
69
+
70
+ __device__ __forceinline__ int make_divisible(int c, int divisor){
71
+ return (c + divisor - 1) / divisor;
72
+ }
73
+
74
+ template <int NPerBlock, int Batch, int BlockSize, int GroupSize, typename T>
75
+ __global__ void gemv_kernel(
76
+ const T* inputs, const uint32_t* weight, const T* scales, const T* zeros, T* outputs,
77
+ const int IC, const int OC)
78
+ {
79
+ const int kStride = 64;
80
+ const int kElemsPerThread = MEM_ACCESS_SIZE / 4;
81
+ const int kThreadsNumPerTile = kStride / kElemsPerThread;
82
+ // assert(MEM_ACCESS_SIZE == 128);
83
+
84
+ using T2 = typename std::conditional<
85
+ std::is_same<T, half>::value,
86
+ half2,
87
+ nv_bfloat162
88
+ >::type;
89
+
90
+ static constexpr int kShuffleSize = 32;
91
+ static constexpr int kShuffleBasicTile = 2;
92
+ static constexpr int kShuffleContinous = 4;
93
+ static constexpr int kShuffleStrided = 4;
94
+
95
+ constexpr int Num = NPerBlock * Batch;
96
+ constexpr int kInterleave = 4;
97
+
98
+ T local_inputs[kElemsPerThread];
99
+ uint32_t local_qweights[MEM_ACCESS_SIZE / 32];
100
+ T half_weight_buffer[kElemsPerThread];
101
+ T dequantized_weight[kElemsPerThread * NPerBlock];
102
+ T local_scale[NPerBlock];
103
+ T local_scaled_zeros[NPerBlock];
104
+
105
+ T psum[Num];
106
+ for (int i = 0; i < Num; ++i)
107
+ psum[i] = static_cast<T>(0.f);
108
+
109
+ // extern __shared__ uint8_t shmem[];
110
+ // float(*out_smem)[Num * kInterleave] = reinterpret_cast<float(*)[Num * kInterleave]>(shmem);
111
+ __shared__ float out_smem[BlockSize / WARP_SIZE * 2][Num * kInterleave];
112
+
113
+ const int blk_row_offset = blockIdx.x * NPerBlock * kInterleave;
114
+ const int thd_row_offset = (threadIdx.x / kThreadsNumPerTile) % kInterleave;
115
+ const int act_k_offset = threadIdx.x / (kThreadsNumPerTile * kInterleave) * kStride
116
+ + (threadIdx.x % kThreadsNumPerTile) * kElemsPerThread;
117
+ const int group_offset = act_k_offset / GroupSize;
118
+ // TODO: use make_divisible
119
+ const uint32_t* blk_weight_ptr = weight + blk_row_offset * IC / PACK_FACTOR;
120
+ const T* scale_ptr = scales + blk_row_offset + thd_row_offset + group_offset * OC;
121
+ const T* zeros_ptr = zeros + blk_row_offset + thd_row_offset + group_offset * OC;
122
+ const T* inputs_ptr = inputs + act_k_offset;
123
+
124
+ const int act_forward_step = BlockSize * kElemsPerThread / kInterleave;
125
+ const int scale_forward_step = act_forward_step / GroupSize * OC;
126
+
127
+ // Main loop iteration, each block completes the outputs for several OCs
128
+ for (int kk = threadIdx.x * kElemsPerThread; kk < IC * kInterleave; kk += BlockSize * kElemsPerThread)
129
+ {
130
+ // Load qweight, scales and scaled_zeros
131
+ #pragma unroll
132
+ for (int idx = 0; idx < NPerBlock; ++idx)
133
+ {
134
+ // use float4 to load weights, each thread load 32 int4 numbers (1 x float4, 128 bit)
135
+ *((float4*)(local_qweights)) =
136
+ *((float4*)(blk_weight_ptr + (idx * kInterleave * IC + kk)/ PACK_FACTOR));
137
+ local_scale[idx] = *(scale_ptr + idx * kInterleave);
138
+ local_scaled_zeros[idx] = *(zeros_ptr + idx * kInterleave);
139
+
140
+ // Map int4 qweight to fp format
141
+ #pragma unroll
142
+ for (int i = 0; i < MEM_ACCESS_SIZE / 32; ++i)
143
+ {
144
+ // Converts 32 bits (8 x int4) to 8 fp16
145
+ dequantize_s4_to_fp16x2<T>(*reinterpret_cast<half2 *>(local_qweights + i), reinterpret_cast<uint4 *>(half_weight_buffer + i * PACK_FACTOR));
146
+ }
147
+
148
+ // Dequantize (apply s/z) and shuffle elements to match the weight packing format
149
+ #pragma unroll
150
+ for (int i = 0; i < kShuffleContinous; ++i)
151
+ {
152
+ #pragma unroll
153
+ for (int j = 0; j < kShuffleStrided; ++j)
154
+ {
155
+ T2 w =
156
+ *reinterpret_cast<T2*>(
157
+ half_weight_buffer + (i + j * kShuffleContinous)* kShuffleBasicTile
158
+ );
159
+ if constexpr (std::is_same<T, half>::value)
160
+ {
161
+ w = __hfma2(w, __half2half2(local_scale[idx]), __half2half2(local_scaled_zeros[idx]));
162
+ }
163
+ else
164
+ {
165
+ w = __hfma2(w, __bfloat162bfloat162(local_scale[idx]), __bfloat162bfloat162(local_scaled_zeros[idx]));
166
+ }
167
+ dequantized_weight[((i * kShuffleStrided + j) * kShuffleBasicTile + 0)
168
+ * NPerBlock + idx]
169
+ = w.x;
170
+ dequantized_weight[((i * kShuffleStrided + j) * kShuffleBasicTile + 1)
171
+ * NPerBlock + idx]
172
+ = w.y;
173
+ }
174
+ }
175
+ }
176
+ #pragma unroll
177
+ for (int batch_idx = 0; batch_idx < Batch; ++batch_idx)
178
+ {
179
+ const T* local_inputs_ptr = inputs_ptr + batch_idx * IC;
180
+ #pragma unroll
181
+ for (int idx = 0; idx < kElemsPerThread / 8; ++idx)
182
+ {
183
+ // load activation, 8 halves (128 bits) / step.
184
+ *((float4*)(local_inputs + idx * 8)) = *((float4*)(local_inputs_ptr + idx * 8));
185
+ }
186
+ // Perform the MACs
187
+ #pragma unroll
188
+ for (int x = 0; x < NPerBlock / 2; ++x)
189
+ {
190
+ #pragma unroll
191
+ for (int y = 0; y < kElemsPerThread; ++y)
192
+ {
193
+ if constexpr (std::is_same<T, half>::value)
194
+ {
195
+ *reinterpret_cast<half2*>(psum + batch_idx * NPerBlock + x * 2)
196
+ = __hfma2(*reinterpret_cast<half2*>(dequantized_weight + y * NPerBlock + x * 2),
197
+ __half2half2(local_inputs[y]),
198
+ *reinterpret_cast<half2*>(psum + batch_idx * NPerBlock + x * 2));
199
+ }
200
+ else
201
+ {
202
+ *reinterpret_cast<nv_bfloat162*>(psum + batch_idx * NPerBlock + x * 2)
203
+ = __hfma2(*reinterpret_cast<nv_bfloat162*>(dequantized_weight + y * NPerBlock + x * 2),
204
+ __bfloat162bfloat162(local_inputs[y]),
205
+ *reinterpret_cast<nv_bfloat162*>(psum + batch_idx * NPerBlock + x * 2));
206
+ }
207
+ }
208
+ }
209
+ }
210
+ inputs_ptr += act_forward_step;
211
+ scale_ptr += scale_forward_step;
212
+ zeros_ptr += scale_forward_step;
213
+ }
214
+
215
+ warp_reduce<Num, WARP_SIZE>(psum, out_smem);
216
+
217
+ // Num * Interleave = batch * NPerBlock * Interleave -> 1 thread_block write back num
218
+ for (int i = threadIdx.x; i < Num * kInterleave; i += BlockSize)
219
+ {
220
+ int batch_idx = i / (NPerBlock * kInterleave);
221
+ int oc_idx = i % (NPerBlock * kInterleave);
222
+ float acc = 0.f;
223
+ for (int j = 0; j < BlockSize / WARP_SIZE; ++j)
224
+ {
225
+ acc += out_smem[j][i];
226
+ }
227
+ outputs[batch_idx * OC + blk_row_offset + oc_idx] = static_cast<T>(acc);
228
+ }
229
+ }
230
+
231
+ /*
232
+ Computes GEMV (PyTorch interface).
233
+
234
+ Args:
235
+ _in_feats: tensor of shape [B, IC];
236
+ _kernel: int tensor of shape [OC, IC // 8];
237
+ _zeros: int tensor of shape [OC, IC // G // 8];
238
+ _scaling_factors: tensor of shape [OC, IC // G];
239
+ blockDim_x: size of thread block, dimension x, where blockDim_x * workload_per_thread = IC;
240
+ blockDim_y: size of thread block, dimension y, where blockDim_y * gridDim_y = OC;
241
+
242
+ Returns:
243
+ out_feats: tensor of shape [B, OC];
244
+ */
245
+ torch::Tensor gemv_forward_cuda_new(
246
+ torch::Tensor _in_feats,
247
+ torch::Tensor _kernel,
248
+ torch::Tensor _scaling_factors,
249
+ torch::Tensor _zeros,
250
+ int m,
251
+ int n,
252
+ int k,
253
+ int group_size)
254
+ {
255
+
256
+ std::vector<int64_t> output_shape = _in_feats.sizes().vec();
257
+ output_shape.back() = n;
258
+
259
+ auto data_type = _in_feats.scalar_type();
260
+ TORCH_CHECK(_scaling_factors.scalar_type() == data_type);
261
+ TORCH_CHECK(_zeros.scalar_type() == data_type);
262
+
263
+ auto options = torch::TensorOptions().dtype(_in_feats.dtype()).device(_in_feats.device());
264
+ at::Tensor _out_feats = torch::empty(output_shape, options);
265
+
266
+ DISPATCH_PYTORCH_DTYPE_TO_CTYPE_FP16(data_type, ctype, {
267
+ auto in_feats = reinterpret_cast<ctype*>(_in_feats.data_ptr());
268
+ auto kernel = reinterpret_cast<uint32_t*>(_kernel.data_ptr());
269
+ auto zeros = reinterpret_cast<ctype*>(_zeros.data_ptr());
270
+ auto scaling_factors = reinterpret_cast<ctype*>(_scaling_factors.data_ptr());
271
+ auto out_feats = reinterpret_cast<ctype*>(_out_feats.data_ptr());
272
+
273
+ static constexpr int N_PER_BLOCK = 2;
274
+ static constexpr int K_INTERLEAVE = 4;
275
+ static constexpr int BLOCK_SIZE = 256;
276
+
277
+ dim3 num_blocks(n / N_PER_BLOCK / K_INTERLEAVE);
278
+ dim3 num_threads(BLOCK_SIZE);
279
+
280
+ // if (group_size == 64)
281
+ // {
282
+ // gemv_kernel_g64<<<num_blocks, num_threads>>>(
283
+ // // pointers
284
+ // in_feats, kernel, zeros, scaling_factors, out_feats,
285
+ // // constants
286
+ // num_in_channels, num_out_channels
287
+ // );
288
+ // }
289
+ if (group_size == 128)
290
+ {
291
+ switch (m)
292
+ {
293
+ case 1:
294
+ gemv_kernel<N_PER_BLOCK, 1, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
295
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
296
+ );
297
+ break;
298
+ case 2:
299
+ gemv_kernel<N_PER_BLOCK, 2, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
300
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
301
+ );
302
+ break;
303
+ case 3:
304
+ gemv_kernel<N_PER_BLOCK, 3, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
305
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
306
+ );
307
+ break;
308
+ case 4:
309
+ gemv_kernel<N_PER_BLOCK, 4, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
310
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
311
+ );
312
+ break;
313
+ case 5:
314
+ gemv_kernel<N_PER_BLOCK, 5, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
315
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
316
+ );
317
+ break;
318
+ case 6:
319
+ gemv_kernel<N_PER_BLOCK, 6, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
320
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
321
+ );
322
+ break;
323
+ case 7:
324
+ gemv_kernel<N_PER_BLOCK, 7, BLOCK_SIZE, 128><<<num_blocks, num_threads>>>(
325
+ in_feats, kernel, scaling_factors, zeros, out_feats, k, n
326
+ );
327
+ break;
328
+ default:
329
+ throw std::runtime_error("Unsupported batch size for gemv kernel.\n");
330
+ }
331
+ }
332
+ else
333
+ {
334
+ throw std::runtime_error("Unsupported group size for gemv kernel.\n");
335
+ }
336
+ });
337
+ return _out_feats;
338
+ }
339
+
llm-awq/awq/kernels/csrc/quantization_new/gemv/gemv_cuda.h ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+ #include <torch/extension.h>
3
+
4
+ torch::Tensor gemv_forward_cuda_new(
5
+ torch::Tensor _in_feats,
6
+ torch::Tensor _kernel,
7
+ torch::Tensor _scaling_factors,
8
+ torch::Tensor _zeros,
9
+ int m,
10
+ int n,
11
+ int k,
12
+ int group_size);
llm-awq/awq/kernels/csrc/rope_new/fused_rope_with_pos.cu ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Modified from https://github.com/NVIDIA/TransformerEngine
2
+ // Modified by Shang Yang.
3
+
4
+ /*************************************************************************
5
+ * Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
6
+ *reserved.
7
+ *
8
+ * See LICENSE for license information.
9
+ ************************************************************************/
10
+
11
+ #include <ATen/cuda/CUDAContext.h>
12
+ #include <cuda_bf16.h>
13
+ #include <cuda_fp16.h>
14
+ #include <cuda_runtime.h>
15
+ #include <torch/extension.h>
16
+
17
+ #include "fused_rope_with_pos.h"
18
+ // #include <transformer_engine/fused_rope.h>
19
+
20
+ // #include "../common.h"
21
+ // #include "../util/logging.h"
22
+ // #include "../utils.cuh"
23
+ #define VLLM_DISPATCH_CASE_FLOATING_TYPES(...) \
24
+ AT_DISPATCH_CASE(at::ScalarType::Float, __VA_ARGS__) \
25
+ AT_DISPATCH_CASE(at::ScalarType::Half, __VA_ARGS__) \
26
+ AT_DISPATCH_CASE(at::ScalarType::BFloat16, __VA_ARGS__)
27
+
28
+ #define VLLM_DISPATCH_FLOATING_TYPES(TYPE, NAME, ...) \
29
+ AT_DISPATCH_SWITCH(TYPE, NAME, VLLM_DISPATCH_CASE_FLOATING_TYPES(__VA_ARGS__))
30
+
31
+ #define THREADS_PER_WARP 32
32
+
33
+ template <typename scalar_t>
34
+ __device__ void fused_rope_with_pos_block_forward(
35
+ const scalar_t *src, const float *freqs, scalar_t *dst,
36
+ const int offset_block, const int offset_block_dst, const int h,
37
+ const int d, const int d2, const int stride_h, const int stride_d,
38
+ const int o_stride_h, const int o_stride_d) {
39
+ int s_id = blockIdx.x;
40
+ int s = gridDim.x;
41
+ int b_id = blockIdx.y;
42
+ #pragma unroll
43
+ for (int d_id = threadIdx.x; d_id < d2; d_id += blockDim.x) {
44
+ float v_cos, v_sin;
45
+ sincosf(freqs[(b_id * s + s_id) * d2 + d_id], &v_sin, &v_cos);
46
+ #pragma unroll
47
+ for (int h_id = threadIdx.y; h_id < h; h_id += blockDim.y) {
48
+ int offset_src = offset_block + h_id * stride_h + d_id * stride_d;
49
+ int offset_dst = offset_block_dst + h_id * o_stride_h + d_id * o_stride_d;
50
+ float v_src = src[offset_src];
51
+ float v_src_rotate =
52
+ (d_id + d2 / 2 < d2)
53
+ ? -static_cast<float>(src[offset_src + (d2 / 2) * stride_d])
54
+ : static_cast<float>(src[offset_src + (d2 / 2 - d2) * stride_d]);
55
+ dst[offset_dst] = v_src * v_cos + v_src_rotate * v_sin;
56
+ }
57
+ }
58
+
59
+ // copy the rest
60
+ if (d > d2) {
61
+ #pragma unroll
62
+ for (int h_id = threadIdx.y; h_id < h; h_id += blockDim.y) {
63
+ int offset_head = offset_block + h_id * stride_h;
64
+ int offset_head_dst = offset_block_dst + h_id * o_stride_h;
65
+ #pragma unroll
66
+ for (int d_id = d2 + threadIdx.x; d_id < d; d_id += blockDim.x) {
67
+ dst[offset_head_dst + d_id * o_stride_d] =
68
+ src[offset_head + d_id * stride_d];
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ // template <typename scalar_t>
75
+ // __device__ void fused_rope_block_backward(const scalar_t *src, const float
76
+ // *freqs, scalar_t *dst,
77
+ // const int offset_block, const int
78
+ // offset_block_dst, const int h,
79
+ // const int d, const int d2, const
80
+ // int stride_h, const int stride_d,
81
+ // const int o_stride_h, const int
82
+ // o_stride_d) {
83
+ // int s_id = blockIdx.x;
84
+ // #pragma unroll
85
+ // for (int d_id = threadIdx.x; d_id < d2; d_id += blockDim.x) {
86
+ // float v_cos = cosf(freqs[s_id * d2 + d_id]);
87
+ // float v_sin = (d_id + d2 / 2 < d2) ? sinf(freqs[s_id * d2 + d_id + d2 /
88
+ // 2])
89
+ // : -sinf(freqs[s_id * d2 + d_id + d2 /
90
+ // 2 - d2]);
91
+ // #pragma unroll
92
+ // for (int h_id = threadIdx.y; h_id < h; h_id += blockDim.y) {
93
+ // int offset_src = offset_block + h_id * stride_h + d_id * stride_d;
94
+ // int offset_dst = offset_block_dst + h_id * o_stride_h + d_id *
95
+ // o_stride_d; float v_src = src[offset_src]; float v_src_rotate = (d_id +
96
+ // d2 / 2 < d2) ? src[offset_src + (d2 / 2) * stride_d]
97
+ // : src[offset_src + (d2 / 2 -
98
+ // d2) * stride_d];
99
+ // dst[offset_dst] = v_src * v_cos + v_src_rotate * v_sin;
100
+ // }
101
+ // }
102
+
103
+ // // handle the tail
104
+ // if (d > d2) {
105
+ // #pragma unroll
106
+ // for (int h_id = threadIdx.y; h_id < h; h_id += blockDim.y) {
107
+ // int offset_head = offset_block + h_id * stride_h;
108
+ // int offset_head_dst = offset_block_dst + h_id * o_stride_h;
109
+ // #pragma unroll
110
+ // for (int d_id = d2 + threadIdx.x; d_id < d; d_id += blockDim.x) {
111
+ // dst[offset_head_dst + d_id * o_stride_d] = src[offset_head + d_id *
112
+ // stride_d];
113
+ // }
114
+ // }
115
+ // }
116
+ // }
117
+
118
+ template <typename scalar_t>
119
+ __global__ void fused_rope_with_pos_forward_kernel(
120
+ const scalar_t *src, const float *freqs, scalar_t *dst, const int h,
121
+ const int d, const int d2, const int stride_s, const int stride_b,
122
+ const int stride_h, const int stride_d, const int o_stride_s,
123
+ const int o_stride_b, const int o_stride_h, const int o_stride_d) {
124
+ int s_id = blockIdx.x, b_id = blockIdx.y;
125
+ int offset_block = s_id * stride_s + b_id * stride_b;
126
+ int offset_block_dst = s_id * o_stride_s + b_id * o_stride_b;
127
+ fused_rope_with_pos_block_forward<scalar_t>(
128
+ src, freqs, dst, offset_block, offset_block_dst, h, d, d2, stride_h,
129
+ stride_d, o_stride_h, o_stride_d);
130
+ }
131
+
132
+ // template <typename scalar_t>
133
+ // __global__ void fused_rope_backward_kernel(const scalar_t *src, const float
134
+ // *freqs, scalar_t *dst,
135
+ // const int h, const int d, const
136
+ // int d2, const int stride_s, const
137
+ // int stride_b, const int stride_h,
138
+ // const int stride_d, const int
139
+ // o_stride_s, const int o_stride_b,
140
+ // const int o_stride_h, const int
141
+ // o_stride_d) {
142
+ // int s_id = blockIdx.x, b_id = blockIdx.y;
143
+ // int offset_block = s_id * stride_s + b_id * stride_b;
144
+ // int offset_block_dst = s_id * o_stride_s + b_id * o_stride_b;
145
+ // fused_rope_block_backward<scalar_t>(src, freqs, dst, offset_block,
146
+ // offset_block_dst, h, d, d2, stride_h,
147
+ // stride_d, o_stride_h, o_stride_d);
148
+ // }
149
+
150
+ template <typename scalar_t>
151
+ void fused_rope_with_pos_forward_launcher(
152
+ const scalar_t *input, const float *freqs, scalar_t *output, const int s,
153
+ const int b, const int h, const int d, const int d2, const int stride_s,
154
+ const int stride_b, const int stride_h, const int stride_d,
155
+ const int o_stride_s, const int o_stride_b, const int o_stride_h,
156
+ const int o_stride_d, cudaStream_t stream) {
157
+ int warps_per_block = h < 16 ? 4 : 8;
158
+ dim3 blocks(s, b);
159
+ dim3 threads(THREADS_PER_WARP, warps_per_block);
160
+
161
+ fused_rope_with_pos_forward_kernel<scalar_t><<<blocks, threads, 0, stream>>>(
162
+ input, freqs, output, h, d, d2, stride_s, stride_b, stride_h, stride_d,
163
+ o_stride_s, o_stride_b, o_stride_h, o_stride_d);
164
+ // NVTE_CHECK_CUDA(cudaGetLastError());
165
+ }
166
+
167
+ // template <typename scalar_t>
168
+ // void fused_rope_backward_launcher(const scalar_t *output_grads, const float
169
+ // *freqs,
170
+ // scalar_t *input_grads, const int s, const
171
+ // int b, const int h, const int d, const int
172
+ // d2, const int stride_s, const int stride_b,
173
+ // const int stride_h, const int stride_d,
174
+ // const int o_stride_s, const int o_stride_b,
175
+ // const int o_stride_h, const int o_stride_d,
176
+ // cudaStream_t stream) {
177
+ // int warps_per_block = h < 16 ? 4 : 8;
178
+ // dim3 blocks(s, b);
179
+ // dim3 threads(THREADS_PER_WARP, warps_per_block);
180
+
181
+ // fused_rope_backward_kernel<scalar_t><<<blocks, threads, 0, stream>>>(
182
+ // output_grads, freqs, input_grads, h, d, d2, stride_s, stride_b,
183
+ // stride_h, stride_d, o_stride_s, o_stride_b, o_stride_h, o_stride_d);
184
+ // // NVTE_CHECK_CUDA(cudaGetLastError());
185
+ // }
186
+
187
+ template <typename scalar_t>
188
+ void fused_rope_with_pos_forward(const at::Tensor &input,
189
+ const at::Tensor &freqs, at::Tensor &output,
190
+ const int s, const int b, const int h,
191
+ const int d, const int d2, const int stride_s,
192
+ const int stride_b, const int stride_h,
193
+ const int stride_d, const int o_stride_s,
194
+ const int o_stride_b, const int o_stride_h,
195
+ const int o_stride_d, cudaStream_t stream) {
196
+ // TRANSFORMER_ENGINE_TYPE_SWITCH_INPUT(
197
+ // input.data.dtype, scalar_t,
198
+ fused_rope_with_pos_forward_launcher<scalar_t>(
199
+ reinterpret_cast<const scalar_t *>(input.data_ptr()),
200
+ reinterpret_cast<const float *>(freqs.data_ptr()),
201
+ reinterpret_cast<scalar_t *>(output.data_ptr()), s, b, h, d, d2, stride_s,
202
+ stride_b, stride_h, stride_d, o_stride_s, o_stride_b, o_stride_h,
203
+ o_stride_d, stream);
204
+ // );
205
+ }
206
+
207
+ // template <typename scalar_t>
208
+ // void fused_rope_backward(const at::Tensor &output_grads, const at::Tensor
209
+ // &freqs, at::Tensor &input_grads,
210
+ // const int s, const int b, const int h, const int d,
211
+ // const int d2, const int stride_s, const int
212
+ // stride_b, const int stride_h, const int stride_d,
213
+ // const int o_stride_s, const int o_stride_b, const
214
+ // int o_stride_h, const int o_stride_d, cudaStream_t
215
+ // stream) {
216
+ // // TRANSFORMER_ENGINE_TYPE_SWITCH_INPUT(
217
+ // // output_grads.data.dtype, scalar_t,
218
+ // fused_rope_backward_launcher<scalar_t>(reinterpret_cast<const scalar_t
219
+ // *>(output_grads.data_ptr()),
220
+ // reinterpret_cast<const float
221
+ // *>(freqs.data_ptr()),
222
+ // reinterpret_cast<scalar_t
223
+ // *>(input_grads.data_ptr()), s, b, h, d,
224
+ // d2, stride_s, stride_b, stride_h,
225
+ // stride_d, o_stride_s, o_stride_b,
226
+ // o_stride_h, o_stride_d, stream);
227
+ // // );
228
+ // }
229
+
230
+ template <typename scalar_t>
231
+ void nvte_fused_rope_with_pos_forward(
232
+ const at::Tensor input, const at::Tensor freqs, at::Tensor output,
233
+ const int s, const int b, const int h, const int d, const int d2,
234
+ const int stride_s, const int stride_b, const int stride_h,
235
+ const int stride_d, const int o_stride_s, const int o_stride_b,
236
+ const int o_stride_h, const int o_stride_d, cudaStream_t stream) {
237
+ // NVTE_API_CALL(nvte_fused_rope_forward);
238
+ // using namespace transformer_engine;
239
+ fused_rope_with_pos_forward<scalar_t>(
240
+ input, freqs, output, s, b, h, d, d2, stride_s, stride_b, stride_h,
241
+ stride_d, o_stride_s, o_stride_b, o_stride_h, o_stride_d, stream);
242
+ }
243
+
244
+ // template <typename scalar_t>
245
+ // void nvte_fused_rope_backward(const at::Tensor output_grads, const at::Tensor
246
+ // freqs,
247
+ // at::Tensor input_grads, const int s, const int
248
+ // b, const int h, const int d, const int d2,
249
+ // const int stride_s, const int stride_b, const
250
+ // int stride_h, const int stride_d, const int
251
+ // o_stride_s, const int o_stride_b, const int
252
+ // o_stride_h, const int o_stride_d, cudaStream_t
253
+ // stream) {
254
+ // // NVTE_API_CALL(nvte_fused_rope_backward);
255
+ // // using namespace transformer_engine;
256
+ // fused_rope_backward<scalar_t>(output_grads, freqs, input_grads, s, b, h, d,
257
+ // d2, stride_s, stride_b,
258
+ // stride_h, stride_d, o_stride_s, o_stride_b, o_stride_h,
259
+ // o_stride_d, stream);
260
+ // }
261
+
262
+ // Interface for Python
263
+ at::Tensor fused_rope_with_pos_forward_func(
264
+ const at::Tensor &input, const at::Tensor &freqs,
265
+ const bool transpose_output_memory) {
266
+ // using namespace transformer_engine;
267
+ // TORCH_CHECK(input.dim() == 4, "expected 4D tensor");
268
+ // TORCH_CHECK(freqs.dim() == 4, "expected 4D tensor");
269
+ // TORCH_CHECK(input.size(0) <= freqs.size(0),
270
+ // "expected freqs tensor has a longer sequence length than
271
+ // input");
272
+ // TORCH_CHECK(freqs.size(1) == 1 && freqs.size(2) == 1,
273
+ // "expected the second and third dims of the freqs tensor equal
274
+ // 1");
275
+ // TORCH_CHECK(input.size(3) >= freqs.size(3),
276
+ // "expected the last dim of the input tensor equals or is "
277
+ // "greater than the freqs tensor");
278
+ // TORCH_CHECK(freqs.scalar_type() == at::ScalarType::Float,
279
+ // "Dtype of the freqs tensor must be float");
280
+
281
+ // input sizes: (s, b, h, d)
282
+ // s: sequence length
283
+ // b: batch size
284
+ // h: head num
285
+ // d: dim of each head
286
+ const int s = input.size(0);
287
+ const int b = input.size(1);
288
+ const int h = input.size(2);
289
+ const int d = input.size(3);
290
+ // input strides
291
+ const int stride_s = input.stride(0);
292
+ const int stride_b = input.stride(1);
293
+ const int stride_h = input.stride(2);
294
+ const int stride_d = input.stride(3);
295
+ // freqs' shape is always (s, 1, 1, d2), so the strides are same under
296
+ // different memory formats
297
+ // freqs' shape is now (B, S, D)
298
+ const int d2 = freqs.size(-1);
299
+
300
+ // output
301
+ auto act_options = input.options().requires_grad(false);
302
+ at::Tensor output;
303
+ if (transpose_output_memory) {
304
+ output = torch::empty({b, s, h, d}, act_options).transpose(0, 1);
305
+ } else {
306
+ output = torch::empty({s, b, h, d}, act_options);
307
+ }
308
+ // output strides
309
+ const int o_stride_s = output.stride(0);
310
+ const int o_stride_b = output.stride(1);
311
+ const int o_stride_h = output.stride(2);
312
+ const int o_stride_d = output.stride(3);
313
+
314
+ auto input_cu = input;
315
+ auto freqs_cu = freqs;
316
+ auto output_cu = output;
317
+
318
+ VLLM_DISPATCH_FLOATING_TYPES(
319
+ input.scalar_type(), "nvte_fused_rope_forward", [&] {
320
+ nvte_fused_rope_with_pos_forward<scalar_t>(
321
+ input_cu.data(), freqs_cu.data(), output_cu.data(), s, b, h, d, d2,
322
+ stride_s, stride_b, stride_h, stride_d, o_stride_s, o_stride_b,
323
+ o_stride_h, o_stride_d, at::cuda::getCurrentCUDAStream());
324
+ });
325
+
326
+ // nvte_fused_rope_forward<input.scalar_type()>(input_cu.data(),
327
+ // freqs_cu.data(), output_cu.data(), s, b, h, d, d2,
328
+ // stride_s, stride_b, stride_h, stride_d, o_stride_s,
329
+ // o_stride_b, o_stride_h, o_stride_d,
330
+ // at::cuda::getCurrentCUDAStream());
331
+
332
+ return output;
333
+ }
334
+
335
+ // // Interface for Python
336
+ // at::Tensor fused_rope_backward_func(const at::Tensor &output_grads, const
337
+ // at::Tensor &freqs,
338
+ // const bool transpose_output_memory) {
339
+ // // using namespace transformer_engine;
340
+ // // TORCH_CHECK(output_grads.dim() == 4, "expected 4D tensor");
341
+ // // TORCH_CHECK(freqs.dim() == 4, "expected 4D tensor");
342
+ // // TORCH_CHECK(output_grads.size(0) <= freqs.size(0),
343
+ // // "expected freqs tensor has a longer sequence length than
344
+ // output_grads");
345
+ // // TORCH_CHECK(freqs.size(1) == 1 && freqs.size(2) == 1,
346
+ // // "expected the second and third dims of the freqs tensor
347
+ // equal 1");
348
+ // // TORCH_CHECK(output_grads.size(3) >= freqs.size(3),
349
+ // // "expected the last dim of the output_grads tensor equals or
350
+ // is "
351
+ // // "greater than the freqs tensor");
352
+ // // TORCH_CHECK(freqs.scalar_type() == at::ScalarType::Float,
353
+ // // "Dtype of the freqs tensor must be float");
354
+
355
+ // // output_grads sizes: (s, b, h, d)
356
+ // // s: sequence length
357
+ // // b: batch size
358
+ // // h: head num
359
+ // // d: dim of each head
360
+ // const int s = output_grads.size(0);
361
+ // const int b = output_grads.size(1);
362
+ // const int h = output_grads.size(2);
363
+ // const int d = output_grads.size(3);
364
+ // // output_grads strides
365
+ // const int stride_s = output_grads.stride(0);
366
+ // const int stride_b = output_grads.stride(1);
367
+ // const int stride_h = output_grads.stride(2);
368
+ // const int stride_d = output_grads.stride(3);
369
+ // // freqs' shape is always (s, 1, 1, d2), so the strides are same under
370
+ // // different memory formats
371
+ // const int d2 = freqs.size(3);
372
+
373
+ // auto act_options = output_grads.options().requires_grad(false);
374
+ // at::Tensor input_grads;
375
+ // if (transpose_output_memory) {
376
+ // input_grads = torch::empty({b, s, h, d}, act_options).transpose(0, 1);
377
+ // } else {
378
+ // input_grads = torch::empty({s, b, h, d}, act_options);
379
+ // }
380
+ // const int o_stride_s = input_grads.stride(0);
381
+ // const int o_stride_b = input_grads.stride(1);
382
+ // const int o_stride_h = input_grads.stride(2);
383
+ // const int o_stride_d = input_grads.stride(3);
384
+
385
+ // auto output_grads_cu = output_grads;
386
+ // auto freqs_cu = freqs;
387
+ // auto input_grads_cu = input_grads;
388
+
389
+ // VLLM_DISPATCH_FLOATING_TYPES(
390
+ // output_grads.scalar_type(), "nvte_fused_rope_forward", [&] {
391
+ // nvte_fused_rope_backward<scalar_t>(output_grads_cu.data(),
392
+ // freqs_cu.data(), input_grads_cu.data(), s, b, h,
393
+ // d, d2, stride_s, stride_b, stride_h,
394
+ // stride_d, o_stride_s, o_stride_b,
395
+ // o_stride_h, o_stride_d,
396
+ // at::cuda::getCurrentCUDAStream());
397
+ // });
398
+
399
+ // // nvte_fused_rope_backward<float>(output_grads_cu.data(), freqs_cu.data(),
400
+ // input_grads_cu.data(), s, b, h,
401
+ // // d, d2, stride_s, stride_b, stride_h, stride_d,
402
+ // o_stride_s, o_stride_b,
403
+ // // o_stride_h, o_stride_d,
404
+ // at::cuda::getCurrentCUDAStream());
405
+
406
+ // return input_grads;
407
+ // }
llm-awq/awq/kernels/csrc/rope_new/fused_rope_with_pos.h ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include <torch/extension.h>
2
+
3
+ at::Tensor fused_rope_with_pos_forward_func(const at::Tensor &input,
4
+ const at::Tensor &freqs,
5
+ const bool transpose_output_memory);
llm-awq/awq/kernels/csrc/w8a8/act.cu ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <ATen/cuda/CUDAContext.h>
2
+ #include <torch/extension.h>
3
+ #include <cuda_fp16.h>
4
+
5
+ #include "dispatch_utils.h"
6
+ #include "utils.cuh"
7
+ #include "reduction_utils.cuh"
8
+
9
+ namespace vllm {
10
+
11
+ template <typename T> __device__ __forceinline__ T silu(const T &x) {
12
+ // x * sigmoid(x)
13
+ return (T)(((float)x) / (1.0f + expf((float)-x)));
14
+ }
15
+
16
+ template <typename T> __device__ __forceinline__ T gelu_new(const T &x) {
17
+ const half x3 = (half)(x * x * x);
18
+ const T t = (T)tanhf((T)((T)0.79788456f * (half)(x + (T)((T)0.044715f * x3))));
19
+ return ((T)0.5) * x * (((T)1.0) + t);
20
+ }
21
+
22
+ template <typename T>
23
+ __device__ __forceinline__ T gelu_fast(const T &x) {
24
+ const half f = (half)x;
25
+ const T t =
26
+ (T)tanhf(((T)(f * (T)0.79788456f)) * (((T)1.0) + (T)((T)0.044715f * f) * x));
27
+ return ((T)0.5) * x * (((T)1.0) + t);
28
+ }
29
+
30
+
31
+
32
+ // dequant int32 input, apply silu and mul, then per token quant to int8
33
+ template <typename scale_type, bool use_per_token_quant>
34
+ __global__ void gelu_and_quant_kernel(
35
+ int8_t *__restrict__ out, // [..., d]
36
+ half *__restrict__ input, // [..., d]
37
+ const int d,
38
+ scale_type * scale_out, // [num_tokens]
39
+ half *__restrict__ tmp = nullptr // [num_tokens, d]
40
+ ) {
41
+ const int token_idx = blockIdx.x;
42
+ const float max_value= 127.0f;
43
+ if constexpr (use_per_token_quant) {
44
+ float amax_val = 0.0f;
45
+ const half zero = 0.0001f;
46
+
47
+ for (int idx = threadIdx.x; idx < d; idx += blockDim.x) {
48
+ const half x =
49
+ (half)__ldg(&input[token_idx * d + idx]);
50
+ half t = gelu_fast(x);
51
+ tmp[token_idx * d + idx] = t;
52
+ t = t > zero ? t : -t;
53
+ if ((float)t > amax_val)
54
+ amax_val = (float)t;
55
+ }
56
+
57
+ __shared__ float s_amax;
58
+ const float block_amax_val = blockReduceMax(amax_val);
59
+ if (threadIdx.x == 0) {
60
+ s_amax = block_amax_val;
61
+ scale_out[token_idx] = half(block_amax_val / max_value);
62
+ }
63
+ __syncthreads();
64
+
65
+ float tmp_scale = max_value / s_amax;
66
+ for (int idx = threadIdx.x; idx < d; idx += blockDim.x) {
67
+ out[token_idx * d + idx] =
68
+ float_to_int8_rn((half)tmp_scale * tmp[token_idx * d + idx]);
69
+ }
70
+ } else {
71
+ for (int idx = threadIdx.x; idx < d; idx += blockDim.x) {
72
+ const float x =
73
+ (float)__ldg(&input[token_idx * d + idx]);
74
+ out[token_idx * d + idx] = float_to_int8_rn((half)gelu_fast(x) / scale_out[0]);
75
+ }
76
+ }
77
+ }
78
+ } // namespace vllm
79
+
80
+
81
+
82
+ void gelu_and_quant(
83
+ torch::Tensor &out, // [..., d]
84
+ torch::Tensor &input, // [..., d]
85
+ torch::Tensor &scale_out, // [...]
86
+ torch::Tensor &tmp // [num_tokens, d]
87
+ ) {
88
+ int64_t num_tokens = input.numel() / input.size(-1);
89
+ int d = input.size(-1);
90
+ dim3 grid(num_tokens);
91
+ dim3 block(std::min(d, 128));
92
+ const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
93
+ vllm::gelu_and_quant_kernel<half, true><<<grid, block, 0, stream>>>(
94
+ out.data_ptr<int8_t>(), reinterpret_cast<half *>(input.data_ptr<at::Half>()), d, reinterpret_cast<half *>(scale_out.data_ptr<at::Half>()),reinterpret_cast<half *>(tmp.data_ptr<at::Half>()));
95
+ }
96
+
97
+
98
+
99
+ namespace vllm {
100
+
101
+ template<typename scalar_t>
102
+ __global__ void silu_and_mul_kernel(
103
+ scalar_t* __restrict__ out, // [..., d]
104
+ const scalar_t* __restrict__ input, // [..., 2 * d]
105
+ const int d) {
106
+
107
+ const int token_idx = blockIdx.x;
108
+ const int64_t token_idx_d = token_idx * int64_t(d);
109
+ const int64_t token_idx_2d = token_idx_d * 2;
110
+ for (int idx = threadIdx.x; idx < d; idx += blockDim.x) {
111
+ const scalar_t x = __ldg(&input[token_idx_2d + idx]);
112
+ const scalar_t y = __ldg(&input[token_idx_2d + d + idx]);
113
+ out[token_idx_d + idx] = silu(x) * y;
114
+ }
115
+ }
116
+ } // namespace vllm
117
+
118
+
119
+
120
+ torch::Tensor silu_and_mul(
121
+ torch::Tensor& input) // [..., 2 * d]
122
+ {
123
+ int64_t num_tokens = input.numel() / input.size(-1);
124
+ int d = input.size(-1) / 2;
125
+
126
+ std::vector<int64_t> output_shape = input.sizes().vec();
127
+ output_shape[output_shape.size() - 1]=d;
128
+ auto options =
129
+ torch::TensorOptions().dtype(input.dtype()).device(input.device());
130
+ at::Tensor output = torch::empty(output_shape, options);
131
+
132
+
133
+ dim3 grid(num_tokens);
134
+ dim3 block(std::min(d, 256));
135
+ const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
136
+ VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "silu_and_mul_kernel", [&] {
137
+ vllm::silu_and_mul_kernel<scalar_t><<<grid, block, 0, stream>>>(
138
+ output.data_ptr<scalar_t>(), input.data_ptr<scalar_t>(), d);
139
+ });
140
+ return output;
141
+ }
llm-awq/awq/kernels/csrc/w8a8/act.h ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Inspired by TRT-LLM.
2
+ // Modified by Shang Yang and Haotian Tang.
3
+ // @article{lin2024awq,
4
+ // title={AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration},
5
+ // author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Chen, Wei-Ming and Wang, Wei-Chen and Xiao, Guangxuan and Dang, Xingyu and Gan, Chuang and Han, Song},
6
+ // journal={Proceedings of Machine Learning and Systems},
7
+ // volume={6},
8
+ // pages={87--100},
9
+ // year={2024}
10
+ // }
11
+
12
+ #include <torch/extension.h>
13
+ #include <cuda_fp16.h>
14
+ // Inspired by vLLM-SmoothQuant: https://github.com/vllm-project/vllm/pull/1112.
15
+ #include <torch/extension.h>
16
+
17
+
18
+ void gelu_and_quant(torch::Tensor &out, // [..., d]
19
+ torch::Tensor &input, // [..., d]
20
+ torch::Tensor &scale_out, // [num_tokens]
21
+ torch::Tensor &tmp // [num_tokens, d]
22
+ );
23
+
24
+ torch::Tensor silu_and_mul(torch::Tensor &input // [..., 2 * d]
25
+ );
26
+
27
+
28
+
29
+
llm-awq/awq/kernels/csrc/w8a8/dispatch_utils.h ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Adapted from
3
+ * https://github.com/pytorch/pytorch/blob/v2.0.1/aten/src/ATen/Dispatch.h
4
+ */
5
+ #include <torch/extension.h>
6
+
7
+ #define VLLM_DISPATCH_CASE_FLOATING_TYPES(...) \
8
+ AT_DISPATCH_CASE(at::ScalarType::Float, __VA_ARGS__) \
9
+ AT_DISPATCH_CASE(at::ScalarType::Half, __VA_ARGS__) \
10
+ AT_DISPATCH_CASE(at::ScalarType::BFloat16, __VA_ARGS__)
11
+
12
+ #define VLLM_DISPATCH_FLOATING_TYPES(TYPE, NAME, ...) \
13
+ AT_DISPATCH_SWITCH( \
14
+ TYPE, NAME, VLLM_DISPATCH_CASE_FLOATING_TYPES(__VA_ARGS__))
llm-awq/awq/kernels/csrc/w8a8/layernorm.cu ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Inspired by QServe https://github.com/mit-han-lab/qserve/tree/main.
2
+ // Modified by Yuming Lou.
3
+ // @article{lin2024awq,
4
+ // title={AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration},
5
+ // author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Chen, Wei-Ming and Wang, Wei-Chen and Xiao, Guangxuan and Dang, Xingyu and Gan, Chuang and Han, Song},
6
+ // journal={Proceedings of Machine Learning and Systems},
7
+ // volume={6},
8
+ // pages={87--100},
9
+ // year={2024}
10
+ // }
11
+ #include <ATen/cuda/CUDAContext.h>
12
+ #include <torch/extension.h>
13
+ #include "dispatch_utils.h"
14
+ #include "utils.cuh"
15
+ #include "reduction_utils.cuh"
16
+
17
+
18
+ namespace vllm {
19
+
20
+ // from TRTLLM
21
+ template <typename Tf, typename T>
22
+ __inline__ __device__ Tf compute_layernorm(Tf val, float s_mean, float s_variance, const T* gamma, const T* beta, int i)
23
+ {
24
+ Tf ret = (val - s_mean) * s_variance * cuda_cast<Tf>(gamma[i]);
25
+ if (beta != nullptr)
26
+ {
27
+ ret = ret + cuda_cast<Tf>(beta[i]);
28
+ }
29
+ return ret;
30
+ }
31
+
32
+ // from TRTLLM
33
+ /* Computes the layernorm https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html
34
+ * normed_output <- ( (input - E[input]) / Sqrt(Var[input] + eps) ) * gamma + beta
35
+ * input is [tokens, hidden_dim]. Mean and Variance are per-row (i.e. per-token)
36
+ *
37
+ * One CTA handles one row.
38
+ *
39
+ * with USE_DIFF_OF_SQUARES set to false:
40
+ * First pass (loop) computes the mean.
41
+ * Second computes the variance via Var[x] = E[(x - E[x])²].
42
+ * Third pass computes and writes normed_output
43
+ * For better speedup, we set USE_DIFF_OF_SQUARES to true (may be faster but less accurate):
44
+ * It turns out the accuracy dosen't drop.
45
+ * First pass (loop) computes the mean and variance via Var[x] = E[x²] - E[x]²
46
+ * Second pass computes and writes normed_output
47
+ *
48
+ *
49
+ * use_shmem controls if we cache input values into shared memory
50
+ *
51
+ * Optional: with dynamic scaling, the last pass doesn't write immediately but finds the
52
+ * amax per row. A final pass scales to int8 accordingly, and writes output to
53
+ * normed_output_quant.
54
+ */
55
+ template <typename T, typename scale_type, bool USE_DIFF_OF_SQUARES = true>
56
+ __global__ void generalLayerNorm(const T* input, const T* gamma, const T* beta, T* normed_output, const float eps,
57
+ int tokens, int hidden_dim, const scale_type* scale_orig_quant_per_tensor, scale_type* scale_orig_quant_per_token,
58
+ int8_t* normed_output_quant, bool use_shmem)
59
+ {
60
+ constexpr auto num_elems_T = num_elems<T>::value;
61
+ using int8_packed_t = typename packed_as<int8_t, num_elems_T>::type;
62
+ using float_packed_t = typename packed_as<float, num_elems_T>::type;
63
+ using T_scalar = typename packed_as<T, 1>::type;
64
+
65
+ extern __shared__ __align__(sizeof(float)) char _shmem[];
66
+ T* shmem = reinterpret_cast<T*>(_shmem);
67
+ __shared__ float s_mean;
68
+ __shared__ float s_variance;
69
+
70
+ const int tidx = threadIdx.x;
71
+ const int bidx = blockIdx.x;
72
+
73
+ float mean = 0.0f;
74
+ float variance = 0.0f;
75
+ float local_sum = 0.0f;
76
+ float local_var_sum = 0.0f;
77
+ const int n_elems = hidden_dim / num_elems_T;
78
+ for (int i = tidx; i < n_elems; i += blockDim.x)
79
+ {
80
+ const T val = input[bidx * n_elems + i];
81
+ if (use_shmem)
82
+ {
83
+ shmem[i] = val;
84
+ }
85
+ const float_packed_t val_f = cuda_cast<float_packed_t>(val);
86
+ local_sum += cuda_sum<float>(val_f);
87
+ if (USE_DIFF_OF_SQUARES)
88
+ {
89
+ local_var_sum += cuda_sum<float>(val_f * val_f);
90
+ }
91
+ }
92
+ //Compute mean
93
+ if (USE_DIFF_OF_SQUARES)
94
+ {
95
+ float packed[2] = {local_sum, local_var_sum};
96
+ blockReduceSumV2<float, 2>(packed);
97
+ mean = packed[0];
98
+ variance = packed[1];
99
+ }
100
+ else
101
+ {
102
+ mean = blockReduceSum(local_sum);
103
+ }
104
+
105
+ if (threadIdx.x == 0)
106
+ {
107
+ mean = mean / hidden_dim;
108
+ s_mean = mean;
109
+ if (USE_DIFF_OF_SQUARES)
110
+ {
111
+ variance = (variance / hidden_dim) - (mean * mean); // Var[x] = E[x²] - E[x]²
112
+ s_variance = rsqrtf(variance + eps);
113
+ }
114
+ }
115
+ __syncthreads();
116
+
117
+
118
+ if (!USE_DIFF_OF_SQUARES)
119
+ {
120
+ for (int i = tidx; i < n_elems; i += blockDim.x)
121
+ {
122
+ const T val = use_shmem ? shmem[i] : input[bidx * n_elems + i];
123
+ float_packed_t diff = cuda_cast<float_packed_t>(val); // - s_mean;
124
+ local_var_sum += cuda_sum<float>(diff * diff);
125
+ }
126
+ variance = blockReduceSum(local_var_sum);
127
+
128
+ if (threadIdx.x == 0)
129
+ {
130
+ s_variance = rsqrtf(variance / hidden_dim + eps);
131
+ }
132
+ __syncthreads();
133
+ }
134
+
135
+ // Compute LN and Quantize
136
+ const bool with_per_token_scaling = scale_orig_quant_per_token != nullptr;
137
+ const bool with_per_tensor_scaling = scale_orig_quant_per_tensor != nullptr;
138
+ const float_packed_t scale_orig_quant
139
+ = cuda_cast<float_packed_t>(with_per_tensor_scaling ? __half2float(*scale_orig_quant_per_tensor) : 0.0f);
140
+ T_scalar amax = 1e-6f;
141
+
142
+ for (int i = tidx; i < n_elems; i += blockDim.x)
143
+ {
144
+ const int index = bidx * n_elems + i;
145
+ const float_packed_t val_f = cuda_cast<float_packed_t>(use_shmem ? shmem[i] : input[index]);
146
+ const T val = cuda_cast<T>(compute_layernorm(val_f, s_mean, s_variance, gamma, beta, i));
147
+
148
+ if (with_per_token_scaling)
149
+ {
150
+ amax = cuda_max(cuda_max<T_scalar, T>(cuda_abs(val)), amax);
151
+ if (use_shmem)
152
+ {
153
+ shmem[i] = val;
154
+ }
155
+ }
156
+ else if (with_per_tensor_scaling)
157
+ {
158
+ reinterpret_cast<int8_packed_t*>(normed_output_quant)[index]
159
+ = cuda_cast<int8_packed_t>(cuda_cast<float_packed_t>(val) * scale_orig_quant);
160
+ }
161
+ else
162
+ {
163
+ normed_output[index] = val;
164
+ }
165
+ }
166
+
167
+ if (with_per_token_scaling)
168
+ {
169
+ float abs_max_f = blockAllReduceMax(cuda_cast<float>(amax));
170
+ const float dynamic_per_token_scale = 127.f / abs_max_f;
171
+ for (int i = tidx; i < n_elems; i += blockDim.x)
172
+ {
173
+ const int index = bidx * n_elems + i;
174
+ float_packed_t val_f = cuda_cast<float_packed_t>(use_shmem ? shmem[i] : input[index]);
175
+ if (!use_shmem)
176
+ {
177
+ val_f = compute_layernorm(val_f, s_mean, s_variance, gamma, beta, i);
178
+ }
179
+
180
+ reinterpret_cast<int8_packed_t*>(normed_output_quant)[index]
181
+ = cuda_cast<int8_packed_t>(val_f * cuda_cast<float_packed_t>(dynamic_per_token_scale));
182
+ }
183
+ if (tidx == 0)
184
+ {
185
+ scale_orig_quant_per_token[bidx] = abs_max_f / 127.f;
186
+ }
187
+ }
188
+ }
189
+
190
+
191
+ } // namespace vllm
192
+
193
+ void rms_norm_general(torch::Tensor &out, // [..., hidden_size]
194
+ torch::Tensor &input, // [..., hidden_size]
195
+ torch::Tensor &weight, // [hidden_size]
196
+ torch::Tensor &bias, // [hidden_size]
197
+ torch::Tensor &scaling, // [tokens] or [1]
198
+ float epsilon,
199
+ bool use_per_token_quant = true) {
200
+ int hidden_size = input.size(-1);
201
+ int num_tokens = input.numel() / hidden_size;
202
+ dim3 grid(num_tokens);
203
+ dim3 block(std::min(hidden_size, 128));//Reduce the idle probability of threads
204
+ block.x = 32 * ((block.x + 31) / 32);
205
+
206
+ const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
207
+ VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "generalLayerNorm", [&] {
208
+ using T = typename FloatTypeConverter<scalar_t>::Type;
209
+ if (use_per_token_quant) {
210
+ // per-token
211
+ vllm::generalLayerNorm<T, at::Half><<<grid, block, 0, stream>>>(
212
+ reinterpret_cast<T*>(input.data_ptr<scalar_t>()),
213
+ reinterpret_cast<T*>(weight.data_ptr<scalar_t>()),
214
+ reinterpret_cast<T*>(bias.data_ptr<scalar_t>()),
215
+ nullptr, epsilon, num_tokens, hidden_size, nullptr, scaling.data_ptr<at::Half>(),
216
+ out.data_ptr<int8_t>(), false
217
+ );
218
+ // input, gamma, beta, normed_output, eps, tokens, hidden_dim, per_tensor_scale, per_token_scale
219
+ // normed_output_quant, use_shmem
220
+ // out.data_ptr<int8_t>(), input.data_ptr<scalar_t>(),
221
+ // weight.data_ptr<scalar_t>(), epsilon, num_tokens, hidden_size);
222
+ } else {
223
+ // per-tensor
224
+ vllm::generalLayerNorm<T, at::Half><<<grid, block, 0, stream>>>(
225
+ reinterpret_cast<T*>(input.data_ptr<scalar_t>()),
226
+ reinterpret_cast<T*>(weight.data_ptr<scalar_t>()), nullptr,
227
+ nullptr, epsilon, num_tokens, hidden_size, scaling.data_ptr<at::Half>(), nullptr,
228
+ out.data_ptr<int8_t>(), false
229
+ );
230
+ }
231
+ });
232
+ }
llm-awq/awq/kernels/csrc/w8a8/layernorm.h ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Inspired by TRT-LLM.
2
+ // Modified by Shang Yang and Haotian Tang.
3
+ // @article{lin2024awq,
4
+ // title={AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration},
5
+ // author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Chen, Wei-Ming and Wang, Wei-Chen and Xiao, Guangxuan and Dang, Xingyu and Gan, Chuang and Han, Song},
6
+ // journal={Proceedings of Machine Learning and Systems},
7
+ // volume={6},
8
+ // pages={87--100},
9
+ // year={2024}
10
+ // }
11
+
12
+ #include <torch/extension.h>
13
+ #include <cuda_fp16.h>
14
+ void rms_norm_general(torch::Tensor &out, // [..., hidden_size]
15
+ torch::Tensor &input, // [..., hidden_size]
16
+ torch::Tensor &weight, // [hidden_size]
17
+ torch::Tensor &bias, // [hidden_size]
18
+ torch::Tensor &scaling, // [tokens] or [1]
19
+ float epsilon,
20
+ bool use_per_token_quant);
21
+
llm-awq/awq/kernels/csrc/w8a8/quantization.cu ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Inspired by vLLM-SmoothQuant: https://github.com/vllm-project/vllm/pull/1112 and TensorRT-LLM.
2
+ // Modified by Shang Yang and Haotian Tang.
3
+ // @article{lin2024awq,
4
+ // title={AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration},
5
+ // author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Chen, Wei-Ming and Wang, Wei-Chen and Xiao, Guangxuan and Dang, Xingyu and Gan, Chuang and Han, Song},
6
+ // journal={Proceedings of Machine Learning and Systems},
7
+ // volume={6},
8
+ // pages={87--100},
9
+ // year={2024}
10
+ // }
11
+ #include <ATen/cuda/CUDAContext.h>
12
+ #include <torch/extension.h>
13
+
14
+ #include "utils.cuh"
15
+ #include <cuda_fp16.h>
16
+ #include <cassert>
17
+ #include "quantization.h"
18
+
19
+ #define VLLM_DISPATCH_CASE_FLOATING_TYPES(...) \
20
+ AT_DISPATCH_CASE(at::ScalarType::Float, __VA_ARGS__) \
21
+ AT_DISPATCH_CASE(at::ScalarType::Half, __VA_ARGS__) \
22
+ AT_DISPATCH_CASE(at::ScalarType::BFloat16, __VA_ARGS__)
23
+ #define VLLM_DISPATCH_FLOATING_TYPES(TYPE, NAME, ...) AT_DISPATCH_SWITCH(TYPE, NAME, VLLM_DISPATCH_CASE_FLOATING_TYPES(__VA_ARGS__))
24
+
25
+ template<typename T>
26
+ __inline__ __device__ T warpReduceMax(T val)
27
+ {
28
+ #pragma unroll
29
+ for (int mask = 16; mask > 0; mask >>= 1)
30
+ val = max(val, __shfl_xor_sync(0xffffffff, val, mask, 32));
31
+ return val;
32
+ }
33
+
34
+ /* Calculate the maximum of all elements in a block */
35
+ template<typename T>
36
+ __inline__ __device__ T blockReduceMax(T val)
37
+ {
38
+ static __shared__ T shared[32];
39
+ int lane = threadIdx.x & 0x1f; // in-warp idx
40
+ int wid = threadIdx.x >> 5; // warp idx
41
+ val = warpReduceMax(val); // get maxx in each warp
42
+ if (lane == 0) // record in-warp maxx by warp Idx
43
+ shared[wid] = val;
44
+ __syncthreads();
45
+ // Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
46
+ // blockDim.x is not divided by 32
47
+ val = (threadIdx.x < (blockDim.x / 32.f)) ? shared[lane] : -1e20f;
48
+ val = warpReduceMax(val);
49
+ return val;
50
+ }
51
+
52
+
53
+
54
+ namespace vllm {
55
+ template <typename T, typename scale_type, bool use_per_token_quant>
56
+ __global__ void quant_kernel(const T *__restrict__ input,
57
+ int8_t *__restrict__ output, scale_type scale,
58
+ int num_tokens, int hidden_size) {
59
+ const int tid = threadIdx.x;
60
+ const int token_idx = blockIdx.x;
61
+
62
+ if constexpr (use_per_token_quant) {
63
+ float amax_val = 0.0f;
64
+ const float zero = 0.0f;
65
+
66
+ for (int i = tid; i < hidden_size; i += blockDim.x) {
67
+ float val = (float)input[token_idx * hidden_size + i];
68
+ val = val > zero ? val : -val;
69
+ if (val > amax_val)
70
+ amax_val = val;
71
+ }
72
+
73
+ __shared__ float s_amax;
74
+ const float block_amax_val = blockReduceMax(amax_val);
75
+ if (tid == 0) {
76
+ s_amax = block_amax_val;
77
+ scale[token_idx] = __float2half_rn(block_amax_val / 127.0f);
78
+ }
79
+ __syncthreads();
80
+
81
+ float tmp_scale = 127.0f / s_amax;
82
+ for (int i = tid; i < hidden_size; i += blockDim.x) {
83
+ output[token_idx * hidden_size + i] =
84
+ float_to_int8_rn(((float)input[token_idx * hidden_size + i]) * tmp_scale);
85
+ }
86
+ } else {
87
+ for (int i = tid; i < hidden_size; i += blockDim.x) {
88
+ output[token_idx * hidden_size + i] =
89
+ float_to_int8_rn(((float)input[token_idx * hidden_size + i]) / __half2float(scale));
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+
96
+
97
+ void invoke_quant(torch::Tensor &out, // [..., hidden_size]
98
+ torch::Tensor &input, // [..., hidden_size]
99
+ torch::Tensor &scale) { // [num_tokens]
100
+ assert(input.is_contiguous());
101
+ assert(out.is_contiguous());
102
+ int hidden_size = input.size(-1);
103
+ int num_tokens = input.numel() / hidden_size;
104
+ dim3 grid(num_tokens);
105
+ dim3 block(std::min(hidden_size, 1024));
106
+ const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
107
+ VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "quant_kernel", [&] {
108
+ vllm::quant_kernel<scalar_t, at::Half *, true><<<grid, block, 0, stream>>>(
109
+ input.data_ptr<scalar_t>(), out.data_ptr<int8_t>(),
110
+ scale.data_ptr<at::Half>(), num_tokens, hidden_size);
111
+ });
112
+ }
113
+
llm-awq/awq/kernels/csrc/w8a8/quantization.h ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #include <torch/extension.h>
2
+ void invoke_quant(torch::Tensor &out, // [..., hidden_size]
3
+ torch::Tensor &input, // [..., hidden_size]
4
+ torch::Tensor &scale); // [num_tokens]
llm-awq/awq/kernels/csrc/w8a8/utils.cuh ADDED
@@ -0,0 +1,469 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Adated from FasterTransformer, https://github.com/NVIDIA/FasterTransformer/blob/release/v5.3_tag/src/fastertransformer/kernels/decoder_masked_multihead_attention/decoder_masked_multihead_attention_template.hpp
2
+ // Modified by Haotian Tang
3
+ #pragma once
4
+
5
+ #include <assert.h>
6
+ #include <stdint.h>
7
+ #include <float.h>
8
+ #include <type_traits>
9
+ #include <torch/extension.h>
10
+
11
+ template <typename T>
12
+ struct FloatTypeConverter
13
+ {
14
+ using Type = T;
15
+ };
16
+
17
+ template <>
18
+ struct FloatTypeConverter<at::Half>
19
+ {
20
+ using Type = half;
21
+ };
22
+
23
+ template <>
24
+ struct FloatTypeConverter<at::BFloat16>
25
+ {
26
+ using Type = __nv_bfloat16;
27
+ };
28
+
29
+ template <>
30
+ struct FloatTypeConverter<float>
31
+ {
32
+ using Type = float;
33
+ };
34
+
35
+
36
+
37
+ template<typename T> struct num_elems;
38
+ template <> struct num_elems<float> { static constexpr int value = 1; };
39
+ template <> struct num_elems<float2> { static constexpr int value = 2; };
40
+ template <> struct num_elems<float4> { static constexpr int value = 4; };
41
+ template <> struct num_elems<half> { static constexpr int value = 1; };
42
+ template <> struct num_elems<half2> { static constexpr int value = 2; };
43
+ #ifdef ENABLE_BF16
44
+ template <> struct num_elems<__nv_bfloat16> { static constexpr int value = 1; };
45
+ template <> struct num_elems<__nv_bfloat162> { static constexpr int value = 2; };
46
+ #endif
47
+ #ifdef ENABLE_FP8
48
+ template <> struct num_elems<__nv_fp8_e4m3> { static constexpr int value = 1; };
49
+ template <> struct num_elems<__nv_fp8x2_e4m3> { static constexpr int value = 2; };
50
+ #endif
51
+
52
+ template<typename T, int num> struct packed_as;
53
+ template<typename T> struct packed_as<T, 1> { using type = T; };
54
+ template<> struct packed_as<half, 2> { using type = half2; };
55
+ template<> struct packed_as<float, 2> { using type = float2; };
56
+ template<> struct packed_as<int8_t, 2> { using type = int16_t; };
57
+ template<> struct packed_as<int32_t, 2> { using type = int2; };
58
+ template<> struct packed_as<half2, 1> { using type = half; };
59
+ template<> struct packed_as<float2, 1> { using type = float; };
60
+ #ifdef ENABLE_BF16
61
+ template<> struct packed_as<__nv_bfloat16, 2> { using type = __nv_bfloat162; };
62
+ template<> struct packed_as<__nv_bfloat162, 1> { using type = __nv_bfloat16; };
63
+ #endif
64
+ #ifdef ENABLE_FP8
65
+ template<> struct packed_as<__nv_fp8_e4m3, 2> { using type = __nv_fp8x2_e4m3; };
66
+ template<> struct packed_as<__nv_fp8x2_e4m3, 1> { using type = __nv_fp8_e4m3; };
67
+ template<> struct packed_as<__nv_fp8_e5m2, 2> { using type = __nv_fp8x2_e5m2; };
68
+ template<> struct packed_as<__nv_fp8x2_e5m2, 1> { using type = __nv_fp8_e5m2; };
69
+ #endif
70
+
71
+ inline __device__ float2 operator*(float2 a, float2 b) { return make_float2(a.x * b.x, a.y * b.y); }
72
+ inline __device__ float2 operator+(float2 a, float2 b) { return make_float2(a.x + b.x, a.y + b.y); }
73
+ inline __device__ float2 operator-(float2 a, float2 b) { return make_float2(a.x - b.x, a.y - b.y); }
74
+
75
+ inline __device__ float2 operator*(float2 a, float b) { return make_float2(a.x * b, a.y * b); }
76
+ inline __device__ float2 operator+(float2 a, float b) { return make_float2(a.x + b, a.y + b); }
77
+ inline __device__ float2 operator-(float2 a, float b) { return make_float2(a.x - b, a.y - b); }
78
+
79
+ static inline __device__ int8_t float_to_int8_rn(float x)
80
+ {
81
+ uint32_t dst;
82
+ asm volatile("cvt.rni.sat.s8.f32 %0, %1;" : "=r"(dst) : "f"(x));
83
+ return reinterpret_cast<const int8_t&>(dst);
84
+ }
85
+
86
+ template<typename T>
87
+ inline __device__ T ldg(const T* val) {
88
+ return __ldg(val);
89
+ }
90
+
91
+ #if ENABLE_BF16
92
+ #define bf1622float2 __bfloat1622float2
93
+ #define float22bf162 __float22bfloat162_rn
94
+ #define bf162bf162 __bfloat162bfloat162
95
+ inline __device__ int16_t bf1622int16(__nv_bfloat162 val)
96
+ {
97
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 800
98
+ float2 f_val;
99
+ f_val.x = max(min(__low2float(val), 127.f), -128.f);
100
+ f_val.y = max(min(__high2float(val), 127.f), -128.f);
101
+
102
+ union
103
+ {
104
+ int8_t int8[2];
105
+ int16_t int16;
106
+ };
107
+
108
+ int8[0] = static_cast<int8_t>(static_cast<short>(f_val.x));
109
+ int8[1] = static_cast<int8_t>(static_cast<short>(f_val.y));
110
+ return int16;
111
+ #else
112
+ val = __hmin2(val, make_bfloat162(127., 127.));
113
+ val = __hmax2(val, make_bfloat162(-128., -128.));
114
+
115
+ union
116
+ {
117
+ int8_t int8[2];
118
+ int16_t int16;
119
+ };
120
+
121
+ int8[0] = static_cast<int8_t>(static_cast<short>(val.x));
122
+ int8[1] = static_cast<int8_t>(static_cast<short>(val.y));
123
+ return int16;
124
+ #endif
125
+ }
126
+ #endif
127
+
128
+ #if ENABLE_BF16
129
+ template<>
130
+ inline __device__ __nv_bfloat162 ldg(const __nv_bfloat162* val) {
131
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 800
132
+ return val[0];
133
+ #else
134
+ return __ldg(val);
135
+ #endif
136
+ }
137
+
138
+ template<>
139
+ inline __device__ __nv_bfloat16 ldg(const __nv_bfloat16* val) {
140
+ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 800
141
+ return val[0];
142
+ #else
143
+ return __ldg(val);
144
+ #endif
145
+ }
146
+ #endif // ENABLE_BF16
147
+
148
+ template <typename T_OUT, typename T_IN>
149
+ __device__ inline T_OUT cuda_cast(T_IN val)
150
+ {
151
+ return val;
152
+ }
153
+
154
+ template <>
155
+ __device__ inline float2 cuda_cast<float2, int2>(int2 val)
156
+ {
157
+ return make_float2(val.x, val.y);
158
+ }
159
+
160
+ template <>
161
+ __device__ inline float2 cuda_cast<float2, float>(float val)
162
+ {
163
+ return make_float2(val, val);
164
+ }
165
+
166
+ template <>
167
+ __device__ inline float2 cuda_cast<float2, half2>(half2 val)
168
+ {
169
+ return __half22float2(val);
170
+ }
171
+
172
+ template <>
173
+ __device__ inline half2 cuda_cast<half2, float2>(float2 val)
174
+ {
175
+ return __float22half2_rn(val);
176
+ }
177
+
178
+ template <>
179
+ __device__ inline half2 cuda_cast<half2, float>(float val)
180
+ {
181
+ return __float2half2_rn(val);
182
+ }
183
+
184
+ template <>
185
+ __device__ inline half2 cuda_cast<half2, half>(half val)
186
+ {
187
+ return __half2half2(val);
188
+ }
189
+
190
+ template <>
191
+ __device__ inline int8_t cuda_cast<int8_t, half>(half val)
192
+ {
193
+ union
194
+ {
195
+ int8_t int8[2];
196
+ int16_t int16;
197
+ };
198
+
199
+ union
200
+ {
201
+ half fp16;
202
+ int16_t int16_in;
203
+ };
204
+
205
+ fp16 = val;
206
+ asm volatile("cvt.rni.sat.s8.f16 %0, %1;" : "=h"(int16) : "h"(int16_in));
207
+ return int8[0];
208
+ }
209
+
210
+ template <>
211
+ __device__ inline int16_t cuda_cast<int16_t, half2>(half2 val)
212
+ {
213
+ union
214
+ {
215
+ int8_t int8[2];
216
+ int16_t int16;
217
+ };
218
+
219
+ int8[0] = cuda_cast<int8_t>(val.x);
220
+ int8[1] = cuda_cast<int8_t>(val.y);
221
+ return int16;
222
+ }
223
+
224
+ template <>
225
+ __device__ inline int8_t cuda_cast<int8_t, float>(float val)
226
+ {
227
+ union
228
+ {
229
+ int8_t int8[2];
230
+ int16_t int16;
231
+ };
232
+
233
+ asm volatile("cvt.rni.sat.s8.f32 %0, %1;" : "=h"(int16) : "f"(val));
234
+ return int8[0];
235
+ }
236
+
237
+ template <>
238
+ __device__ inline int16_t cuda_cast<int16_t, float2>(float2 val)
239
+ {
240
+ union
241
+ {
242
+ int8_t int8[2];
243
+ int16_t int16;
244
+ };
245
+
246
+ int8[0] = cuda_cast<int8_t>(val.x);
247
+ int8[1] = cuda_cast<int8_t>(val.y);
248
+ return int16;
249
+ }
250
+
251
+ template <>
252
+ __device__ inline half2 cuda_cast<half2, int16_t>(int16_t val)
253
+ {
254
+ union
255
+ {
256
+ int8_t int8[2];
257
+ int16_t int16;
258
+ };
259
+
260
+ int16 = val;
261
+ return make_half2(int8[0], int8[1]);
262
+ }
263
+
264
+ template <>
265
+ __device__ inline float2 cuda_cast<float2, int16_t>(int16_t val)
266
+ {
267
+ union
268
+ {
269
+ int8_t int8[2];
270
+ int16_t int16;
271
+ };
272
+
273
+ int16 = val;
274
+ return make_float2(int8[0], int8[1]);
275
+ }
276
+
277
+ #ifdef ENABLE_BF16
278
+ template <>
279
+ __device__ inline __nv_bfloat16 cuda_cast(int32_t val)
280
+ {
281
+ return static_cast<float>(val);
282
+ }
283
+
284
+ template <>
285
+ __device__ inline __nv_bfloat16 cuda_cast(int8_t val)
286
+ {
287
+ return static_cast<float>(val);
288
+ }
289
+
290
+ template <>
291
+ __device__ inline int8_t cuda_cast(__nv_bfloat16 val)
292
+ {
293
+ return static_cast<float>(val);
294
+ }
295
+
296
+ template <>
297
+ __device__ inline float cuda_cast<float, __nv_bfloat16>(__nv_bfloat16 val)
298
+ {
299
+ return __bfloat162float(val);
300
+ }
301
+
302
+ template <>
303
+ __device__ inline float2 cuda_cast<float2, __nv_bfloat162>(__nv_bfloat162 val)
304
+ {
305
+ return bf1622float2(val);
306
+ }
307
+
308
+ template <>
309
+ __device__ inline half cuda_cast<half, __nv_bfloat16>(__nv_bfloat16 val)
310
+ {
311
+ return __float2half(__bfloat162float(val));
312
+ }
313
+
314
+ template <>
315
+ __device__ inline int16_t cuda_cast<int16_t, __nv_bfloat162>(__nv_bfloat162 val)
316
+ {
317
+ return bf1622int16(val);
318
+ }
319
+
320
+ template <>
321
+ __device__ inline __nv_bfloat16 cuda_cast<__nv_bfloat16, float>(float val)
322
+ {
323
+ return __float2bfloat16(val);
324
+ }
325
+
326
+ template <>
327
+ __device__ inline __nv_bfloat16 cuda_cast<__nv_bfloat16, half>(half val)
328
+ {
329
+ return __float2bfloat16(__half2float(val));
330
+ }
331
+
332
+ template <>
333
+ __device__ inline __nv_bfloat162 cuda_cast<__nv_bfloat162, __nv_bfloat16>(__nv_bfloat16 val)
334
+ {
335
+ return bf162bf162(val);
336
+ }
337
+
338
+ template <>
339
+ __device__ inline __nv_bfloat162 cuda_cast<__nv_bfloat162, float>(float val)
340
+ {
341
+ return __float2bfloat162_rn(val);
342
+ }
343
+
344
+ template <>
345
+ __device__ inline __nv_bfloat162 cuda_cast<__nv_bfloat162, float2>(float2 val)
346
+ {
347
+ return float22bf162(val);
348
+ }
349
+
350
+ template <>
351
+ __device__ inline __nv_bfloat162 cuda_cast<__nv_bfloat162, int16_t>(int16_t val)
352
+ {
353
+ union
354
+ {
355
+ int8_t int8[2];
356
+ int16_t int16;
357
+ };
358
+
359
+ int16 = val;
360
+ __nv_bfloat162 res;
361
+ res.x = cuda_cast<__nv_bfloat16>(int8[0]);
362
+ res.y = cuda_cast<__nv_bfloat16>(int8[1]);
363
+ return res;
364
+ }
365
+
366
+ template <>
367
+ __device__ inline __nv_bfloat162 cuda_cast<__nv_bfloat162, half2>(half2 val)
368
+ {
369
+ return float22bf162(__half22float2(val));
370
+ }
371
+
372
+ #endif // ENABLE BF16
373
+
374
+ template <typename To, typename Ti>
375
+ __device__ inline To cuda_sum(Ti val)
376
+ {
377
+ return cuda_cast<To>(val);
378
+ };
379
+
380
+ template <typename To>
381
+ __device__ inline To cuda_sum(float2 val)
382
+ {
383
+ return cuda_cast<To>(val.x + val.y);
384
+ };
385
+
386
+ // Unary maximum: compute the max of a vector type
387
+ template <typename To, typename Ti>
388
+ __device__ inline To cuda_max(Ti val)
389
+ {
390
+ return cuda_cast<To>(val);
391
+ };
392
+
393
+ template <>
394
+ __device__ inline float cuda_max(float2 val)
395
+ {
396
+ return fmaxf(val.x, val.y);
397
+ }
398
+
399
+ template <>
400
+ __device__ inline half cuda_max(half2 val)
401
+ {
402
+ return __hmax(val.x, val.y);
403
+ }
404
+
405
+ #ifdef ENABLE_BF16
406
+ template <>
407
+ __device__ inline __nv_bfloat16 cuda_max(__nv_bfloat162 val)
408
+ {
409
+ #if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800))
410
+ return __hmax(val.x, val.y);
411
+ #endif
412
+ }
413
+ #endif
414
+
415
+ // Binary maximum: compute the max of two scalar types
416
+ template <typename T>
417
+ __device__ inline T cuda_max(T val1, T val2)
418
+ {
419
+ return (val1 > val2) ? val1 : val2;
420
+ }
421
+
422
+ template <typename T>
423
+ __device__ inline T cuda_abs(T val)
424
+ {
425
+ assert(false);
426
+ return {};
427
+ }
428
+
429
+ template <>
430
+ __device__ inline float cuda_abs(float val)
431
+ {
432
+ return fabs(val);
433
+ }
434
+
435
+ template <>
436
+ __device__ inline float2 cuda_abs(float2 val)
437
+ {
438
+ return make_float2(fabs(val.x), fabs(val.y));
439
+ }
440
+
441
+ template <>
442
+ __device__ inline half cuda_abs(half val)
443
+ {
444
+ return __habs(val);
445
+ }
446
+
447
+ template <>
448
+ __device__ inline half2 cuda_abs(half2 val)
449
+ {
450
+ return __habs2(val);
451
+ }
452
+
453
+ #ifdef ENABLE_BF16
454
+
455
+ #if __CUDA_ARCH__ >= 800 || !defined(__CUDA_ARCH__)
456
+ template <>
457
+ __device__ inline __nv_bfloat16 cuda_abs(__nv_bfloat16 val)
458
+ {
459
+ return __habs(val);
460
+ }
461
+
462
+ template <>
463
+ __device__ inline __nv_bfloat162 cuda_abs(__nv_bfloat162 val)
464
+ {
465
+ return __habs2(val);
466
+ }
467
+ #endif
468
+
469
+ #endif // ENABLE_FP16
llm-awq/awq/kernels/csrc/w8a8/w8a8_gemm_cuda.cu ADDED
@@ -0,0 +1,953 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Inspired by QServe https://github.com/mit-han-lab/qserve/tree/main.
2
+ // Modified by Yuming Lou.
3
+ // @article{lin2024awq,
4
+ // title={AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration},
5
+ // author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Chen, Wei-Ming and Wang, Wei-Chen and Xiao, Guangxuan and Dang, Xingyu and Gan, Chuang and Han, Song},
6
+ // journal={Proceedings of Machine Learning and Systems},
7
+ // volume={6},
8
+ // pages={87--100},
9
+ // year={2024}
10
+ // }
11
+
12
+ #include "w8a8_gemm_cuda.h"
13
+ #include <cuda_fp16.h>
14
+ #include <cuda_pipeline_primitives.h>
15
+ #include <torch/extension.h>
16
+
17
+ #define OP_M 16
18
+ #define OP_N 8
19
+ #define OP_K 32
20
+ #define INTRIN_M 16
21
+ #define INTRIN_N 16
22
+ #define INTRIN_K 32
23
+ #define WARP_SIZE 32
24
+ #define SMEM_PAD_A 0
25
+ #define SMEM_PAD_B 0
26
+ #define PACK_SIZE 16
27
+ #if (__CUDACC_VER_MAJOR__ >= 11) && (__CUDACC_VER_MINOR__ >= 4)
28
+ #define L2_CACHEHINT(size) ".L2::" #size "B"
29
+ #else
30
+ #define L2_CACHEHINT(size)
31
+ #endif
32
+ #define KERNEL_LAUNCH_CODE_FUSE_BIAS \
33
+ constexpr int NUM_WARPS = (CTA_M / WARP_M) * (CTA_N / WARP_N) * (CTA_K / WARP_K); \
34
+ constexpr int kSmemByteSize = \
35
+ (CTA_M * (CTA_K + SMEM_PAD_A) + CTA_N * (CTA_K + SMEM_PAD_B)) * STAGES * \
36
+ sizeof(int8_t) + CTA_N * sizeof(float); \
37
+ if (kSmemByteSize >= 99 * 1024) \
38
+ { \
39
+ printf("This kernel requires %d Bytes of shared memory, which exceeds " \
40
+ "device limit.\n", \
41
+ kSmemByteSize); \
42
+ return ; \
43
+ } \
44
+ int num_blocks_m = (num_out_feats + CTA_M - 1) / CTA_M; \
45
+ int num_blocks_n = (num_out_channels+ CTA_N - 1) / CTA_N / 1; \
46
+ const int log_tile = get_log_tile<8>((num_out_feats + CTA_M - 1) / CTA_M); \
47
+ const int tile_shift = 1 << log_tile; \
48
+ dim3 num_blocks(num_blocks_n *tile_shift, \
49
+ (num_blocks_m + tile_shift - 1) / tile_shift); \
50
+ dim3 threads_per_block(WARP_SIZE, NUM_WARPS); \
51
+ auto kernel_func = \
52
+ dense_kernel0_fuse_bias<CTA_M, CTA_N, CTA_K, WARP_M, WARP_N, WARP_K, STAGES>; \
53
+ cudaFuncSetAttribute(kernel_func, cudaFuncAttributeMaxDynamicSharedMemorySize, \
54
+ kSmemByteSize); \
55
+ kernel_func<<<num_blocks, threads_per_block, kSmemByteSize>>>( \
56
+ in_feats, kernel, wscales, ascales, out_feats, bias, num_in_feats, num_out_channels, \
57
+ num_in_channels);
58
+
59
+
60
+ #define KERNEL_LAUNCH_CODE \
61
+ constexpr int NUM_WARPS = (CTA_M / WARP_M) * (CTA_N / WARP_N) * (CTA_K / WARP_K); \
62
+ constexpr int kSmemByteSize = \
63
+ (CTA_M * (CTA_K + SMEM_PAD_A) + CTA_N * (CTA_K + SMEM_PAD_B)) * STAGES * \
64
+ sizeof(int8_t); \
65
+ if (kSmemByteSize >= 99 * 1024) \
66
+ { \
67
+ printf("This kernel requires %d Bytes of shared memory, which exceeds " \
68
+ "device limit.\n", \
69
+ kSmemByteSize); \
70
+ return ; \
71
+ } \
72
+ int num_blocks_m = (num_out_feats + CTA_M - 1) / CTA_M; \
73
+ int num_blocks_n = num_out_channels / CTA_N / 1; \
74
+ const int log_tile = get_log_tile<8>((num_out_feats + CTA_M - 1) / CTA_M); \
75
+ const int tile_shift = 1 << log_tile; \
76
+ dim3 num_blocks(num_blocks_n *tile_shift, \
77
+ (num_blocks_m + tile_shift - 1) / tile_shift); \
78
+ dim3 threads_per_block(WARP_SIZE, NUM_WARPS); \
79
+ auto kernel_func = \
80
+ dense_kernel0<CTA_M, CTA_N, CTA_K, WARP_M, WARP_N, WARP_K, STAGES>; \
81
+ cudaFuncSetAttribute(kernel_func, cudaFuncAttributeMaxDynamicSharedMemorySize, \
82
+ kSmemByteSize); \
83
+ kernel_func<<<num_blocks, threads_per_block, kSmemByteSize>>>( \
84
+ in_feats, kernel, wscales, ascales, out_feats, num_in_feats, num_out_channels, \
85
+ num_in_channels);
86
+
87
+
88
+
89
+ template <int N>
90
+ __inline__ __host__ __device__ int get_log_tile(int n)
91
+ {
92
+ if (N >= 8 && n >= 6)
93
+ return 3;
94
+ else if (N >= 4 && n >= 3)
95
+ return 2;
96
+ else if (N >= 2 && n >= 2)
97
+ return 1;
98
+ else
99
+ return 0;
100
+ }
101
+
102
+ __inline__ __device__ uint2 get_block_idx_mapping(int blockIdx_x,
103
+ int blockIdx_y,
104
+ int log_tile)
105
+ {
106
+ return make_uint2((blockIdx_x >> log_tile),
107
+ (blockIdx_y << log_tile) +
108
+ ((blockIdx_x) & ((1 << (log_tile)) - 1)));
109
+ }
110
+
111
+ __inline__ __device__ uint32_t cast_smem_ptr_to_uint(void const *const ptr)
112
+ {
113
+ uint32_t smem_int_ptr;
114
+
115
+ asm("{.reg .u64 smem_ptr; cvta.to.shared.u64 smem_ptr, %1; cvt.u32.u64 %0, "
116
+ "smem_ptr; }\n"
117
+ : "=r"(smem_int_ptr)
118
+ : "l"(ptr));
119
+
120
+ return smem_int_ptr;
121
+ }
122
+
123
+ __inline__ __device__ void ldmatrix_m8n8_x4_b16(int8_t *shared_warp, int ax0_0,
124
+ uint32_t addr)
125
+ {
126
+ __asm__ __volatile__("ldmatrix.sync.aligned.m8n8.x4.shared.b16"
127
+ "{%0, %1, %2, %3}, [%4];"
128
+ : "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[0]),
129
+ "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[1]),
130
+ "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[2]),
131
+ "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[3])
132
+ : "r"(addr));
133
+ }
134
+
135
+ __inline__ __device__ void
136
+ ldmatrix_m8n8_x4_trans_b16(int8_t *shared_warp, int ax0_0, uint32_t addr)
137
+ {
138
+ __asm__ __volatile__("ldmatrix.sync.aligned.m8n8.x4.trans.shared.b16"
139
+ "{%0, %1, %2, %3}, [%4];"
140
+ : "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[0]),
141
+ "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[1]),
142
+ "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[2]),
143
+ "=r"(((unsigned *)(shared_warp + (ax0_0 * 16)))[3])
144
+ : "r"(addr));
145
+ }
146
+
147
+ // function from lmdeploy
148
+ __inline__ __device__ void
149
+ cp_async_cg_A(uint32_t smem_int_ptr, const uint4 *__restrict__ src, bool mask)//256 * int8
150
+ {
151
+ const int cp_size = 16;
152
+ asm volatile("{"
153
+ " .reg .pred p;"
154
+ " setp.ne.b32 p, %0, 0;"
155
+ " @p cp.async.cg.shared.global" L2_CACHEHINT(128) " [%1], [%2], %3;"
156
+ "}" ::"r"((int)mask),
157
+ "r"(smem_int_ptr),
158
+ "l"(src),
159
+ "n"(cp_size));
160
+ }
161
+
162
+ __device__ __inline__ void mma_m16n8k32(void *C_warp, void *A_shared_warp,
163
+ void *B_shared_warp)
164
+ {
165
+ __asm__ __volatile__(
166
+ "mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32"
167
+ "{%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%10, %11, %12, %13};"
168
+ : "=r"(((int *)C_warp)[0]), "=r"(((int *)C_warp)[1]),
169
+ "=r"(((int *)C_warp)[2]), "=r"(((int *)C_warp)[3])
170
+ : "r"(((unsigned *)A_shared_warp)[0]),
171
+ "r"(((unsigned *)A_shared_warp)[1]),
172
+ "r"(((unsigned *)A_shared_warp)[2]),
173
+ "r"(((unsigned *)A_shared_warp)[3]),
174
+ "r"(((unsigned *)B_shared_warp)[0]),
175
+ "r"(((unsigned *)B_shared_warp)[1]), "r"(((int *)C_warp)[0]),
176
+ "r"(((int *)C_warp)[1]), "r"(((int *)C_warp)[2]),
177
+ "r"(((int *)C_warp)[3]));
178
+ }
179
+
180
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int SHARED_K_ITERS,
181
+ int STAGES>
182
+ __device__ __inline__ void
183
+ global_to_share_one_stage_A(int8_t *src, int8_t *dst, int global_ncols,
184
+ int cta_offset_m, int cta_offset_n,
185
+ int global_iter_k, int shared_iter_k, bool mask,
186
+ bool *preds)
187
+ {
188
+ constexpr int total_global_iters = (CTA_M * CTA_K) / PACK_SIZE / CTA_SIZE;
189
+ constexpr int partial_global_iters = total_global_iters / SHARED_K_ITERS;
190
+ constexpr int cta_step_m_or_n = (CTA_SIZE * PACK_SIZE) / CTA_K;
191
+ constexpr int warp_step_m_or_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
192
+ constexpr int threads_per_row = CTA_K / PACK_SIZE;
193
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_A;
194
+ int8_t *dst_hoisted = dst;
195
+ int8_t *src_hoisted = src + global_iter_k * CTA_K;
196
+
197
+ if (mask)
198
+ {
199
+ #pragma unroll
200
+ for (int _global_iter = 0; _global_iter < partial_global_iters;
201
+ ++_global_iter)
202
+ {
203
+ int global_iter = shared_iter_k * partial_global_iters + _global_iter;
204
+
205
+ void *dst_ptr =
206
+ (void *)(dst_hoisted + global_iter * cta_step_m_or_n * kSmemCol);
207
+ uint4 *src_ptr =
208
+ (uint4 *)(src_hoisted + global_iter * cta_step_m_or_n * global_ncols);
209
+ if constexpr (STAGES > 1)
210
+ {
211
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
212
+ cp_async_cg_A(addr, src_ptr, preds[global_iter]);
213
+ }
214
+ else
215
+ {
216
+ if (preds[global_iter])
217
+ *(uint4 *)dst_ptr = *src_ptr;
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int SHARED_K_ITERS,
224
+ int STAGES>
225
+ __device__ __inline__ void
226
+ global_to_share_one_stage_B(int8_t *src, int8_t *dst, int global_ncols,
227
+ int cta_offset_m, int cta_offset_n,
228
+ int global_iter_k, int shared_iter_k, bool mask, bool *preds)
229
+ {
230
+ constexpr int total_global_iters = (CTA_N * CTA_K) / PACK_SIZE / CTA_SIZE;
231
+ constexpr int partial_global_iters = total_global_iters / SHARED_K_ITERS;
232
+ constexpr int cta_step_m_or_n = (CTA_SIZE * PACK_SIZE) / CTA_K;
233
+ constexpr int warp_step_m_or_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
234
+ constexpr int threads_per_row = CTA_K / PACK_SIZE;
235
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_B;
236
+ int8_t *dst_hoisted = dst;
237
+ int8_t *src_hoisted = src + global_iter_k * CTA_K;
238
+ #pragma unroll
239
+ for (int _global_iter = 0; _global_iter < partial_global_iters;
240
+ ++_global_iter)
241
+ {
242
+ int global_iter = shared_iter_k * partial_global_iters + _global_iter;
243
+
244
+ void *dst_ptr =
245
+ (void *)(dst_hoisted + global_iter * cta_step_m_or_n * kSmemCol);
246
+ uint4 *src_ptr =
247
+ (uint4 *)(src_hoisted + global_iter * cta_step_m_or_n * global_ncols);
248
+ if constexpr (STAGES > 1)
249
+ {
250
+ uint32_t addr = cast_smem_ptr_to_uint(dst_ptr);
251
+ cp_async_cg_A(addr, src_ptr, preds[global_iter]);
252
+ }
253
+ else
254
+ {
255
+ if (preds[global_iter])
256
+ *(uint4 *)dst_ptr = *src_ptr;
257
+ }
258
+ }
259
+ }
260
+
261
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int STAGES>
262
+ __device__ __inline__ void
263
+ share_to_reg_one_stage_A(int8_t *src, int8_t *dst, int warp_offset_m,
264
+ int warp_offset_n, int k_0_1, int shared_iters)
265
+ {
266
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_A;
267
+ int ld_col = (k_0_1 * INTRIN_K + (threadIdx.x / 16) * 16) / PACK_SIZE;
268
+
269
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
270
+ {
271
+ int ld_row = warp_offset_m + shared_iter * INTRIN_M + (threadIdx.x % 16);
272
+ int ld_col_swizzled = ld_col ^ (ld_row / 2) & 3;
273
+ void *addr_ptr =
274
+ (void *)(src + ld_row * kSmemCol + ld_col_swizzled * PACK_SIZE);
275
+ uint32_t addr = cast_smem_ptr_to_uint(addr_ptr);
276
+ ldmatrix_m8n8_x4_b16(dst, shared_iter, addr);
277
+ }
278
+ }
279
+
280
+ template <int CTA_M, int CTA_N, int CTA_K, int CTA_SIZE, int STAGES>
281
+ __device__ __inline__ void
282
+ share_to_reg_one_stage_B(int8_t *src, int8_t *dst, int warp_offset_m,
283
+ int warp_offset_n, int k_0_1, int shared_iters)
284
+ {
285
+ constexpr int kSmemCol = CTA_K + SMEM_PAD_B;
286
+ int ld_col = (k_0_1 * INTRIN_K + ((threadIdx.x / 8) % 2) * 16) / PACK_SIZE;
287
+
288
+ for (int shared_iter = 0; shared_iter < shared_iters; ++shared_iter)
289
+ {
290
+ int ld_row = warp_offset_n + shared_iter * INTRIN_N + ((threadIdx.x / 8 / 2) * 8 + threadIdx.x % 8);
291
+ int ld_col_swizzled = ld_col ^ (ld_row / 2) & 3;
292
+ void *addr_ptr =
293
+ (void *)(src + ld_row * kSmemCol + ld_col_swizzled * PACK_SIZE);
294
+ uint32_t addr = cast_smem_ptr_to_uint(addr_ptr);
295
+ ldmatrix_m8n8_x4_b16(dst, shared_iter, addr);
296
+ }
297
+ }
298
+
299
+ template <int CTA_M, int CTA_N, int CTA_K, int WARP_M, int WARP_N, int WARP_K,
300
+ int STAGES>
301
+ __global__ void dense_kernel0_fuse_bias(int8_t *__restrict__ A, int8_t *__restrict__ B,
302
+ half2 *__restrict__ wscales, half *__restrict__ ascales,
303
+ half *__restrict__ C, half *__restrict__ Bias,
304
+ int M, int N, int K)
305
+ {
306
+ constexpr int NUM_WARPS_MN = CTA_M / WARP_M * CTA_N / WARP_N;
307
+ constexpr int NUM_WARPS = NUM_WARPS_MN * CTA_K / WARP_K;
308
+ constexpr int CTA_SIZE = NUM_WARPS * WARP_SIZE;
309
+ constexpr int CTA_SIZE_MN = NUM_WARPS_MN * WARP_SIZE;
310
+ constexpr int SLICES = CTA_K / WARP_K;
311
+ int num_blocks_n = (N + CTA_N - 1) / CTA_N;
312
+ int num_blocks_m = (M + CTA_M - 1) / CTA_M;
313
+
314
+ int blockIdx_n = blockIdx.x;
315
+ int blockIdx_m = blockIdx.y;
316
+ const int log_tile = get_log_tile<8>((M + CTA_M - 1) / CTA_M);
317
+ const uint2 block_idx_mapping =
318
+ get_block_idx_mapping(blockIdx_n, blockIdx_m, log_tile);
319
+ blockIdx_n = block_idx_mapping.x;
320
+ blockIdx_m = block_idx_mapping.y;
321
+
322
+ int C_warp[CTA_M * CTA_N / CTA_SIZE_MN];
323
+ constexpr int kSmemPadKA = CTA_K + SMEM_PAD_A;
324
+ constexpr int kSmemPadKB = CTA_K + SMEM_PAD_B;
325
+ constexpr int kSmemSizeAPerStage = CTA_M * kSmemPadKA;
326
+ constexpr int kSmemSizeBPerStage = CTA_N * kSmemPadKB;
327
+ constexpr int kSmemSizeA = kSmemSizeAPerStage * STAGES;
328
+ constexpr int kSmemSizeB = kSmemSizeBPerStage * STAGES;
329
+ extern __shared__ int8_t mem_shared[];
330
+ int8_t *A_shared = mem_shared;
331
+ int8_t *B_shared = mem_shared + kSmemSizeA;
332
+ float *Bias_shared= reinterpret_cast<float*>(mem_shared + kSmemSizeA + kSmemSizeB);
333
+ int8_t A_shared_warp_[2][WARP_M * WARP_K /
334
+ WARP_SIZE];
335
+ int8_t B_shared_warp_[2][WARP_N * WARP_K /
336
+ WARP_SIZE];
337
+ constexpr int A_total_global_iters = (CTA_M * CTA_K) / PACK_SIZE / CTA_SIZE;
338
+ constexpr int B_total_global_iters = (CTA_N * CTA_K) / PACK_SIZE / CTA_SIZE;
339
+ constexpr int A_src_step_m = (CTA_SIZE * PACK_SIZE) / CTA_K;
340
+ constexpr int B_src_step_k = (CTA_SIZE * PACK_SIZE) / CTA_K;
341
+ constexpr int A_warp_step_m = (WARP_SIZE * PACK_SIZE) / CTA_K;
342
+ constexpr int B_warp_step_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
343
+ constexpr int A_threads_per_row = CTA_K / PACK_SIZE;
344
+ constexpr int B_threads_per_row = CTA_K / PACK_SIZE;
345
+ int cta_offset_m = blockIdx_m * CTA_M;
346
+ int cta_offset_n = blockIdx_n * CTA_N;
347
+ int warp_mn = threadIdx.y % NUM_WARPS_MN;
348
+ int slice_id = threadIdx.y / NUM_WARPS_MN; // Always zero if threadIdx.z==0!
349
+ int warp_offset_m = (warp_mn % (CTA_M / WARP_M)) * WARP_M;
350
+ int warp_offset_n = (warp_mn / (CTA_M / WARP_M)) * WARP_N;
351
+ int warp_offset_k = slice_id * WARP_K;
352
+
353
+ for (int i = 0; i < CTA_M * CTA_N / CTA_SIZE_MN; i++)
354
+ C_warp[i] = 0;
355
+
356
+ int gemm_iters = (K + CTA_K - 1) / CTA_K;
357
+ int k_0_0_ld = 0;
358
+ int k_0_0 = 0;
359
+ constexpr int prologue_stages = STAGES == 1 ? 1 : STAGES - 1;
360
+ int A_hoisted_row = threadIdx.y * A_warp_step_m + (threadIdx.x / A_threads_per_row);
361
+ int A_hoisted_col = (threadIdx.x % A_threads_per_row);
362
+ int A_hoisted_col_swizzled = A_hoisted_col ^ (A_hoisted_row / 2) & 3;
363
+
364
+ int B_hoisted_row = threadIdx.y * B_warp_step_n + (threadIdx.x / B_threads_per_row);
365
+ int B_hoisted_col = (threadIdx.x % B_threads_per_row);
366
+ int B_hoisted_col_swizzled = B_hoisted_col ^ (B_hoisted_row / 2) & 3;
367
+
368
+ int8_t *A_shared_hoisted = A_shared +
369
+ A_hoisted_row * kSmemPadKA +
370
+ A_hoisted_col_swizzled * PACK_SIZE;
371
+ int8_t *B_shared_hoisted = B_shared + B_hoisted_row * kSmemPadKB +
372
+ B_hoisted_col_swizzled * PACK_SIZE;
373
+ int8_t *A_hoisted = A + cta_offset_m * K + A_hoisted_row * K +
374
+ A_hoisted_col * PACK_SIZE;
375
+ int8_t *B_hoisted = B + cta_offset_n * K + B_hoisted_row * K +
376
+ B_hoisted_col * PACK_SIZE;
377
+ bool A_g2s_preds[A_total_global_iters];
378
+ bool B_g2s_preds[B_total_global_iters];
379
+ //debug
380
+ // printf("A: %d ",A_total_global_iters);
381
+ // printf("B: %d ",B_total_global_iters);
382
+ // printf("prologue_stages: %d ",prologue_stages);
383
+ // __shared__ float2 Bias_shared[CTA_N];
384
+ #pragma unroll
385
+ for (int i = 0; i < CTA_N ; i++)
386
+ {
387
+ Bias_shared[i] = __half2float(Bias[cta_offset_n+i]);
388
+ }
389
+
390
+
391
+ #pragma unroll
392
+ for (int i = 0; i < A_total_global_iters; i++)
393
+ {
394
+ A_g2s_preds[i] = (cta_offset_m + A_hoisted_row + i * A_src_step_m) < M;
395
+ }
396
+ #pragma unroll
397
+ for (int i = 0; i < B_total_global_iters; i++)
398
+ {
399
+ B_g2s_preds[i] = cta_offset_n + B_hoisted_row + i * B_src_step_k < N;
400
+ }
401
+ int *C_shared = reinterpret_cast<int *>(mem_shared);
402
+ #pragma unroll
403
+ for (k_0_0_ld = 0; k_0_0_ld < prologue_stages; ++k_0_0_ld)
404
+ {
405
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(
406
+ A_hoisted, A_shared_hoisted + k_0_0_ld * kSmemSizeAPerStage, K,
407
+ cta_offset_m, cta_offset_n, k_0_0_ld, 0, true, A_g2s_preds);
408
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(
409
+ B_hoisted, B_shared_hoisted + k_0_0_ld * kSmemSizeBPerStage, K,
410
+ cta_offset_m, cta_offset_n, k_0_0_ld, 0, true, B_g2s_preds);
411
+ if constexpr (STAGES > 1)
412
+ __pipeline_commit();
413
+ }
414
+ if constexpr (STAGES > 1)
415
+ __pipeline_wait_prior(STAGES - 2);
416
+ __syncthreads();
417
+
418
+ // global_to_share_bias<CTA_N,CTA_SIZE>(Bias,Bias_shared,cta_offset_n);
419
+
420
+ share_to_reg_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
421
+ A_shared + warp_offset_k, A_shared_warp_[0], warp_offset_m, warp_offset_n, 0,
422
+ WARP_M / INTRIN_M);
423
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
424
+ B_shared + warp_offset_k, B_shared_warp_[0], warp_offset_m, warp_offset_n, 0,
425
+ WARP_N / INTRIN_N);
426
+ constexpr int SHARED_K_ITERS = WARP_K / INTRIN_K;
427
+
428
+ for (; k_0_0 < gemm_iters; ++k_0_0, ++k_0_0_ld)
429
+ {
430
+ int ld_stage = k_0_0_ld % STAGES;
431
+ int compute_stage = k_0_0 % STAGES;
432
+ int8_t *A_shared_this_compute_stage;
433
+ int8_t *B_shared_this_compute_stage;
434
+
435
+ for (int iter_k = 0; iter_k < SHARED_K_ITERS; ++iter_k)
436
+ {
437
+ A_shared_this_compute_stage =
438
+ A_shared + compute_stage * kSmemSizeAPerStage + warp_offset_k;
439
+ B_shared_this_compute_stage =
440
+ B_shared + compute_stage * kSmemSizeBPerStage + warp_offset_k;
441
+ share_to_reg_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
442
+ A_shared_this_compute_stage, A_shared_warp_[(iter_k + 1) % 2],
443
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS,
444
+ WARP_M / INTRIN_M);
445
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
446
+ B_shared_this_compute_stage, B_shared_warp_[(iter_k + 1) % 2],
447
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS,
448
+ WARP_N / INTRIN_N);
449
+ int8_t *A_shared_warp = A_shared_warp_[iter_k % 2];
450
+ int8_t *B_shared_warp = B_shared_warp_[iter_k % 2];
451
+ for (int i_0_3 = 0; i_0_3 < WARP_M / INTRIN_M; ++i_0_3)
452
+ {
453
+ for (int j_0_4 = 0; j_0_4 < WARP_N / INTRIN_N; ++j_0_4)
454
+ {
455
+ mma_m16n8k32(
456
+ (void *)(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8),
457
+ (void *)(A_shared_warp + i_0_3 * 16),
458
+ (void *)(B_shared_warp + j_0_4 * 16));
459
+ mma_m16n8k32(
460
+ (void *)(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8 + 4),
461
+ (void *)(A_shared_warp + i_0_3 * 16),
462
+ (void *)(B_shared_warp + j_0_4 * 16 + 8));
463
+ }
464
+ }
465
+
466
+ if (iter_k < SHARED_K_ITERS - 1)
467
+ {
468
+ if constexpr (STAGES == 1)
469
+ __syncthreads();
470
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE,
471
+ WARP_K / INTRIN_K, STAGES>(
472
+ A_hoisted, A_shared_hoisted + ld_stage * kSmemSizeAPerStage, K,
473
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k,
474
+ k_0_0_ld < gemm_iters, A_g2s_preds);
475
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE,
476
+ WARP_K / INTRIN_K, STAGES>(
477
+ B_hoisted, B_shared_hoisted + ld_stage * kSmemSizeBPerStage, K,
478
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k,
479
+ k_0_0_ld < gemm_iters, B_g2s_preds);
480
+ }
481
+
482
+ if (iter_k == SHARED_K_ITERS - 2)
483
+ {
484
+ if constexpr (STAGES == 1 && SHARED_K_ITERS > 2)
485
+ {
486
+ __syncthreads();
487
+ }
488
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE,
489
+ WARP_K / INTRIN_K, STAGES>(
490
+ A_hoisted, A_shared_hoisted + ld_stage * kSmemSizeAPerStage, K,
491
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k + 1,
492
+ k_0_0_ld < gemm_iters, A_g2s_preds);
493
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE,
494
+ WARP_K / INTRIN_K, STAGES>(
495
+ B_hoisted, B_shared_hoisted + ld_stage * kSmemSizeBPerStage, K,
496
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k + 1,
497
+ k_0_0_ld < gemm_iters, B_g2s_preds);
498
+ if constexpr (STAGES > 1)
499
+ {
500
+ __pipeline_commit();
501
+ __pipeline_wait_prior(STAGES - 2);
502
+ }
503
+ compute_stage = (k_0_0 + 1) % STAGES;
504
+ __syncthreads();
505
+ }
506
+ }
507
+ }
508
+ __pipeline_commit();
509
+ __pipeline_wait_prior(0);
510
+ __syncthreads();
511
+
512
+ if constexpr (SLICES > 1)
513
+ {
514
+ #pragma unroll
515
+ for (int z = 0; z < SLICES; ++z)
516
+ {
517
+ if (slice_id == z)
518
+ {
519
+ #pragma unroll
520
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
521
+ {
522
+ #pragma unroll
523
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
524
+ {
525
+ #pragma unroll
526
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
527
+ {
528
+ if (z > 0)
529
+ {
530
+ C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] += C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
531
+ }
532
+ C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2] = C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id];
533
+ };
534
+ }
535
+ }
536
+ }
537
+ __syncthreads();
538
+ }
539
+ if (slice_id == 0)
540
+ {
541
+ #pragma unroll
542
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
543
+ {
544
+ #pragma unroll
545
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
546
+ {
547
+ #pragma unroll
548
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
549
+ {
550
+ C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] = C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
551
+ };
552
+ }
553
+ }
554
+ }
555
+ }
556
+
557
+ int row_wb_thd = cta_offset_m + warp_offset_m + (threadIdx.x / 4);
558
+ int col_wb_thd = cta_offset_n + warp_offset_n + (threadIdx.x % 4) * 2;
559
+ if (slice_id == 0)
560
+ {
561
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
562
+ {
563
+ int row_wb_1 = row_wb_thd + ax0_0_1 * OP_M;
564
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
565
+ {
566
+ int col_wb_1 = col_wb_thd + ax1_0_1 * 16;
567
+ int *C_warp_local = C_warp + ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8;
568
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
569
+ {
570
+ int row_wb = row_wb_1 + (local_id % 4) / 2 * 8;
571
+ int col_wb = col_wb_1 + (local_id / 4) * 8 + (local_id % 2);
572
+ if (row_wb < M && col_wb < N ){
573
+ float2 wscale = __half22float2(*(wscales + col_wb / 2));
574
+ float ascale = __half2float(ascales[row_wb]);
575
+ float2 psums = make_float2(__int2float_rn(C_warp_local[local_id]), __int2float_rn(C_warp_local[local_id + 1]));
576
+ psums.x = psums.x * wscale.x * ascale + Bias_shared[col_wb % CTA_N];
577
+ psums.y = psums.y * wscale.y * ascale + Bias_shared[col_wb % CTA_N + 1];
578
+ *reinterpret_cast<half2 *>(C + row_wb * N + col_wb) = __float22half2_rn(psums);
579
+ }
580
+ };
581
+ }
582
+ }
583
+ }
584
+ }
585
+
586
+ void w8a8_gemm_fuse_bias_forward_cuda(torch::Tensor _in_feats,
587
+ torch::Tensor _kernel,
588
+ torch::Tensor _wscales,
589
+ torch::Tensor _ascales,
590
+ torch::Tensor _out_feats,
591
+ torch::Tensor _bias)
592
+ {
593
+ int num_in_feats = _in_feats.size(0);
594
+ int num_in_channels = _in_feats.size(1);
595
+ auto in_feats = reinterpret_cast<int8_t *>(_in_feats.data_ptr<int8_t>());
596
+ auto kernel = reinterpret_cast<int8_t *>(_kernel.data_ptr<int8_t>());
597
+ auto wscales = reinterpret_cast<half2 *>(_wscales.data_ptr());
598
+ auto ascales = reinterpret_cast<half *>(_ascales.data_ptr());
599
+ auto bias = reinterpret_cast<half *>(_bias.data_ptr());
600
+ // auto options =
601
+ // torch::TensorOptions().dtype(torch::kFloat16).device(_in_feats.device());
602
+ // at::Tensor _out_feats =
603
+ // torch::empty({num_in_feats, _kernel.size(0)}, options);
604
+ int num_out_feats = _out_feats.size(-2);
605
+ int num_out_channels = _out_feats.size(-1);
606
+
607
+
608
+ auto out_feats = reinterpret_cast<half *>(_out_feats.data_ptr<at::Half>());
609
+
610
+ if (num_out_feats > 128)
611
+ {
612
+ constexpr int CTA_M = 128;
613
+ constexpr int CTA_N = 128;
614
+ constexpr int CTA_K = 64;
615
+ constexpr int WARP_M = 64;
616
+ constexpr int WARP_N = 32;
617
+ constexpr int WARP_K = 64;
618
+ constexpr int STAGES = 6;
619
+ KERNEL_LAUNCH_CODE_FUSE_BIAS
620
+ }
621
+ else
622
+ {
623
+ constexpr int CTA_M = 64;
624
+ constexpr int CTA_N = 64;
625
+ constexpr int CTA_K = 64;
626
+ constexpr int WARP_M = 32;
627
+ constexpr int WARP_N = 16;
628
+ constexpr int WARP_K = 64;
629
+ constexpr int STAGES = 6;
630
+ KERNEL_LAUNCH_CODE_FUSE_BIAS
631
+ }
632
+ return ;
633
+ }
634
+
635
+ template <int CTA_M, int CTA_N, int CTA_K, int WARP_M, int WARP_N, int WARP_K,
636
+ int STAGES>
637
+ __global__ void dense_kernel0(int8_t *__restrict__ A, int8_t *__restrict__ B,
638
+ half2 *__restrict__ wscales, half *__restrict__ ascales,
639
+ half *__restrict__ C, int M, int N, int K)
640
+ {
641
+ constexpr int NUM_WARPS_MN = CTA_M / WARP_M * CTA_N / WARP_N;
642
+ constexpr int NUM_WARPS = NUM_WARPS_MN * CTA_K / WARP_K;
643
+ constexpr int CTA_SIZE = NUM_WARPS * WARP_SIZE;
644
+ constexpr int CTA_SIZE_MN = NUM_WARPS_MN * WARP_SIZE;
645
+ constexpr int SLICES = CTA_K / WARP_K;
646
+ int num_blocks_n = (N + CTA_N - 1) / CTA_N;
647
+ int num_blocks_m = (M + CTA_M - 1) / CTA_M;
648
+
649
+ int blockIdx_n = blockIdx.x;
650
+ int blockIdx_m = blockIdx.y;
651
+ const int log_tile = get_log_tile<8>((M + CTA_M - 1) / CTA_M);
652
+ const uint2 block_idx_mapping =
653
+ get_block_idx_mapping(blockIdx_n, blockIdx_m, log_tile);
654
+ blockIdx_n = block_idx_mapping.x;
655
+ blockIdx_m = block_idx_mapping.y;
656
+
657
+ int C_warp[CTA_M * CTA_N / CTA_SIZE_MN];
658
+ constexpr int kSmemPadKA = CTA_K + SMEM_PAD_A;
659
+ constexpr int kSmemPadKB = CTA_K + SMEM_PAD_B;
660
+ constexpr int kSmemSizeAPerStage = CTA_M * kSmemPadKA;
661
+ constexpr int kSmemSizeBPerStage = CTA_N * kSmemPadKB;
662
+ constexpr int kSmemSizeA = kSmemSizeAPerStage * STAGES;
663
+ constexpr int kSmemSizeB = kSmemSizeBPerStage * STAGES;
664
+ extern __shared__ int8_t mem_shared[];
665
+ int8_t *A_shared = mem_shared;
666
+ int8_t *B_shared = mem_shared + kSmemSizeA;
667
+ int8_t A_shared_warp_[2][WARP_M * WARP_K /
668
+ WARP_SIZE];
669
+ int8_t B_shared_warp_[2][WARP_N * WARP_K /
670
+ WARP_SIZE];
671
+ constexpr int A_total_global_iters = (CTA_M * CTA_K) / PACK_SIZE / CTA_SIZE;
672
+ constexpr int B_total_global_iters = (CTA_N * CTA_K) / PACK_SIZE / CTA_SIZE;
673
+ constexpr int A_src_step_m = (CTA_SIZE * PACK_SIZE) / CTA_K;
674
+ constexpr int B_src_step_k = (CTA_SIZE * PACK_SIZE) / CTA_K;
675
+ constexpr int A_warp_step_m = (WARP_SIZE * PACK_SIZE) / CTA_K;
676
+ constexpr int B_warp_step_n = (WARP_SIZE * PACK_SIZE) / CTA_K;
677
+ constexpr int A_threads_per_row = CTA_K / PACK_SIZE;
678
+ constexpr int B_threads_per_row = CTA_K / PACK_SIZE;
679
+ int cta_offset_m = blockIdx_m * CTA_M;
680
+ int cta_offset_n = blockIdx_n * CTA_N;
681
+ int warp_mn = threadIdx.y % NUM_WARPS_MN;
682
+ int slice_id = threadIdx.y / NUM_WARPS_MN;
683
+ int warp_offset_m = (warp_mn % (CTA_M / WARP_M)) * WARP_M;
684
+ int warp_offset_n = (warp_mn / (CTA_M / WARP_M)) * WARP_N;
685
+ int warp_offset_k = slice_id * WARP_K;
686
+
687
+ for (int i = 0; i < CTA_M * CTA_N / CTA_SIZE_MN; i++)
688
+ C_warp[i] = 0;
689
+
690
+ int gemm_iters = (K + CTA_K - 1) / CTA_K;
691
+ int k_0_0_ld = 0;
692
+ int k_0_0 = 0;
693
+ constexpr int prologue_stages = STAGES == 1 ? 1 : STAGES - 1;
694
+ int A_hoisted_row = threadIdx.y * A_warp_step_m + (threadIdx.x / A_threads_per_row);
695
+ int A_hoisted_col = (threadIdx.x % A_threads_per_row);
696
+ int A_hoisted_col_swizzled = A_hoisted_col ^ (A_hoisted_row / 2) & 3;
697
+
698
+ int B_hoisted_row = threadIdx.y * B_warp_step_n + (threadIdx.x / B_threads_per_row);
699
+ int B_hoisted_col = (threadIdx.x % B_threads_per_row);
700
+ int B_hoisted_col_swizzled = B_hoisted_col ^ (B_hoisted_row / 2) & 3;
701
+
702
+ int8_t *A_shared_hoisted = A_shared +
703
+ A_hoisted_row * kSmemPadKA +
704
+ A_hoisted_col_swizzled * PACK_SIZE;
705
+ int8_t *B_shared_hoisted = B_shared + B_hoisted_row * kSmemPadKB +
706
+ B_hoisted_col_swizzled * PACK_SIZE;
707
+ int8_t *A_hoisted = A + cta_offset_m * K + A_hoisted_row * K +
708
+ A_hoisted_col * PACK_SIZE;
709
+ int8_t *B_hoisted = B + cta_offset_n * K + B_hoisted_row * K +
710
+ B_hoisted_col * PACK_SIZE;
711
+ bool A_g2s_preds[A_total_global_iters];
712
+ #pragma unroll
713
+ for (int i = 0; i < A_total_global_iters; i++)
714
+ {
715
+ A_g2s_preds[i] = (cta_offset_m + A_hoisted_row + i * A_src_step_m) < M;
716
+ }
717
+ bool B_g2s_preds[B_total_global_iters];
718
+ #pragma unroll
719
+ for (int i = 0; i < B_total_global_iters; i++)
720
+ {
721
+ B_g2s_preds[i] = (cta_offset_n + B_hoisted_col + i) < N;
722
+ }
723
+ int *C_shared = reinterpret_cast<int *>(mem_shared);
724
+ #pragma unroll
725
+ for (k_0_0_ld = 0; k_0_0_ld < prologue_stages; ++k_0_0_ld)
726
+ {
727
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(
728
+ A_hoisted, A_shared_hoisted + k_0_0_ld * kSmemSizeAPerStage, K,
729
+ cta_offset_m, cta_offset_n, k_0_0_ld, 0, true, A_g2s_preds);
730
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, 1, STAGES>(
731
+ B_hoisted, B_shared_hoisted + k_0_0_ld * kSmemSizeBPerStage, K,
732
+ cta_offset_m, cta_offset_n, k_0_0_ld, 0, true, B_g2s_preds);
733
+ if constexpr (STAGES > 1)
734
+ __pipeline_commit();
735
+ }
736
+ if constexpr (STAGES > 1)
737
+ __pipeline_wait_prior(STAGES - 2);
738
+ __syncthreads();
739
+
740
+ share_to_reg_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
741
+ A_shared + warp_offset_k, A_shared_warp_[0], warp_offset_m, warp_offset_n, 0,
742
+ WARP_M / INTRIN_M);
743
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
744
+ B_shared + warp_offset_k, B_shared_warp_[0], warp_offset_m, warp_offset_n, 0,
745
+ WARP_N / INTRIN_N);
746
+ constexpr int SHARED_K_ITERS = WARP_K / INTRIN_K;
747
+
748
+ for (; k_0_0 < gemm_iters; ++k_0_0, ++k_0_0_ld)
749
+ {
750
+ int ld_stage = k_0_0_ld % STAGES;
751
+ int compute_stage = k_0_0 % STAGES;
752
+ int8_t *A_shared_this_compute_stage;
753
+ int8_t *B_shared_this_compute_stage;
754
+
755
+ for (int iter_k = 0; iter_k < SHARED_K_ITERS; ++iter_k)
756
+ {
757
+ A_shared_this_compute_stage =
758
+ A_shared + compute_stage * kSmemSizeAPerStage + warp_offset_k;
759
+ B_shared_this_compute_stage =
760
+ B_shared + compute_stage * kSmemSizeBPerStage + warp_offset_k;
761
+ share_to_reg_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
762
+ A_shared_this_compute_stage, A_shared_warp_[(iter_k + 1) % 2],
763
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS,
764
+ WARP_M / INTRIN_M);
765
+ share_to_reg_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE, STAGES>(
766
+ B_shared_this_compute_stage, B_shared_warp_[(iter_k + 1) % 2],
767
+ warp_offset_m, warp_offset_n, (iter_k + 1) % SHARED_K_ITERS,
768
+ WARP_N / INTRIN_N);
769
+ int8_t *A_shared_warp = A_shared_warp_[iter_k % 2];
770
+ int8_t *B_shared_warp = B_shared_warp_[iter_k % 2];
771
+ for (int i_0_3 = 0; i_0_3 < WARP_M / INTRIN_M; ++i_0_3)
772
+ {
773
+ for (int j_0_4 = 0; j_0_4 < WARP_N / INTRIN_N; ++j_0_4)
774
+ {
775
+ mma_m16n8k32(
776
+ (void *)(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8),
777
+ (void *)(A_shared_warp + i_0_3 * 16),
778
+ (void *)(B_shared_warp + j_0_4 * 16));
779
+ mma_m16n8k32(
780
+ (void *)(C_warp + i_0_3 * WARP_N / INTRIN_N * 8 + j_0_4 * 8 + 4),
781
+ (void *)(A_shared_warp + i_0_3 * 16),
782
+ (void *)(B_shared_warp + j_0_4 * 16 + 8));
783
+ }
784
+ }
785
+
786
+ if (iter_k < SHARED_K_ITERS - 1)
787
+ {
788
+ if constexpr (STAGES == 1)
789
+ __syncthreads();
790
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE,
791
+ WARP_K / INTRIN_K, STAGES>(
792
+ A_hoisted, A_shared_hoisted + ld_stage * kSmemSizeAPerStage, K,
793
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k,
794
+ k_0_0_ld < gemm_iters, A_g2s_preds);
795
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE,
796
+ WARP_K / INTRIN_K, STAGES>(
797
+ B_hoisted, B_shared_hoisted + ld_stage * kSmemSizeBPerStage, K,
798
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k,
799
+ k_0_0_ld < gemm_iters, B_g2s_preds);
800
+ }
801
+
802
+ if (iter_k == SHARED_K_ITERS - 2)
803
+ {
804
+ if constexpr (STAGES == 1 && SHARED_K_ITERS > 2)
805
+ {
806
+ __syncthreads();
807
+ }
808
+ global_to_share_one_stage_A<CTA_M, CTA_N, CTA_K, CTA_SIZE,
809
+ WARP_K / INTRIN_K, STAGES>(
810
+ A_hoisted, A_shared_hoisted + ld_stage * kSmemSizeAPerStage, K,
811
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k + 1,
812
+ k_0_0_ld < gemm_iters, A_g2s_preds);
813
+ global_to_share_one_stage_B<CTA_M, CTA_N, CTA_K, CTA_SIZE,
814
+ WARP_K / INTRIN_K, STAGES>(
815
+ B_hoisted, B_shared_hoisted + ld_stage * kSmemSizeBPerStage, K,
816
+ cta_offset_m, cta_offset_n, k_0_0_ld, iter_k + 1,
817
+ k_0_0_ld < gemm_iters, B_g2s_preds);
818
+ if constexpr (STAGES > 1)
819
+ {
820
+ __pipeline_commit();
821
+ __pipeline_wait_prior(STAGES - 2);
822
+ }
823
+ compute_stage = (k_0_0 + 1) % STAGES;
824
+ __syncthreads();
825
+ }
826
+ }
827
+ }
828
+ __pipeline_commit();
829
+ __pipeline_wait_prior(0);
830
+ __syncthreads();
831
+
832
+ if constexpr (SLICES > 1)
833
+ {
834
+ #pragma unroll
835
+ for (int z = 0; z < SLICES; ++z)
836
+ {
837
+ if (slice_id == z)
838
+ {
839
+ #pragma unroll
840
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
841
+ {
842
+ #pragma unroll
843
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
844
+ {
845
+ #pragma unroll
846
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
847
+ {
848
+ if (z > 0)
849
+ {
850
+ C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] += C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
851
+ }
852
+ C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2] = C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id];
853
+ };
854
+ }
855
+ }
856
+ }
857
+ __syncthreads();
858
+ }
859
+ if (slice_id == 0)
860
+ {
861
+ #pragma unroll
862
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
863
+ {
864
+ #pragma unroll
865
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
866
+ {
867
+ #pragma unroll
868
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; ++local_id)
869
+ {
870
+ C_warp[ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8 + local_id] = C_shared[warp_offset_m * CTA_N + ax0_0_1 * OP_M * CTA_N + warp_offset_n + ax1_0_1 * 16 + ((local_id % 4) / 2 * 8 + (threadIdx.x / 4)) * CTA_N + (local_id / 4) * 8 + (local_id % 2) + (threadIdx.x % 4) * 2];
871
+ };
872
+ }
873
+ }
874
+ }
875
+ }
876
+
877
+ int row_wb_thd = cta_offset_m + warp_offset_m + (threadIdx.x / 4);
878
+ int col_wb_thd = cta_offset_n + warp_offset_n + (threadIdx.x % 4) * 2;
879
+ if (slice_id == 0)
880
+ {
881
+ for (int ax0_0_1 = 0; ax0_0_1 < WARP_M / INTRIN_M; ++ax0_0_1)
882
+ {
883
+ int row_wb_1 = row_wb_thd + ax0_0_1 * OP_M;
884
+ for (int ax1_0_1 = 0; ax1_0_1 < WARP_N / INTRIN_N; ++ax1_0_1)
885
+ {
886
+ int col_wb_1 = col_wb_thd + ax1_0_1 * 16;
887
+ int *C_warp_local = C_warp + ax0_0_1 * WARP_N / INTRIN_N * 8 + ax1_0_1 * 8;
888
+ for (int local_id = 0; local_id < OP_M * 16 / WARP_SIZE; local_id += 2)
889
+ {
890
+ int row_wb = row_wb_1 + (local_id % 4) / 2 * 8;
891
+ int col_wb = col_wb_1 + (local_id / 4) * 8 + (local_id % 2);
892
+ if (row_wb < M && col_wb < N){
893
+ int col_wb = col_wb_1 + (local_id / 4) * 8 + (local_id % 2);
894
+ float2 wscale = __half22float2(*(wscales + col_wb / 2));
895
+ float ascale = __half2float(ascales[row_wb]);
896
+ float2 psums = make_float2(__int2float_rn(C_warp_local[local_id]), __int2float_rn(C_warp_local[local_id + 1]));
897
+ psums.x *= wscale.x * ascale;
898
+ psums.y *= wscale.y * ascale;
899
+ *reinterpret_cast<half2 *>(C + row_wb * N + col_wb) = __float22half2_rn(psums);
900
+ }
901
+ };
902
+ }
903
+ }
904
+ }
905
+ }
906
+
907
+ void w8a8_gemm_forward_cuda(torch::Tensor _in_feats,
908
+ torch::Tensor _kernel,
909
+ torch::Tensor _wscales,
910
+ torch::Tensor _ascales,
911
+ torch::Tensor _out_feats)
912
+ {
913
+ int num_in_feats = _in_feats.size(0);
914
+ int num_in_channels = _in_feats.size(1);
915
+ auto in_feats = reinterpret_cast<int8_t *>(_in_feats.data_ptr<int8_t>());
916
+ auto kernel = reinterpret_cast<int8_t *>(_kernel.data_ptr<int8_t>());
917
+ auto wscales = reinterpret_cast<half2 *>(_wscales.data_ptr());
918
+ auto ascales = reinterpret_cast<half *>(_ascales.data_ptr());
919
+
920
+ // auto options =
921
+ // torch::TensorOptions().dtype(torch::kFloat16).device(_in_feats.device());
922
+ // at::Tensor _out_feats =
923
+ // torch::empty({num_in_feats, _kernel.size(0)}, options);
924
+ int num_out_feats = _out_feats.size(-2);
925
+ int num_out_channels = _out_feats.size(-1);
926
+
927
+
928
+ auto out_feats = reinterpret_cast<half *>(_out_feats.data_ptr<at::Half>());
929
+
930
+ if (num_out_feats > 128)
931
+ {
932
+ constexpr int CTA_M = 128;
933
+ constexpr int CTA_N = 128;
934
+ constexpr int CTA_K = 64;
935
+ constexpr int WARP_M = 128;
936
+ constexpr int WARP_N = 32;
937
+ constexpr int WARP_K = 64;
938
+ constexpr int STAGES = 3;
939
+ KERNEL_LAUNCH_CODE
940
+ }
941
+ else
942
+ {
943
+ constexpr int CTA_M = 64;
944
+ constexpr int CTA_N = 64;
945
+ constexpr int CTA_K = 64;
946
+ constexpr int WARP_M = 32;
947
+ constexpr int WARP_N = 32;
948
+ constexpr int WARP_K = 64;
949
+ constexpr int STAGES = 6;
950
+ KERNEL_LAUNCH_CODE
951
+ }
952
+ return ;
953
+ }
llm-awq/awq/kernels/csrc/w8a8/w8a8_gemm_cuda.h ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #include <torch/extension.h>
2
+
3
+ void w8a8_gemm_forward_cuda(torch::Tensor _in_feats, torch::Tensor _kernel, torch::Tensor _wscales, torch::Tensor _ascales, torch::Tensor _out_feats);
4
+ void w8a8_gemm_fuse_bias_forward_cuda(torch::Tensor _in_feats, torch::Tensor _kernel, torch::Tensor _wscales, torch::Tensor _ascales, torch::Tensor _out_feats, torch::Tensor _bias);
llm-awq/awq/quantize/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .w8a8_linear import *
2
+ from .smooth import *
llm-awq/awq/quantize/__pycache__/w8a8_linear.cpython-311.pyc ADDED
Binary file (14.4 kB). View file
 
llm-awq/awq/quantize/auto_clip.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from .quantizer import pseudo_quantize_tensor
4
+ import gc
5
+
6
+ __all__ = ["auto_clip_block"]
7
+
8
+
9
+ # weight quantization
10
+ @torch.no_grad()
11
+ def auto_clip_layer(
12
+ w, input_feat, n_bit, q_config, n_grid=20, max_shrink=0.5, n_sample_token=512
13
+ ):
14
+ assert w.dim() == 2
15
+ org_w_shape = w.shape
16
+ # w [co, ci] -> [co, 1, n_group, group size]
17
+ # input_feat [n_token, ci] -> [1, n_token, n_group, group size]
18
+ group_size = (
19
+ q_config["q_group_size"] if q_config["q_group_size"] > 0 else w.shape[1]
20
+ )
21
+ input_feat = input_feat.view(-1, input_feat.shape[-1])
22
+ input_feat = input_feat.reshape(1, input_feat.shape[0], -1, group_size)
23
+ input_feat = input_feat[:, 0 :: input_feat.shape[1] // n_sample_token]
24
+ w = w.reshape(w.shape[0], 1, -1, group_size)
25
+
26
+ oc_batch_size = 256 if w.shape[0] % 256 == 0 else 64 # prevent OOM
27
+ assert w.shape[0] % oc_batch_size == 0
28
+ w_all = w
29
+ best_max_val_all = []
30
+
31
+ for i_b in range(w.shape[0] // oc_batch_size):
32
+ w = w_all[i_b * oc_batch_size : (i_b + 1) * oc_batch_size]
33
+
34
+ org_max_val = w.abs().amax(dim=-1, keepdim=True) # co, 1, n_group, 1
35
+
36
+ best_max_val = org_max_val.clone()
37
+ min_errs = torch.ones_like(org_max_val) * 1e9
38
+ input_feat = input_feat.to(w.device)
39
+ org_out = (input_feat * w).sum(dim=-1) # co, n_token, n_group
40
+
41
+ for i_s in range(int(max_shrink * n_grid)):
42
+ max_val = org_max_val * (1 - i_s / n_grid)
43
+ min_val = -max_val
44
+ cur_w = torch.clamp(w, min_val, max_val)
45
+ q_w = pseudo_quantize_tensor(cur_w, n_bit=n_bit, **q_config)
46
+ cur_out = (input_feat * q_w).sum(dim=-1)
47
+
48
+ # co, 1, n_group, 1
49
+ err = (cur_out - org_out).pow(2).mean(dim=1).view(min_errs.shape)
50
+ del cur_w
51
+ del cur_out
52
+ cur_best_idx = err < min_errs
53
+ min_errs[cur_best_idx] = err[cur_best_idx]
54
+ best_max_val[cur_best_idx] = max_val[cur_best_idx]
55
+ best_max_val_all.append(best_max_val)
56
+
57
+ best_max_val = torch.cat(best_max_val_all, dim=0)
58
+
59
+ del input_feat
60
+ del org_out
61
+ gc.collect()
62
+ torch.cuda.empty_cache()
63
+ return best_max_val.squeeze(1)
64
+
65
+
66
+ @torch.no_grad()
67
+ def auto_clip_block(module, w_bit, q_config, input_feat):
68
+ named_linears = {
69
+ name: m for name, m in module.named_modules() if isinstance(m, nn.Linear)
70
+ }
71
+
72
+ clip_list = []
73
+ for name in named_linears:
74
+ # due to qk bmm, it is hard to clip precisely
75
+ if any([_ in name for _ in ["q_", "k_", "query", "key", "Wqkv"]]):
76
+ continue
77
+ named_linears[name].cuda()
78
+ max_val = auto_clip_layer(
79
+ named_linears[name].weight, input_feat[name], n_bit=w_bit, q_config=q_config
80
+ )
81
+ clip_list.append((name, max_val))
82
+ named_linears[name].cpu()
83
+ return clip_list
84
+
85
+
86
+ @torch.no_grad()
87
+ def apply_clip(module, clip_list):
88
+ from ..utils.module import get_op_by_name
89
+
90
+ for name, max_val in clip_list:
91
+ layer = get_op_by_name(module, name)
92
+ layer.cuda()
93
+ max_val = max_val.to(layer.weight.device).to(layer.weight.dtype)
94
+ org_shape = layer.weight.shape
95
+ layer.weight.data = layer.weight.data.reshape(*max_val.shape[:2], -1)
96
+ layer.weight.data = torch.clamp(layer.weight.data, -max_val, max_val)
97
+ layer.weight.data = layer.weight.data.reshape(org_shape)
98
+ layer.cpu()
llm-awq/awq/quantize/auto_scale.py ADDED
@@ -0,0 +1,480 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gc
2
+ import torch
3
+ import torch.nn as nn
4
+
5
+ from transformers.models.bloom.modeling_bloom import BloomBlock, BloomGelu
6
+ from transformers.models.opt.modeling_opt import OPTDecoderLayer
7
+ from transformers.models.llama.modeling_llama import LlamaDecoderLayer, LlamaRMSNorm
8
+ from transformers.activations import GELUActivation
9
+ from transformers.models.qwen2.modeling_qwen2 import Qwen2RMSNorm, Qwen2DecoderLayer
10
+
11
+ from .qmodule import ScaledActivation
12
+ from ..utils.module import get_op_by_name, get_op_name, set_op_by_name
13
+
14
+ __all__ = ["auto_scale_block", "apply_scale"]
15
+
16
+
17
+ @torch.no_grad()
18
+ def get_weight_scale(weight, q_group_size=-1):
19
+ org_shape = weight.shape
20
+ if q_group_size > 0:
21
+ weight = weight.view(-1, q_group_size)
22
+ scale = weight.abs() / weight.abs().amax(dim=1, keepdim=True)
23
+ scale = scale.view(org_shape)
24
+ scale = scale.mean(0)
25
+ return scale
26
+
27
+
28
+ @torch.no_grad()
29
+ def get_act_scale(x):
30
+ return x.abs().view(-1, x.shape[-1]).mean(0)
31
+
32
+
33
+ @torch.no_grad()
34
+ def scale_ln_fcs(ln, fcs, scales):
35
+ if not isinstance(fcs, list):
36
+ fcs = [fcs]
37
+
38
+ scales = scales.to(ln.weight.device).to(ln.weight.dtype)
39
+
40
+ ln.weight.div_(scales)
41
+ if hasattr(ln, "bias") and ln.bias is not None:
42
+ ln.bias.div_(scales)
43
+
44
+ for fc in fcs:
45
+ fc.weight.mul_(scales.view(1, -1))
46
+
47
+ for p in ln.parameters():
48
+ assert torch.isnan(p).sum() == 0
49
+ for fc in fcs:
50
+ for p in fc.parameters():
51
+ assert torch.isnan(p).sum() == 0
52
+
53
+
54
+ @torch.no_grad()
55
+ def scale_fc_fc(fc1, fc2, scales):
56
+ assert isinstance(fc1, nn.Linear)
57
+ assert isinstance(fc2, nn.Linear)
58
+ # assert fc1.out_features == fc2.in_features
59
+
60
+ scales = scales.to(fc1.weight.device).to(fc1.weight.dtype)
61
+
62
+ # fc1.weight.div_(scales.view(-1, 1))
63
+ fc1.weight[-scales.size(0) :].div_(scales.view(-1, 1))
64
+ if fc1.bias is not None:
65
+ fc1.bias.div_(scales.view(-1))
66
+
67
+ fc2.weight.mul_(scales.view(1, -1))
68
+
69
+ for p in fc1.parameters():
70
+ assert torch.isnan(p).sum() == 0
71
+ for p in fc2.parameters():
72
+ assert torch.isnan(p).sum() == 0
73
+
74
+
75
+ @torch.no_grad()
76
+ def scale_gelu_fc(gelu, fc, scales):
77
+ assert isinstance(gelu, (nn.GELU, BloomGelu, GELUActivation))
78
+ assert isinstance(fc, nn.Linear)
79
+
80
+ fc.weight.mul_(scales.view(1, -1).to(fc.weight.device).to(fc.weight.dtype))
81
+
82
+ for p in fc.parameters():
83
+ assert torch.isnan(p).sum() == 0
84
+
85
+
86
+ @torch.no_grad()
87
+ def auto_scale_block(module, module_kwargs, w_bit, q_config, input_feat):
88
+ from .quantizer import pseudo_quantize_tensor
89
+
90
+ # firstly, get the weight quantize function
91
+ if w_bit is not None:
92
+
93
+ def w_quantize_func(p):
94
+ return pseudo_quantize_tensor(
95
+ p,
96
+ n_bit=w_bit,
97
+ **q_config,
98
+ ).detach()
99
+
100
+ else:
101
+
102
+ def w_quantize_func(p):
103
+ return p
104
+
105
+ if "use_cache" in module_kwargs:
106
+ module_kwargs.pop("use_cache")
107
+
108
+ # find the best scale ratio
109
+ def _search_module_scale(block, linears2scale: list, x, kwargs={}):
110
+ # w: co, ci
111
+ # x: n, ci
112
+ x = x.to(next(block.parameters()).device)
113
+ with torch.no_grad():
114
+ org_out = block(x, **kwargs)
115
+ if isinstance(org_out, tuple):
116
+ org_out = org_out[0]
117
+
118
+ x_max = get_act_scale(x)
119
+
120
+ best_error = float("inf")
121
+ best_ratio = -1
122
+ best_scales = None
123
+
124
+ n_grid = 20
125
+ history = []
126
+
127
+ org_sd = {k: v.cpu() for k, v in block.state_dict().items()}
128
+ for ratio in range(n_grid):
129
+ ratio = ratio * 1 / n_grid
130
+ scales = x_max.pow(ratio).clamp(min=1e-4).view(-1)
131
+ scales = scales / (scales.max() * scales.min()).sqrt()
132
+ for fc in linears2scale:
133
+ fc.weight.mul_(scales.view(1, -1).to(fc.weight.device))
134
+ fc.weight.data = w_quantize_func(fc.weight.data) / (scales.view(1, -1))
135
+ out = block(x, **kwargs)
136
+ if isinstance(out, tuple):
137
+ out = out[0]
138
+
139
+ loss = (
140
+ (org_out - out).float().pow(2).mean().item()
141
+ ) # float prevents overflow
142
+ history.append(loss)
143
+ is_best = loss < best_error
144
+ if is_best:
145
+ best_error = loss
146
+ best_ratio = ratio
147
+ best_scales = scales
148
+ block.load_state_dict(org_sd)
149
+ if best_ratio == -1:
150
+ print(history)
151
+ raise Exception
152
+ # print(best_ratio)
153
+ best_scales = best_scales.view(-1)
154
+
155
+ assert torch.isnan(best_scales).sum() == 0, best_scales
156
+ return best_scales.detach()
157
+
158
+ def _auto_get_scale(prev_op, layers, inp, module2inspect=None, kwargs={}):
159
+ # module2inspect: if given, we will check the output diff of this module instead of layers
160
+ if module2inspect is None:
161
+ assert len(layers) == 1
162
+ module2inspect = layers[0]
163
+
164
+ scales = _search_module_scale(module2inspect, layers, inp, kwargs)
165
+ scales = scales.detach().cpu()
166
+ # prev_op_name, [layer_name], scale
167
+ return (
168
+ get_op_name(module, prev_op),
169
+ tuple([get_op_name(module, m) for m in layers]),
170
+ scales,
171
+ )
172
+
173
+ scales_list = [] # return the searched scales
174
+
175
+ if isinstance(module, OPTDecoderLayer):
176
+ # attention input
177
+ scales_list.append(
178
+ _auto_get_scale(
179
+ prev_op=module.self_attn_layer_norm,
180
+ layers=[
181
+ module.self_attn.q_proj,
182
+ module.self_attn.k_proj,
183
+ module.self_attn.v_proj,
184
+ ],
185
+ inp=input_feat["self_attn.q_proj"],
186
+ module2inspect=module.self_attn,
187
+ kwargs=module_kwargs,
188
+ )
189
+ )
190
+ # attn out
191
+ scales_list.append(
192
+ _auto_get_scale(
193
+ prev_op=module.self_attn.v_proj,
194
+ layers=[module.self_attn.out_proj],
195
+ inp=input_feat["self_attn.out_proj"],
196
+ )
197
+ )
198
+ # fc1
199
+ scales_list.append(
200
+ _auto_get_scale(
201
+ prev_op=module.final_layer_norm,
202
+ layers=[module.fc1],
203
+ inp=input_feat["fc1"],
204
+ )
205
+ )
206
+ # fc2
207
+ scales_list.append(
208
+ _auto_get_scale(
209
+ prev_op=module.fc1,
210
+ layers=[module.fc2],
211
+ inp=input_feat["fc2"],
212
+ )
213
+ )
214
+
215
+ elif isinstance(module, (LlamaDecoderLayer, Qwen2DecoderLayer)):
216
+ # attention input
217
+ scales_list.append(
218
+ _auto_get_scale(
219
+ prev_op=module.input_layernorm,
220
+ layers=[
221
+ module.self_attn.q_proj,
222
+ module.self_attn.k_proj,
223
+ module.self_attn.v_proj,
224
+ ],
225
+ inp=input_feat["self_attn.q_proj"],
226
+ module2inspect=module.self_attn,
227
+ kwargs=module_kwargs,
228
+ )
229
+ )
230
+ # attn out
231
+ # Please refer to https://github.com/mit-han-lab/llm-awq/pull/67#issue-1850622696
232
+ if module.self_attn.v_proj.weight.shape == module.self_attn.o_proj.weight.shape:
233
+ scales_list.append(
234
+ _auto_get_scale(
235
+ prev_op=module.self_attn.v_proj,
236
+ layers=[module.self_attn.o_proj],
237
+ inp=input_feat["self_attn.o_proj"],
238
+ )
239
+ )
240
+ # fc1
241
+ scales_list.append(
242
+ _auto_get_scale(
243
+ prev_op=module.post_attention_layernorm,
244
+ layers=[module.mlp.gate_proj, module.mlp.up_proj],
245
+ inp=input_feat["mlp.gate_proj"],
246
+ module2inspect=module.mlp,
247
+ )
248
+ )
249
+ # fc2
250
+ scales_list.append(
251
+ _auto_get_scale(
252
+ prev_op=module.mlp.up_proj,
253
+ layers=[module.mlp.down_proj],
254
+ inp=input_feat["mlp.down_proj"],
255
+ )
256
+ )
257
+
258
+ elif isinstance(module, BloomBlock):
259
+ # attention input
260
+ scales_list.append(
261
+ _auto_get_scale(
262
+ prev_op=module.input_layernorm,
263
+ layers=[module.self_attention.query_key_value],
264
+ inp=input_feat["self_attention.query_key_value"],
265
+ module2inspect=module,
266
+ kwargs=module_kwargs,
267
+ )
268
+ )
269
+ # attn out
270
+ # Please refer to https://github.com/mit-han-lab/llm-awq/issues/2#issuecomment-1606297469
271
+ """
272
+ scales_list.append(_auto_get_scale(
273
+ prev_op=module.self_attention.query_key_value,
274
+ layers=[module.self_attention.dense],
275
+ inp=input_feat['self_attention.dense'],
276
+ ))
277
+ """
278
+ # fc1
279
+ scales_list.append(
280
+ _auto_get_scale(
281
+ prev_op=module.post_attention_layernorm,
282
+ layers=[module.mlp.dense_h_to_4h],
283
+ inp=input_feat["mlp.dense_h_to_4h"],
284
+ module2inspect=module,
285
+ kwargs=module_kwargs,
286
+ )
287
+ )
288
+ # fc2
289
+ scales_list.append(
290
+ _auto_get_scale(
291
+ prev_op=module.mlp.gelu_impl,
292
+ layers=[module.mlp.dense_4h_to_h],
293
+ inp=input_feat["mlp.dense_4h_to_h"],
294
+ )
295
+ )
296
+ elif "mpt" in str(module.__class__).lower():
297
+ # attention input
298
+ scales_list.append(
299
+ _auto_get_scale(
300
+ prev_op=module.norm_1,
301
+ layers=[module.attn.Wqkv],
302
+ inp=input_feat["attn.Wqkv"],
303
+ module2inspect=module.attn,
304
+ kwargs=module_kwargs,
305
+ )
306
+ )
307
+
308
+ # attn out
309
+ scales_list.append(
310
+ _auto_get_scale(
311
+ prev_op=module.attn.Wqkv,
312
+ layers=[module.attn.out_proj],
313
+ inp=input_feat["attn.out_proj"],
314
+ )
315
+ )
316
+ # fc1
317
+ scales_list.append(
318
+ _auto_get_scale(
319
+ prev_op=module.norm_2,
320
+ layers=[module.ffn.up_proj],
321
+ inp=input_feat["ffn.up_proj"],
322
+ module2inspect=module.ffn,
323
+ )
324
+ )
325
+ # fc2
326
+ scales_list.append(
327
+ _auto_get_scale(
328
+ prev_op=module.ffn.act,
329
+ layers=[module.ffn.down_proj],
330
+ inp=input_feat["ffn.down_proj"],
331
+ )
332
+ )
333
+
334
+ elif "falcon" in str(module.__class__).lower():
335
+ # attn out
336
+ # Haotian: TBD: need to handle repeated scales for MQ
337
+ """
338
+ scales_list.append(_auto_get_scale(
339
+ prev_op=module.self_attention.query_key_value,
340
+ layers=[module.self_attention.dense],
341
+ inp=input_feat['self_attention.dense'],
342
+ ))
343
+ """
344
+ # fc1, as long as it is scaled, everything is screwed up
345
+ if "falcon-7b" in str(module.__class__).lower():
346
+ scales_list.append(
347
+ _auto_get_scale(
348
+ prev_op=module.input_layernorm,
349
+ layers=[
350
+ module.mlp.dense_h_to_4h,
351
+ module.self_attention.query_key_value,
352
+ ],
353
+ inp=input_feat["self_attention.query_key_value"],
354
+ module2inspect=module,
355
+ kwargs=module_kwargs,
356
+ )
357
+ )
358
+ elif "falcon-40b" in str(module.__class__).lower():
359
+ scales_list.append(
360
+ _auto_get_scale(
361
+ prev_op=module.ln_attn,
362
+ layers=[module.self_attention.query_key_value],
363
+ inp=input_feat["self_attention.query_key_value"],
364
+ module2inspect=module,
365
+ kwargs=module_kwargs,
366
+ )
367
+ )
368
+ scales_list.append(
369
+ _auto_get_scale(
370
+ prev_op=module.ln_mlp,
371
+ layers=[module.mlp.dense_h_to_4h],
372
+ inp=input_feat["mlp.dense_h_to_4h"],
373
+ module2inspect=module,
374
+ kwargs=module_kwargs,
375
+ )
376
+ )
377
+ else:
378
+ raise NotImplementedError(
379
+ "Unknown Falcon architecture, currently only falcon-7b and falcon-40b are supported"
380
+ )
381
+ # fc2
382
+ scales_list.append(
383
+ _auto_get_scale(
384
+ prev_op=module.mlp.act,
385
+ layers=[module.mlp.dense_4h_to_h],
386
+ inp=input_feat["mlp.dense_4h_to_h"],
387
+ )
388
+ )
389
+ elif "bigcode" in str(module.__class__).lower():
390
+ scales_list.append(
391
+ _auto_get_scale(
392
+ prev_op=module.ln_1,
393
+ layers=[module.attn.c_attn],
394
+ inp=input_feat["attn.c_attn"],
395
+ module2inspect=module.attn,
396
+ kwargs=module_kwargs,
397
+ )
398
+ )
399
+ # fc1
400
+ scales_list.append(
401
+ _auto_get_scale(
402
+ prev_op=module.ln_2,
403
+ layers=[module.mlp.c_fc],
404
+ inp=input_feat["mlp.c_fc"],
405
+ module2inspect=module.mlp,
406
+ )
407
+ )
408
+ # fc2
409
+ scales_list.append(
410
+ _auto_get_scale(
411
+ prev_op=module.mlp.act,
412
+ layers=[module.mlp.c_proj],
413
+ inp=input_feat["mlp.c_proj"],
414
+ )
415
+ )
416
+ elif "neox" in str(module.__class__).lower():
417
+ scales_list.append(
418
+ _auto_get_scale(
419
+ prev_op=module.input_layernorm,
420
+ layers=[module.attention.query_key_value],
421
+ inp=input_feat["attention.query_key_value"],
422
+ module2inspect=module.attention,
423
+ kwargs=module_kwargs,
424
+ )
425
+ )
426
+ # fc1
427
+ scales_list.append(
428
+ _auto_get_scale(
429
+ prev_op=module.post_attention_layernorm,
430
+ layers=[module.mlp.dense_h_to_4h],
431
+ inp=input_feat["mlp.dense_h_to_4h"],
432
+ module2inspect=module.mlp,
433
+ )
434
+ )
435
+ # fc2
436
+ scales_list.append(
437
+ _auto_get_scale(
438
+ prev_op=module.mlp.act,
439
+ layers=[module.mlp.dense_4h_to_h],
440
+ inp=input_feat["mlp.dense_4h_to_h"],
441
+ )
442
+ )
443
+ else:
444
+ raise NotImplementedError(f"{type(module)} not supported yet!")
445
+
446
+ return scales_list
447
+
448
+
449
+ def apply_scale(module, scales_list, input_feat_dict=None):
450
+ for prev_op_name, layer_names, scales in scales_list:
451
+ prev_op = get_op_by_name(module, prev_op_name)
452
+ layers = [get_op_by_name(module, name) for name in layer_names]
453
+
454
+ prev_op.cuda()
455
+ for layer in layers:
456
+ layer.cuda()
457
+ scales.cuda()
458
+
459
+ if isinstance(prev_op, nn.Linear):
460
+ assert len(layers) == 1
461
+ scale_fc_fc(prev_op, layers[0], scales)
462
+ elif isinstance(prev_op, (nn.LayerNorm, LlamaRMSNorm, Qwen2RMSNorm)):
463
+ scale_ln_fcs(prev_op, layers, scales)
464
+ elif isinstance(prev_op, (nn.GELU, BloomGelu, GELUActivation, nn.SiLU)):
465
+ new_module = ScaledActivation(prev_op, scales)
466
+ set_op_by_name(module, prev_op_name, new_module)
467
+ scale_gelu_fc(prev_op, layers[0], scales)
468
+ else:
469
+ raise NotImplementedError(f"prev_op {type(prev_op)} not supported yet!")
470
+
471
+ # apply the scaling to input feat if given; prepare it for clipping
472
+ if input_feat_dict is not None:
473
+ for layer_name in layer_names:
474
+ inp = input_feat_dict[layer_name]
475
+ inp.div_(scales.view(1, -1).to(inp.device).to(inp.dtype))
476
+
477
+ prev_op.cpu()
478
+ for layer in layers:
479
+ layer.cpu()
480
+ scales.cpu()
llm-awq/awq/quantize/pre_quant.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import tqdm
4
+ import gc
5
+ import functools
6
+ from collections import defaultdict
7
+ from typing import List
8
+
9
+ from transformers.models.bloom.modeling_bloom import BloomForCausalLM
10
+ from transformers.models.opt.modeling_opt import OPTForCausalLM
11
+ from transformers.models.llama.modeling_llama import LlamaForCausalLM
12
+ try:
13
+ from tinychat.models import LlavaLlamaForCausalLM
14
+ except ImportError as e:
15
+ pass
16
+
17
+ from transformers.models.qwen2.modeling_qwen2 import Qwen2ForCausalLM
18
+
19
+ from .auto_scale import auto_scale_block, apply_scale
20
+ from .auto_clip import auto_clip_block, apply_clip
21
+
22
+ __all__ = ["run_awq"]
23
+
24
+
25
+ def get_named_linears(module):
26
+ return {name: m for name, m in module.named_modules() if isinstance(m, nn.Linear)}
27
+
28
+
29
+ def get_blocks(model):
30
+ if model.__class__.__name__ in ("LlamaForCausalLM", "Qwen2ForCausalLM"):
31
+ layers = model.model.layers
32
+ elif model.__class__.__name__ == "InternVL3":
33
+ layers = model.language_model.model.layers
34
+ # layers = [model.language_model.model.layers, model.vision_model.encoder.layers]
35
+ elif model.__class__.__name__ == "LlavaLlamaForCausalLM":
36
+ # layers = [model.model.layers, model.model.vision_tower.vision_tower.vision_model.encoder.layers]
37
+ layers = model.model.layers
38
+ elif isinstance(model, OPTForCausalLM):
39
+ layers = model.model.decoder.layers
40
+ elif isinstance(model, BloomForCausalLM):
41
+ layers = model.transformer.h
42
+ elif "mpt" in str(model.__class__).lower():
43
+ layers = model.transformer.blocks
44
+ elif "falcon" in str(model.__class__).lower():
45
+ layers = model.transformer.h
46
+ elif "bigcode" in str(model.__class__).lower():
47
+ layers = model.transformer.h
48
+ elif "neox" in str(model.__class__).lower():
49
+ layers = model.gpt_neox.layers
50
+ elif model.__class__.__name__ == "LlavaLlamaModel":
51
+ layers = model.llm.model.layers
52
+ else:
53
+ raise NotImplementedError(type(model))
54
+ return layers
55
+
56
+
57
+ def move_embed(model, device):
58
+ if isinstance(model, (LlamaForCausalLM, Qwen2ForCausalLM)):
59
+ model.model.embed_tokens = model.model.embed_tokens.to(device)
60
+ model.model.rotary_emb = model.model.rotary_emb.to(device)
61
+ elif model.__class__.__name__ == "InternVL3":
62
+ model.language_model.model.embed_tokens = (
63
+ model.language_model.model.embed_tokens.to(device)
64
+ )
65
+ model.language_model.model.rotary_emb = (
66
+ model.language_model.model.rotary_emb.to(device)
67
+ )
68
+ model.vision_model.embeddings.to(device)
69
+ elif isinstance(model, LlavaLlamaForCausalLM):
70
+ model.model.embed_tokens = model.model.embed_tokens.to(device)
71
+ model.model.vision_tower.vision_tower.vision_model.embeddings.to(device)
72
+ elif isinstance(model, OPTForCausalLM):
73
+ model.model.decoder.embed_tokens = model.model.decoder.embed_tokens.to(device)
74
+ model.model.decoder.embed_positions = model.model.decoder.embed_positions.to(
75
+ device
76
+ )
77
+ elif isinstance(model, BloomForCausalLM):
78
+ model.transformer.word_embeddings = model.transformer.word_embeddings.to(device)
79
+ model.transformer.word_embeddings_layernorm = (
80
+ model.transformer.word_embeddings_layernorm.to(device)
81
+ )
82
+ elif "mpt" in str(model.__class__).lower():
83
+ model.transformer.wte = model.transformer.wte.to(device)
84
+ model.transformer.emb_drop = model.transformer.emb_drop.to(device)
85
+ elif "falcon" in str(model.__class__).lower():
86
+ model.transformer.word_embeddings = model.transformer.word_embeddings.to(device)
87
+ elif "bigcode" in str(model.__class__).lower():
88
+ model.transformer.wte = model.transformer.wte.to(device)
89
+ model.transformer.wpe = model.transformer.wpe.to(device)
90
+ model.transformer.drop = model.transformer.drop.to(device)
91
+ elif "neox" in str(model.__class__).lower():
92
+ model.gpt_neox.embed_in = model.gpt_neox.embed_in.to(device)
93
+ model.gpt_neox.emb_dropout = model.gpt_neox.emb_dropout.to(device)
94
+ model.embed_out = model.embed_out.to(device)
95
+ elif "llavallamamodel" in str(model.__class__).lower():
96
+ model.llm.model.embed_tokens = model.llm.model.embed_tokens.to(device)
97
+ else:
98
+ raise NotImplementedError(type(model))
99
+
100
+
101
+ @torch.no_grad()
102
+ def run_awq(
103
+ model,
104
+ enc,
105
+ w_bit,
106
+ q_config,
107
+ n_samples=512,
108
+ seqlen=512,
109
+ auto_scale=True,
110
+ mse_range=True,
111
+ # some configs for ablation study
112
+ calib_data="pileval",
113
+ ):
114
+ from ..utils.calib_data import get_calib_dataset
115
+ from ..utils.module import append_str_prefix, get_op_name
116
+
117
+ if "bigcode" in str(model.__class__).lower():
118
+ # otherwise attention_mask will always be on cpu.
119
+ model.transformer.bias = model.transformer.bias.to("cuda")
120
+
121
+ layers = get_blocks(model)
122
+
123
+ samples = get_calib_dataset(
124
+ data=calib_data, tokenizer=enc, n_samples=n_samples, block_size=seqlen
125
+ )
126
+ samples = torch.cat(samples, dim=0)
127
+
128
+ inps = []
129
+ layer_kwargs = {}
130
+
131
+ layers[0] = layers[0].cuda()
132
+ move_embed(model, "cuda")
133
+
134
+ # get input and kwargs to layer 0
135
+ # with_kwargs is only supported in PyTorch 2.0
136
+ # use this Catcher hack for now
137
+ class Catcher(nn.Module):
138
+ def __init__(self, module):
139
+ super().__init__()
140
+ self.module = module
141
+
142
+ def forward(self, inp, **kwargs):
143
+ inps.append(inp)
144
+ layer_kwargs.update(kwargs)
145
+ raise ValueError # early exit to break later inference
146
+
147
+ # patch layer 0 to catch input and kwargs
148
+ layers[0] = Catcher(layers[0])
149
+ try:
150
+ if model.__class__.__name__ == "LlavaLlamaModel":
151
+ model.llm(samples.to(next(model.parameters()).device))
152
+ elif model.__class__.__name__ == "InternVL3":
153
+ model.language_model(samples.to(next(model.parameters()).device))
154
+ else:
155
+ model(samples.to(next(model.parameters()).device))
156
+ except ValueError: # work with early exit
157
+ pass
158
+ del samples
159
+ layers[0] = layers[0].module # restore
160
+ inps = inps[0]
161
+
162
+ layers[0] = layers[0].cpu()
163
+ move_embed(model, "cpu")
164
+
165
+ gc.collect()
166
+ torch.cuda.empty_cache()
167
+
168
+ awq_results = {
169
+ "scale": [],
170
+ "clip": [],
171
+ }
172
+
173
+ # solve layer by layer
174
+ for i in tqdm.tqdm(range(len(layers)), desc="Running AWQ..."):
175
+ layer = layers[i]
176
+ layer = layer.cuda()
177
+ named_linears = get_named_linears(layer)
178
+
179
+ # firstly, get input features of all linear layers
180
+ def cache_input_hook(m, x, y, name, feat_dict):
181
+ x = x[0]
182
+ x = x.detach().cpu()
183
+ feat_dict[name].append(x)
184
+
185
+ input_feat = defaultdict(list)
186
+ handles = []
187
+ for name in named_linears:
188
+ handles.append(
189
+ named_linears[name].register_forward_hook(
190
+ functools.partial(cache_input_hook, name=name, feat_dict=input_feat)
191
+ )
192
+ )
193
+ inps = inps.to(next(layer.parameters()).device) # in case multi-gpu
194
+ # get output as next layer's input
195
+ inps = layer(inps, **layer_kwargs)[0]
196
+ for h in handles:
197
+ h.remove()
198
+ # now solve for scaling and clipping
199
+ input_feat = {k: torch.cat(v, dim=0) for k, v in input_feat.items()}
200
+
201
+ # Clear GPU memory
202
+ torch.cuda.empty_cache()
203
+
204
+ if (
205
+ auto_scale
206
+ ): # if it applies, we should also modify the input_feat with scales
207
+ scales_list = auto_scale_block(
208
+ layer,
209
+ layer_kwargs,
210
+ w_bit=w_bit,
211
+ q_config=q_config,
212
+ input_feat=input_feat,
213
+ )
214
+ # apply_scale(layer, scales_list, input_feat_dict=input_feat)
215
+ apply_scale(layers[i], scales_list, input_feat_dict=input_feat)
216
+ # append prefix to make names global
217
+ awq_results["scale"] += append_str_prefix(
218
+ scales_list, get_op_name(model, layer) + "."
219
+ )
220
+
221
+ # Clear GPU memory
222
+ torch.cuda.empty_cache()
223
+ # for line in torch.cuda.memory_summary().splitlines():
224
+ # if "Allocated" in line:
225
+ # print(line)
226
+
227
+ if mse_range:
228
+ clip_list = auto_clip_block(
229
+ layer,
230
+ w_bit=w_bit,
231
+ q_config=q_config,
232
+ input_feat=input_feat,
233
+ )
234
+ apply_clip(layer, clip_list)
235
+ # append prefix to make names global
236
+ awq_results["clip"] += append_str_prefix(
237
+ clip_list, get_op_name(model, layer) + "."
238
+ )
239
+
240
+ layer = layer.cpu()
241
+ # Haotian: check activation replacement
242
+ del input_feat
243
+ gc.collect()
244
+ torch.cuda.empty_cache()
245
+ # for line in torch.cuda.memory_summary().splitlines():
246
+ # if "Allocated" in line:
247
+ # print(line)
248
+
249
+ return awq_results
250
+
251
+
252
+ def apply_awq(model, awq_results):
253
+ apply_scale(model, awq_results["scale"])
254
+ apply_clip(model, awq_results["clip"])
llm-awq/awq/quantize/qmodule.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import torch.nn as nn
4
+ import awq_inference_engine # with CUDA kernels
5
+
6
+
7
+ def make_divisible(c, divisor):
8
+ return (c + divisor - 1) // divisor
9
+
10
+
11
+ def calculate_zeros_width(in_features, group_size=128, pack_num=8):
12
+ if group_size >= 128:
13
+ size_multiplier = 1
14
+ elif group_size == 64:
15
+ size_multiplier = 2
16
+ elif group_size == 32:
17
+ size_multiplier = 4
18
+ else:
19
+ raise NotImplementedError
20
+
21
+ base_width = make_divisible(in_features // group_size, pack_num)
22
+ base_width = make_divisible(base_width, size_multiplier) * size_multiplier
23
+ return base_width
24
+
25
+
26
+ def pack_intweight(unpacked_qweight, interleave, kstride):
27
+ # unpacked_qweight: [N, K]
28
+ N = unpacked_qweight.shape[0]
29
+ K = unpacked_qweight.shape[1]
30
+
31
+ Packed_Kernel = unpacked_qweight.cpu().numpy().reshape(N, K // 32, 32)
32
+ # np.arange(32).reshape(4, 4, 2).transpose(1, 0, 2) => [0, 1, 8, 9, 16, 17, 24, 25, ...]
33
+ Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 4, 4, 2).transpose(0, 1, 3, 2, 4)
34
+ Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 32)
35
+
36
+ # reorder each 8 weights for fast dequantization
37
+ # [0, 1, 2, 3, 4, 5, 6, 7] => [0, 2, 4, 6, 1, 3, 5, 7]
38
+ Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 4, 8)
39
+ Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 4, 4, 2).transpose(0, 1, 2, 4, 3)
40
+ Packed_Kernel = Packed_Kernel.reshape(N, K)
41
+
42
+ # interleaving every four rows
43
+ Packed_Kernel = Packed_Kernel.reshape(
44
+ N // interleave, interleave, K // kstride, kstride
45
+ )
46
+ # N // 4, K // 64, 4, 64
47
+ Packed_Kernel = Packed_Kernel.transpose(0, 2, 1, 3)
48
+ Packed_Kernel = Packed_Kernel.reshape(
49
+ N // interleave, K // kstride, kstride, interleave
50
+ )
51
+ # Packing -> (N // 4, K // 64, 64)
52
+ Packed_Kernel = (
53
+ Packed_Kernel[..., 0]
54
+ | (Packed_Kernel[..., 1] << 4)
55
+ | (Packed_Kernel[..., 2] << 8)
56
+ | (Packed_Kernel[..., 3] << 12)
57
+ )
58
+ # reshape to (N // 4, K), FP16 format
59
+ Packed_Kernel = Packed_Kernel.reshape(N // interleave, K)
60
+ qweight = (
61
+ torch.tensor(Packed_Kernel.astype("int16"))
62
+ .to(unpacked_qweight.device)
63
+ .contiguous()
64
+ )
65
+ return qweight
66
+
67
+
68
+ class ScaledActivation(nn.Module):
69
+ def __init__(self, module, scales):
70
+ super().__init__()
71
+ self.act = module
72
+ self.scales = nn.Parameter(scales.data)
73
+
74
+ def forward(self, x):
75
+ return self.act(x) / self.scales.view(1, 1, -1).to(x.device)
76
+
77
+
78
+ class WQLinear(nn.Module):
79
+ def __init__(self, w_bit, group_size, in_features, out_features, bias, dev, dtype=torch.float16):
80
+ super().__init__()
81
+
82
+ if w_bit not in [4]:
83
+ raise NotImplementedError("Only 4-bit are supported for now.")
84
+
85
+ self.in_features = in_features
86
+ self.out_features = out_features
87
+ self.w_bit = w_bit
88
+ self.group_size = group_size if group_size != -1 else in_features
89
+ self.split_k_iters = 8
90
+ self.interleave = 4
91
+ # quick sanity check (make sure aligment)
92
+ assert self.in_features % self.group_size == 0
93
+ assert out_features % (32 // self.w_bit) == 0
94
+ pack_num = 32 // self.w_bit
95
+ int16_pack_num = 16 // self.w_bit
96
+
97
+ assert out_features % (self.interleave) == 0
98
+ self.register_buffer(
99
+ "qweight",
100
+ torch.zeros(
101
+ (
102
+ out_features // self.interleave,
103
+ in_features // int16_pack_num * self.interleave,
104
+ ),
105
+ dtype=torch.int16,
106
+ device=dev,
107
+ ),
108
+ )
109
+ self.register_buffer(
110
+ "scales",
111
+ torch.zeros(
112
+ (
113
+ calculate_zeros_width(in_features, self.group_size) * pack_num,
114
+ out_features,
115
+ ),
116
+ dtype=dtype,
117
+ device=dev,
118
+ ),
119
+ )
120
+ self.register_buffer(
121
+ "scaled_zeros",
122
+ torch.zeros(
123
+ (
124
+ calculate_zeros_width(in_features, self.group_size) * pack_num,
125
+ out_features,
126
+ ),
127
+ dtype=dtype,
128
+ device=dev,
129
+ ),
130
+ )
131
+
132
+ if bias:
133
+ self.register_buffer(
134
+ "bias", torch.zeros((out_features), dtype=dtype, device=dev)
135
+ )
136
+ else:
137
+ self.bias = None
138
+
139
+ @classmethod
140
+ def from_linear(
141
+ cls, linear, w_bit, group_size, init_only=False, scales=None, zeros=None
142
+ ):
143
+ awq_linear = cls(
144
+ w_bit,
145
+ group_size,
146
+ linear.in_features,
147
+ linear.out_features,
148
+ linear.bias is not None,
149
+ linear.weight.device,
150
+ dtype=linear.weight.data.dtype
151
+ )
152
+ if init_only: # just prepare for loading sd
153
+ return awq_linear
154
+
155
+ # need scales and zeros info for real quantization
156
+ assert scales is not None and zeros is not None
157
+ scale_zeros = zeros * scales
158
+
159
+ dtype = scales.dtype
160
+
161
+ pack_num = 32 // awq_linear.w_bit
162
+ qscales = torch.zeros(
163
+ (
164
+ scales.shape[0],
165
+ calculate_zeros_width(linear.in_features, group_size) * pack_num,
166
+ ),
167
+ dtype=dtype,
168
+ device=scales.device,
169
+ )
170
+ qscales[:, : scales.shape[1]] = scales
171
+ # awq_linear.scales = scales.clone().half()
172
+ awq_linear.scales = qscales.transpose(1, 0).contiguous()
173
+ if linear.bias is not None:
174
+ awq_linear.bias = linear.bias.clone().to(dtype)
175
+
176
+ intweight = []
177
+ for idx in range(awq_linear.in_features):
178
+ intweight.append(
179
+ torch.round(
180
+ (linear.weight.data[:, idx] + scale_zeros[:, idx // group_size])
181
+ / qscales[:, idx // group_size]
182
+ ).to(torch.int)[:, None]
183
+ )
184
+ intweight = torch.cat(intweight, dim=1)
185
+ # intweight = intweight.t().contiguous()
186
+ intweight = intweight.to(dtype=torch.int32)
187
+ awq_linear.qweight = pack_intweight(
188
+ intweight.contiguous(), interleave=4, kstride=64
189
+ )
190
+
191
+ zeros = zeros.to(dtype=torch.int32)
192
+ scaled_zeros = torch.zeros_like(qscales)
193
+ # scaled_zeros[:, :scales.shape[1]] = -(qscales[:, :scales.shape[1]] * (zeros.to(torch.float32) - 8.0)).to(torch.float16)
194
+ scaled_zeros[:, : scales.shape[1]] = -(
195
+ qscales[:, : scales.shape[1]] * (zeros.to(torch.float32))
196
+ ).to(dtype)
197
+ awq_linear.scaled_zeros = scaled_zeros.transpose(1, 0).contiguous()
198
+
199
+ return awq_linear
200
+
201
+ @torch.no_grad()
202
+ def forward(self, x):
203
+ # out_shape = x.shape[:-1] + (self.out_features,)
204
+ # inputs = x.reshape(-1, x.shape[-1])
205
+ inputs = x
206
+ if inputs.numel() / inputs.shape[-1] < 8:
207
+ out = awq_inference_engine.gemv_forward_cuda_new(
208
+ inputs,
209
+ self.qweight,
210
+ self.scales,
211
+ self.scaled_zeros,
212
+ inputs.numel() // inputs.shape[-1],
213
+ self.out_features,
214
+ self.in_features,
215
+ self.group_size,
216
+ )
217
+ else:
218
+ out = awq_inference_engine.gemm_forward_cuda_new(
219
+ inputs, self.qweight, self.scales, self.scaled_zeros
220
+ ) # - 8.0 * self.scales)
221
+ out = out + self.bias if self.bias is not None else out
222
+ # print(out)
223
+ # assert 0
224
+ return out
225
+
226
+ def extra_repr(self) -> str:
227
+ return (
228
+ "in_features={}, out_features={}, bias={}, w_bit={}, group_size={}".format(
229
+ self.in_features,
230
+ self.out_features,
231
+ self.bias is not None,
232
+ self.w_bit,
233
+ self.group_size,
234
+ )
235
+ )
llm-awq/awq/quantize/quantizer.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from tqdm import tqdm
4
+ import gc
5
+ from .qmodule import ScaledActivation
6
+ from ..utils.module import set_op_by_name
7
+
8
+ from transformers.models.bloom.modeling_bloom import BloomBlock
9
+
10
+ EMBEDDING_KEYWORDS = ["embed"]
11
+ LM_HEAD_KEYWORDS = ["lm_head", "embed_out", "output"]
12
+
13
+
14
+ def scale_activations(module):
15
+ param = next(module.parameters())
16
+ dtype = param.dtype
17
+ device = param.device
18
+ if isinstance(module, BloomBlock):
19
+ if isinstance(module.mlp.gelu_impl, ScaledActivation):
20
+ return
21
+ c = module.mlp.dense_h_to_4h.out_features
22
+ act = ScaledActivation(
23
+ module.mlp.gelu_impl, torch.ones(c, dtype=dtype, device=device)
24
+ )
25
+ set_op_by_name(module, "mlp.gelu_impl", act)
26
+ elif "mptblock" in str(module.__class__.__name__).lower():
27
+ if isinstance(module.ffn.act, ScaledActivation):
28
+ return
29
+ c = module.ffn.up_proj.out_features
30
+ act = ScaledActivation(
31
+ module.ffn.act, torch.ones(c, dtype=dtype, device=device)
32
+ )
33
+ set_op_by_name(module, "ffn.act", act)
34
+ elif "falcon" in str(module.__class__).lower():
35
+ if isinstance(module.mlp.act, ScaledActivation):
36
+ return
37
+ c = module.mlp.dense_h_to_4h.out_features
38
+ act = ScaledActivation(
39
+ module.mlp.act, torch.ones(c, dtype=dtype, device=device)
40
+ )
41
+ set_op_by_name(module, "mlp.act", act)
42
+ elif "bigcode" in str(module.__class__).lower():
43
+ if isinstance(module.mlp.act, ScaledActivation):
44
+ return
45
+ c = module.mlp.c_proj.out_features
46
+ act = ScaledActivation(
47
+ module.mlp.act, torch.ones(c, dtype=dtype, device=device)
48
+ )
49
+ set_op_by_name(module, "mlp.act", act)
50
+ elif "neox" in str(module.__class__).lower():
51
+ if isinstance(module.mlp.act, ScaledActivation):
52
+ return
53
+ c = module.mlp.dense_h_to_4h.out_features
54
+ act = ScaledActivation(
55
+ module.mlp.act, torch.ones(c, dtype=dtype, device=device)
56
+ )
57
+ set_op_by_name(module, "mlp.act", act)
58
+
59
+
60
+ # core quantization method (simulated quantization)
61
+ def pseudo_quantize_tensor(
62
+ w, n_bit=8, zero_point=True, q_group_size=-1, inplace=False, get_scale_zp=False
63
+ ):
64
+ org_w_shape = w.shape
65
+ if q_group_size > 0:
66
+ assert org_w_shape[-1] % q_group_size == 0
67
+ w = w.reshape(-1, q_group_size)
68
+ assert w.dim() == 2
69
+ if zero_point:
70
+ max_val = w.amax(dim=1, keepdim=True)
71
+ min_val = w.amin(dim=1, keepdim=True)
72
+ max_int = 2**n_bit - 1
73
+ min_int = 0
74
+ scales = (max_val - min_val).clamp(min=1e-5) / max_int
75
+ zeros = (-torch.round(min_val / scales)).clamp_(min_int, max_int)
76
+ else: # we actually never used this
77
+ assert min_val is None
78
+ max_val = w.abs().amax(dim=1, keepdim=True)
79
+ max_val = max_val.clamp(min=1e-5)
80
+ max_int = 2 ** (n_bit - 1) - 1
81
+ min_int = -(2 ** (n_bit - 1))
82
+ scales = max_val / max_int
83
+ zeros = 0
84
+
85
+ assert torch.isnan(scales).sum() == 0
86
+ assert torch.isnan(w).sum() == 0
87
+
88
+ if inplace:
89
+ (
90
+ (w.div_(scales).round_().add_(zeros)).clamp_(min_int, max_int).sub_(zeros)
91
+ ).mul_(scales)
92
+ else:
93
+ w = (
94
+ torch.clamp(torch.round(w / scales) + zeros, min_int, max_int) - zeros
95
+ ) * scales
96
+ assert torch.isnan(w).sum() == 0
97
+
98
+ w = w.reshape(org_w_shape)
99
+
100
+ if get_scale_zp:
101
+ return w, scales.view(w.shape[0], -1), zeros.view(w.shape[0], -1)
102
+ else:
103
+ return w
104
+
105
+
106
+ @torch.no_grad()
107
+ def pseudo_quantize_model_weight(
108
+ model,
109
+ w_bit,
110
+ q_config,
111
+ ):
112
+ from .pre_quant import get_blocks, get_named_linears
113
+
114
+ layers = get_blocks(model)
115
+ for i in tqdm(range(len(layers)), desc="pseudo weight quantization..."):
116
+ named_linears = get_named_linears(layers[i])
117
+ for n, m in named_linears.items():
118
+ m.cuda()
119
+ m.weight.data = pseudo_quantize_tensor(
120
+ m.weight.data, n_bit=w_bit, **q_config
121
+ )
122
+ m.cpu()
123
+
124
+
125
+ @torch.no_grad()
126
+ def real_quantize_model_weight(model, w_bit, q_config, init_only=False):
127
+ from .qmodule import WQLinear
128
+ from .pre_quant import get_blocks, get_named_linears
129
+
130
+ assert q_config["zero_point"], "We only support zero_point quantization now."
131
+
132
+ layers = get_blocks(model)
133
+ for i in tqdm(
134
+ range(len(layers)),
135
+ desc="real weight quantization..." + ("(init only)" if init_only else ""),
136
+ ):
137
+ layer = layers[i]
138
+ named_linears = get_named_linears(layer)
139
+ scale_activations(layer)
140
+
141
+ for name, module in named_linears.items():
142
+ if init_only:
143
+ q_linear = WQLinear.from_linear(
144
+ module, w_bit, q_config["q_group_size"], True
145
+ )
146
+ q_linear.to(next(layer.parameters()).device)
147
+ set_op_by_name(layer, name, q_linear)
148
+ else:
149
+ module.cuda()
150
+ module.weight.data, scales, zeros = pseudo_quantize_tensor(
151
+ module.weight.data, n_bit=w_bit, get_scale_zp=True, **q_config
152
+ )
153
+ # scales = scales.t().contiguous()
154
+ # zeros = zeros.t().contiguous()
155
+ q_linear = WQLinear.from_linear(
156
+ module, w_bit, q_config["q_group_size"], False, scales, zeros
157
+ )
158
+ module.cpu()
159
+ q_linear.to(next(layer.parameters()).device)
160
+ set_op_by_name(layer, name, q_linear)
161
+ torch.cuda.empty_cache()
162
+ gc.collect()
163
+
164
+ torch.cuda.empty_cache()
165
+ gc.collect()
llm-awq/awq/quantize/smooth.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from SmoothQuant (https://github.com/mit-han-lab/smoothquant) and modified by Yuming Lou
2
+
3
+
4
+ import torch.nn as nn
5
+ try:
6
+ import llava
7
+ from llava.media import Image, Video
8
+ from llava.utils.media import extract_media
9
+ from llava.constants import DEFAULT_IMAGE_TOKEN
10
+ from llava.mm_utils import process_image, process_images
11
+ except ImportError:
12
+ print("VILA is not installed. Multimodal features will not be available. To activate, please install VILA at https://github.com/NVlabs/VILA.")
13
+
14
+ import torch
15
+ from collections import defaultdict
16
+ from functools import partial
17
+ from tqdm import tqdm
18
+ import numpy as np
19
+ import functools
20
+
21
+
22
+ @torch.no_grad()
23
+ def get_act_scales(model, data):
24
+ num_samples = data.shape[0]
25
+ model.eval()
26
+ act_scales = {}
27
+
28
+ def stat_tensor(name, tensor):
29
+ hidden_dim = tensor.shape[-1]
30
+ tensor = tensor.view(-1, hidden_dim).abs().detach()
31
+ comming_max = torch.max(tensor, dim=0)[0].float().cpu()
32
+ if name in act_scales:
33
+ act_scales[name] = torch.max(act_scales[name], comming_max)
34
+ else:
35
+ act_scales[name] = comming_max
36
+
37
+ def stat_input_hook(m, x, y, name):
38
+ if isinstance(x, tuple):
39
+ x = x[0]
40
+ stat_tensor(name, x)
41
+
42
+ hooks = []
43
+ for name, m in model.named_modules():
44
+ if isinstance(m, nn.Linear):
45
+ hooks.append(
46
+ m.register_forward_hook(functools.partial(stat_input_hook, name=name))
47
+ )
48
+
49
+ for i in tqdm(range(num_samples)):
50
+ input = data[i : i + 1]
51
+ model(input)
52
+
53
+ for h in hooks:
54
+ h.remove()
55
+
56
+ return act_scales
57
+
58
+
59
+ @torch.no_grad()
60
+ def get_static_decoder_layer_scales(
61
+ model,
62
+ data,
63
+ ):
64
+ num_samples = data.shape[1]
65
+ model.eval()
66
+ device = next(model.parameters()).device
67
+
68
+ act_dict = defaultdict(dict)
69
+
70
+ def stat_io_hook(m, x, y, name):
71
+ if isinstance(x, tuple):
72
+ x = x[0]
73
+ if name not in act_dict or "input" not in act_dict[name]:
74
+ act_dict[name]["input"] = x.detach().abs().max().item()
75
+ else:
76
+ act_dict[name]["input"] = max(
77
+ act_dict[name]["input"], x.detach().abs().max().item()
78
+ )
79
+ if isinstance(y, tuple):
80
+ y = y[0]
81
+ if name not in act_dict or "output" not in act_dict[name]:
82
+ act_dict[name]["output"] = y.detach().abs().max().item()
83
+ else:
84
+ act_dict[name]["output"] = max(
85
+ act_dict[name]["output"], y.detach().abs().max().item()
86
+ )
87
+
88
+ hooks = []
89
+ for name, m in model.named_modules():
90
+ if isinstance(m, torch.nn.Linear):
91
+ hooks.append(m.register_forward_hook(partial(stat_io_hook, name=name)))
92
+ pbar = tqdm(range(num_samples))
93
+ for i in pbar:
94
+ model(data[i : i + 1])
95
+ mean_scale = np.mean([v["input"] for v in act_dict.values()])
96
+ pbar.set_description(f"Mean input scale: {mean_scale:.2f}")
97
+ for hook in hooks:
98
+ hook.remove()
99
+ decoder_layer_scales = []
100
+ for idx in range(model.config.num_hidden_layers):
101
+ scale_dict = {}
102
+ scale_dict["attn_input_scale"] = (
103
+ act_dict[
104
+ f"vision_tower.vision_model.encoder.layers.{idx}.self_attn.q_proj"
105
+ ]["input"]
106
+ / 127
107
+ )
108
+ scale_dict["q_output_scale"] = (
109
+ act_dict[
110
+ f"vision_tower.vision_model.encoder.layers.{idx}.self_attn.q_proj"
111
+ ]["output"]
112
+ / 127
113
+ )
114
+ scale_dict["k_output_scale"] = (
115
+ act_dict[
116
+ f"vision_tower.vision_model.encoder.layers.{idx}.self_attn.k_proj"
117
+ ]["output"]
118
+ / 127
119
+ )
120
+ scale_dict["v_output_scale"] = (
121
+ act_dict[
122
+ f"vision_tower.vision_model.encoder.layers.{idx}.self_attn.v_proj"
123
+ ]["output"]
124
+ / 127
125
+ )
126
+ scale_dict["out_input_scale"] = (
127
+ act_dict[
128
+ f"vision_tower.vision_model.encoder.layers.{idx}.self_attn.out_proj"
129
+ ]["input"]
130
+ / 127
131
+ )
132
+ scale_dict["fc1_input_scale"] = (
133
+ act_dict[f"vision_tower.vision_model.encoder.layers.{idx}.mlp.fc1"]["input"]
134
+ / 127
135
+ )
136
+ scale_dict["fc2_input_scale"] = (
137
+ act_dict[f"vision_tower.vision_model.encoder.layers.{idx}.mlp.fc2"]["input"]
138
+ / 127
139
+ )
140
+ decoder_layer_scales.append(scale_dict)
141
+
142
+ return decoder_layer_scales, act_dict
143
+
144
+
145
+ def get_smooth_scale(model_path, media):
146
+ # Load model
147
+ model = llava.load(model_path, devices=[0])
148
+ del model.llm
149
+ del model.mm_projector
150
+ torch.cuda.empty_cache()
151
+ model = model.cuda().eval()
152
+ prompt = []
153
+ if media is not None:
154
+ for m in media or []:
155
+ if any(m.endswith(ext) for ext in [".jpg", ".jpeg", ".png"]):
156
+ m = Image(m)
157
+ elif any(m.endswith(ext) for ext in [".mp4", ".mkv", ".webm"]):
158
+ m = Video(m)
159
+ else:
160
+ raise ValueError(f"Unsupported media type: {m}")
161
+ prompt.append(m)
162
+ conversation = [{"from": "human", "value": prompt}]
163
+ media = extract_media(conversation, model.config)
164
+ for name in media:
165
+ if name == "image":
166
+ if (
167
+ len(media["image"]) == 1
168
+ and model.config.image_aspect_ratio == "dynamic"
169
+ ):
170
+ model.config.image_processor = model.vision_tower.image_processor
171
+ images = process_image(
172
+ media["image"][0], model.config, None, enable_dynamic_res=True
173
+ ).half()
174
+ conversation[0]["value"] = conversation[0]["value"].replace(
175
+ DEFAULT_IMAGE_TOKEN, f"{DEFAULT_IMAGE_TOKEN}\n" * images.shape[0]
176
+ )
177
+ else:
178
+ images = process_images(
179
+ media["image"], model.vision_tower.image_processor, model.config
180
+ ).half()
181
+ media[name] = [image for image in images]
182
+ elif name == "video":
183
+ media[name] = [
184
+ process_images(
185
+ images, model.vision_tower.image_processor, model.config
186
+ ).half()
187
+ for images in media[name]
188
+ ]
189
+ else:
190
+ raise ValueError(f"Unsupported media type: {name}")
191
+ images = torch.cat(media["video"], dim=1)
192
+ model.vision_tower = model.vision_tower.eval()
193
+ decoder_layer_scales = get_act_scales(model.vision_tower, images)
194
+ return decoder_layer_scales
195
+
196
+
197
+ @torch.no_grad()
198
+ def smooth_ln_fcs(ln, fcs, act_scales, alpha=0.5):
199
+ if not isinstance(fcs, list):
200
+ fcs = [fcs]
201
+ assert isinstance(ln, nn.LayerNorm)
202
+ for fc in fcs:
203
+ assert isinstance(fc, nn.Linear)
204
+ assert ln.weight.numel() == fc.in_features == act_scales.numel()
205
+
206
+ device, dtype = fcs[0].weight.device, fcs[0].weight.dtype
207
+ act_scales = act_scales.to(device=device, dtype=dtype)
208
+ weight_scales = torch.cat(
209
+ [fc.weight.abs().max(dim=0, keepdim=True)[0] for fc in fcs], dim=0
210
+ )
211
+ weight_scales = weight_scales.max(dim=0)[0].clamp(min=1e-5)
212
+
213
+ scales = (
214
+ (act_scales.pow(alpha) / weight_scales.pow(1 - alpha))
215
+ .clamp(min=1e-5)
216
+ .to(device)
217
+ .to(dtype)
218
+ )
219
+
220
+ ln.weight.div_(scales)
221
+ ln.bias.div_(scales)
222
+
223
+ for fc in fcs:
224
+ fc.weight.mul_(scales.view(1, -1))
225
+
226
+
227
+ @torch.no_grad()
228
+ def smooth_lm(model, scales, alpha=0.5):
229
+ if "siglip" in str(model.__class__).lower():
230
+ num = 0
231
+ for name, module in model.named_modules():
232
+ if "siglipencoderlayer" in str(module.__class__).lower():
233
+ attn_ln = module.layer_norm1
234
+ qkv = [
235
+ module.self_attn.q_proj,
236
+ module.self_attn.k_proj,
237
+ module.self_attn.v_proj,
238
+ ]
239
+ qkv_input_scales = scales[name + ".self_attn.q_proj"]
240
+ smooth_ln_fcs(attn_ln, qkv, qkv_input_scales, alpha)
241
+
242
+ ffn_ln = module.layer_norm2
243
+ fc1 = module.mlp.fc1
244
+ fc1_input_scales = scales[name + ".mlp.fc1"]
245
+ smooth_ln_fcs(ffn_ln, fc1, fc1_input_scales, alpha)
246
+ num += 1
llm-awq/awq/quantize/w8a8_linear.py ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from qserve (https://github.com/mit-han-lab/qserve/tree/main) and modified by Yuming Lou
2
+
3
+
4
+ from typing import Optional, Union
5
+ from torch.nn import Parameter
6
+ import awq_inference_engine
7
+ import torch
8
+ import gc
9
+ from awq.utils.module import set_op_by_name
10
+ from tqdm import tqdm
11
+
12
+
13
+ class W8A8OF16LinearStaticScale(torch.nn.Module):
14
+ def __init__(
15
+ self,
16
+ in_features: int,
17
+ out_features: int,
18
+ bias: bool = True,
19
+ scale: Union[torch.tensor, float] = 1.0,
20
+ params_dtype: Optional[torch.dtype] = None,
21
+ ):
22
+ super().__init__()
23
+
24
+ # Keep input parameters
25
+ self.in_features = in_features
26
+ self.out_features = out_features
27
+ # size [1] or size [oc]
28
+ self.register_buffer(
29
+ "dequant_scale", torch.ones(out_features, dtype=torch.half)
30
+ )
31
+ # Parameters.
32
+ # NOTE: torch.nn.functional.linear performs XA^T + b and as a result
33
+ # we allocate the transpose.
34
+ self.create_weights()
35
+
36
+ if bias:
37
+ self.bias = torch.empty(
38
+ self.out_features,
39
+ device=torch.cuda.current_device(),
40
+ dtype=torch.float16,
41
+ )
42
+ else:
43
+ self.register_parameter("bias", None)
44
+
45
+ def create_weights(self) -> None:
46
+ self.register_buffer(
47
+ "weight",
48
+ torch.empty(
49
+ self.out_features,
50
+ self.in_features,
51
+ dtype=torch.int8,
52
+ requires_grad=False,
53
+ ),
54
+ )
55
+
56
+ def apply_weights(
57
+ self,
58
+ x: torch.Tensor,
59
+ bias: Optional[torch.Tensor],
60
+ ) -> torch.Tensor:
61
+ raise NotImplementedError
62
+
63
+ def forward(self, input_):
64
+ # Matrix multiply.
65
+ output = self.apply_weights(input_, self.bias)
66
+ output_bias = self.bias
67
+ return output, output_bias
68
+
69
+
70
+ class W8A8OF16LinearDynamicInputScale(W8A8OF16LinearStaticScale):
71
+ def __init__(
72
+ self,
73
+ in_features: int,
74
+ out_features: int,
75
+ bias: bool = True,
76
+ scale: Union[torch.tensor, float] = 1.0,
77
+ params_dtype: Optional[torch.dtype] = None,
78
+ ):
79
+ super().__init__(
80
+ in_features=in_features,
81
+ out_features=out_features,
82
+ bias=bias,
83
+ scale=scale,
84
+ params_dtype=params_dtype,
85
+ )
86
+ if bias:
87
+ self.apply_weights = self.apply_weights_bias
88
+ else:
89
+ self.apply_weights = self.apply_weights_no_bias
90
+
91
+ #W bias. Fused bias and W8A8 GEMM
92
+ def apply_weights_bias(
93
+ self,
94
+ # [batch, tokens, channels]
95
+ x: torch.Tensor,
96
+ # [batch * tokens]
97
+ input_scale: torch.Tensor,
98
+ output_buffer: torch.Tensor,
99
+ bias: torch.Tensor = None,
100
+ ):
101
+ x_shape = x.shape
102
+ if len(x.shape) > 2:
103
+ assert 0, "Not implemented"
104
+ x = x.view(-1, x_shape[-1])
105
+ # If use awq_inference_engine.w8a8_gemm_fuse_bias_forward_cuda
106
+ awq_inference_engine.w8a8_gemm_fuse_bias_forward_cuda(
107
+ x, self.weight, self.dequant_scale, input_scale, output_buffer, bias
108
+ )
109
+ if len(x.shape) > 2:
110
+ assert 0, "Not implemented 2"
111
+ output_buffer = output_buffer.view(*x_shape[:-1], -1)
112
+
113
+ #W/H bias. W8A8 GEMM
114
+ def apply_weights_no_bias(
115
+ self,
116
+ # [batch, tokens, channels]
117
+ x: torch.Tensor,
118
+ # [batch * tokens]
119
+ input_scale: torch.Tensor,
120
+ output_buffer: torch.Tensor,
121
+ bias: torch.Tensor = None,
122
+ ):
123
+ x_shape = x.shape
124
+ if len(x.shape) > 2:
125
+ assert 0, "Not implemented"
126
+ x = x.view(-1, x_shape[-1])
127
+ # If use awq_inference_engine.w8a8_gemm_forward_cuda
128
+ awq_inference_engine.w8a8_gemm_forward_cuda(
129
+ x, self.weight, self.dequant_scale, input_scale, output_buffer
130
+ )
131
+ if len(x.shape) > 2:
132
+ assert 0, "Not implemented 2"
133
+ output_buffer = output_buffer.view(*x_shape[:-1], -1)
134
+
135
+ def forward(self, input_, input_scale, output_buffer):
136
+ # Matrix multiply.
137
+ self.apply_weights(input_, input_scale, output_buffer, self.bias)
138
+
139
+ @classmethod
140
+ def from_linear(
141
+ cls,
142
+ linear,
143
+ init_only=False,
144
+ s1_scale=None,
145
+ fc1=False,
146
+ ):
147
+ q_linear = cls(
148
+ linear.in_features,
149
+ linear.out_features,
150
+ linear.bias is not None,
151
+ )
152
+ if init_only: # just prepare for loading sd
153
+ return q_linear
154
+ if s1_scale is None:
155
+ s1_scale, _ = torch.max(abs(linear.weight.data), dim=-1, keepdim=True)
156
+ s1_scale = s1_scale.clamp_(min=1e-5).div_(127)
157
+
158
+ if linear.bias is not None:
159
+ q_linear.bias = linear.bias.clone().half().contiguous().cuda()
160
+ ## Quantize the weights
161
+ # ---- Quantize the weights to int8 ---- #
162
+ linear_weight = linear.weight.data # OC, IC
163
+ linear_weight = linear_weight.div_(s1_scale.to(linear_weight.device))
164
+ linear_weight = linear_weight.round_().to(torch.int8)
165
+
166
+ q_linear.weight.data[:, :] = linear_weight.half().contiguous().cuda()
167
+
168
+ # ---- Pack the scales ---- #
169
+ q_linear.dequant_scale.data[:] = (
170
+ s1_scale.reshape(-1).half().contiguous().cuda()
171
+ )
172
+ return q_linear.cuda()
173
+
174
+ @classmethod
175
+ def from_qkv(
176
+ cls,
177
+ q,
178
+ k,
179
+ v,
180
+ init_only=False,
181
+ s1_scale=None,
182
+ ):
183
+ q_linear = cls(
184
+ q.in_features,
185
+ q.out_features + k.out_features + v.out_features,
186
+ q.bias is not None,
187
+ )
188
+ if init_only: # just prepare for loading sd
189
+ return q_linear
190
+ weight = torch.cat([q.weight.data, k.weight.data, v.weight.data], dim=0)
191
+
192
+ if s1_scale is None:
193
+ s1_scale, _ = torch.max(abs(weight), dim=-1, keepdim=True)
194
+ s1_scale = s1_scale.clamp_(min=1e-5).div_(127)
195
+
196
+ if q.bias is not None:
197
+ bias = torch.cat([q.bias, k.bias, v.bias], dim=0)
198
+ q_linear.bias = bias.clone().half().contiguous().cuda()
199
+ # ---- Quantize the weights to int8 ---- #
200
+ weight = weight.div_(s1_scale.to(weight.device))
201
+ weight = weight.round_().to(torch.int8)
202
+
203
+ q_linear.weight.data[:, :] = weight.contiguous().cuda()
204
+
205
+ # ---- Pack the scales ---- #
206
+ q_linear.dequant_scale.data[:] = (
207
+ s1_scale.reshape(q.out_features + k.out_features + v.out_features)
208
+ .half()
209
+ .contiguous().cuda()
210
+ )
211
+ return q_linear.cuda()
212
+
213
+
214
+ class FakeW8A8Linear(torch.nn.Module):
215
+ def __init__(
216
+ self, in_features: int, out_features: int, bias: bool = True, wbit: int = 8
217
+ ):
218
+ super().__init__()
219
+ self.weight = torch.nn.Parameter(
220
+ torch.empty(out_features, in_features, dtype=torch.half)
221
+ )
222
+ if bias:
223
+ self.bias = torch.nn.Parameter(
224
+ torch.empty(1, out_features, dtype=torch.half)
225
+ )
226
+ else:
227
+ self.bias = None
228
+ self.wbit = wbit
229
+ self.maxv = 2 ** (wbit - 1) - 1
230
+
231
+ def forward(self, input):
232
+ t_shape = input.shape
233
+ input.view(-1, t_shape[-1])
234
+ scales = input.abs().max(dim=-1, keepdim=True)[0]
235
+ scales.clamp_(min=1e-5).div_(self.maxv)
236
+ input.div_(scales).round_().mul_(scales)
237
+ output = torch.functional.F.linear(input, self.weight, self.bias)
238
+ return output
239
+
240
+ @classmethod
241
+ def from_linear(cls, linear: torch.nn.Linear, wbit=8):
242
+ fake_linear = cls(
243
+ linear.in_features, linear.out_features, linear.bias is not None, wbit
244
+ )
245
+ maxv = 2 ** (wbit - 1) - 1
246
+ scale = (
247
+ torch.max(abs(linear.weight.data.detach()), -1, keepdim=True)[0]
248
+ .clamp_(min=1e-5)
249
+ .div_(maxv)
250
+ )
251
+ weight = linear.weight.data / scale
252
+ weight = weight.round_()
253
+ weight = weight * scale
254
+ fake_linear.weight.copy_(weight.contiguous())
255
+ if linear.bias is not None:
256
+ fake_linear.bias.copy_(
257
+ linear.bias.detach().half().reshape(1, linear.out_features).contiguous()
258
+ )
259
+ else:
260
+ linear.bias = None
261
+ del linear, scale, weight
262
+ torch.cuda.empty_cache()
263
+ return fake_linear
264
+
265
+
266
+ def fake_quant(model, wbit=8):
267
+ for name, m in tqdm(
268
+ model.named_modules(),
269
+ desc="Fake quantizing",
270
+ total=len(list(model.named_modules())),
271
+ ):
272
+ if isinstance(m, torch.nn.Linear):
273
+ FQlinear = FakeW8A8Linear.from_linear(m, wbit)
274
+ del m
275
+ torch.cuda.empty_cache()
276
+ set_op_by_name(model, name, FQlinear)
llm-awq/awq/utils/__init__.py ADDED
File without changes
llm-awq/awq/utils/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (179 Bytes). View file
 
llm-awq/awq/utils/__pycache__/parallel.cpython-311.pyc ADDED
Binary file (1.7 kB). View file
 
llm-awq/awq/utils/lm_eval_adaptor.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import transformers
2
+ import torch
3
+ from lm_eval.base import BaseLM
4
+ import fnmatch
5
+
6
+
7
+ class LMEvalAdaptor(BaseLM):
8
+ def __init__(self, model_name, model, tokenizer, batch_size=1, max_length=-1):
9
+ super().__init__()
10
+
11
+ assert isinstance(batch_size, int)
12
+
13
+ self.model_name = model_name
14
+ self.model = model
15
+ self.model.eval()
16
+
17
+ self.tokenizer = tokenizer
18
+
19
+ # assert isinstance(self.tokenizer, (
20
+ # transformers.GPT2Tokenizer, transformers.GPT2TokenizerFast,
21
+ # transformers.T5Tokenizer, transformers.T5TokenizerFast,
22
+ # )), "this tokenizer has not been checked for compatibility yet!"
23
+
24
+ self.vocab_size = self.tokenizer.vocab_size
25
+
26
+ self._batch_size = batch_size
27
+
28
+ self._max_length = max_length
29
+
30
+ @property
31
+ def eot_token_id(self):
32
+ # we use EOT because end of *text* is more accurate for what we're doing than end of *sentence*
33
+ return self.tokenizer.eos_token_id
34
+
35
+ @property
36
+ def max_length(self):
37
+ if self._max_length != -1:
38
+ return self._max_length
39
+ if hasattr(self.model.config, "n_ctx"):
40
+ return self.model.config.n_ctx
41
+ elif hasattr(self.model.config, "max_position_embeddings"):
42
+ return self.model.config.max_position_embeddings
43
+ elif hasattr(self.model.config, "n_positions"):
44
+ return self.model.config.n_positions
45
+ elif "bloom" in self.model_name:
46
+ return 2048
47
+ elif "llama" in self.model_name:
48
+ return 2048 # TODO: did not check this
49
+ elif "mpt" in self.model_name:
50
+ return 2048
51
+ elif "falcon" in self.model_name:
52
+ return 2048
53
+ else:
54
+ print(self.model.config)
55
+ raise NotImplementedError
56
+
57
+ @property
58
+ def max_gen_toks(self):
59
+ return 256
60
+
61
+ @property
62
+ def batch_size(self):
63
+ return self._batch_size
64
+
65
+ @property
66
+ def device(self):
67
+ return "cuda"
68
+
69
+ def tok_encode(self, string: str):
70
+ return self.tokenizer.encode(string, add_special_tokens=False)
71
+
72
+ def tok_decode(self, tokens):
73
+ return self.tokenizer.decode(tokens)
74
+
75
+ def _model_call(self, inps):
76
+ """
77
+ inps: a torch tensor of shape [batch, sequence]
78
+ the size of sequence may vary from call to call
79
+
80
+ returns: a torch tensor of shape [batch, sequence, vocab] with the
81
+ logits returned from the model
82
+ """
83
+ with torch.no_grad():
84
+ if isinstance(
85
+ self.model,
86
+ transformers.models.t5.modeling_t5.T5ForConditionalGeneration,
87
+ ):
88
+ dec_inps = torch.cat(
89
+ [
90
+ torch.tensor(
91
+ self.model.generation_config.decoder_start_token_id,
92
+ )
93
+ .tile(len(inps), 1)
94
+ .to(inps),
95
+ inps,
96
+ ],
97
+ dim=1,
98
+ )
99
+
100
+ kwargs = {
101
+ "decoder_input_ids": dec_inps,
102
+ }
103
+ else:
104
+ kwargs = {}
105
+ out = self.model(inps, **kwargs)[0]
106
+ if (
107
+ "opt" in self.model_name
108
+ ): # there are a few extra tokens in opt, which we should omit
109
+ return out[:, :, :50257]
110
+ else:
111
+ return out # [:, :, :self.tokenizer.vocab_size]
112
+
113
+ def _model_generate(self, context, max_length, eos_token_id):
114
+ return self.model.generate(
115
+ context, max_length=max_length, eos_token_id=eos_token_id, do_sample=False
116
+ )
llm-awq/awq/utils/module.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def get_op_by_name(module, op_name):
2
+ # get the op by its name relative to the module
3
+ for name, m in module.named_modules():
4
+ if name == op_name:
5
+ return m
6
+ raise ValueError(f"Cannot find op {op_name} in module {module}")
7
+
8
+
9
+ def set_op_by_name(layer, name, new_module):
10
+ levels = name.split(".")
11
+ if len(levels) > 1:
12
+ mod_ = layer
13
+ for l_idx in range(len(levels) - 1):
14
+ if levels[l_idx].isdigit():
15
+ mod_ = mod_[int(levels[l_idx])]
16
+ else:
17
+ mod_ = getattr(mod_, levels[l_idx])
18
+ setattr(mod_, levels[-1], new_module)
19
+ else:
20
+ setattr(layer, name, new_module)
21
+
22
+
23
+ def get_op_name(module, op):
24
+ # get the name of the op relative to the module
25
+ for name, m in module.named_modules():
26
+ if m is op:
27
+ return name
28
+ raise ValueError(f"Cannot find op {op} in module {module}")
29
+
30
+
31
+ def append_str_prefix(x, prefix):
32
+ if isinstance(x, str):
33
+ return prefix + x
34
+ elif isinstance(x, tuple):
35
+ return tuple([append_str_prefix(y, prefix) for y in x])
36
+ elif isinstance(x, list):
37
+ return [append_str_prefix(y, prefix) for y in x]
38
+ else:
39
+ return x