Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- baselines_1/Llama-2-7b-hf_bi_idx_10.json +34 -0
- baselines_1/Llama-2-7b-hf_bi_idx_5.json +34 -0
- baselines_1/Llama-2-7b-hf_zd_idx_10.json +34 -0
- baselines_1/Llama-2-7b-hf_zd_idx_5.json +34 -0
- llm-awq/.gitignore +173 -0
- llm-awq/LICENSE +21 -0
- llm-awq/awq.egg-info/top_level.txt +3 -0
- llm-awq/awq/kernels/csrc/attention/decoder_masked_multihead_attention.h +185 -0
- llm-awq/awq/kernels/csrc/attention/decoder_masked_multihead_attention_template.hpp +1608 -0
- llm-awq/awq/kernels/csrc/attention/setup.py +159 -0
- llm-awq/awq/kernels/csrc/layernorm/layernorm.h +3 -0
- llm-awq/awq/kernels/csrc/layernorm/reduction.cuh +82 -0
- llm-awq/awq/kernels/csrc/position_embedding/pos_encoding_kernels.cu +88 -0
- llm-awq/awq/kernels/csrc/quantization/dequantize.cuh +79 -0
- llm-awq/awq/kernels/csrc/quantization/gemm_cuda.h +4 -0
- llm-awq/awq/kernels/csrc/quantization/gemm_cuda_gen.cu +298 -0
- llm-awq/awq/kernels/csrc/quantization/gemv_cuda.h +9 -0
- llm-awq/awq/kernels/csrc/quantization_new/dequantize.cuh +123 -0
- llm-awq/awq/kernels/csrc/quantization_new/dispatch_utils.cuh +18 -0
- llm-awq/awq/kernels/csrc/quantization_new/gemm/gemm_cuda.cu +1236 -0
- llm-awq/awq/kernels/csrc/quantization_new/gemm/gemm_cuda.h +3 -0
- llm-awq/awq/kernels/csrc/quantization_new/gemm/semaphore.h +109 -0
- llm-awq/awq/kernels/csrc/quantization_new/gemv/gemv_cuda.cu +339 -0
- llm-awq/awq/kernels/csrc/quantization_new/gemv/gemv_cuda.h +12 -0
- llm-awq/awq/kernels/csrc/rope_new/fused_rope_with_pos.cu +407 -0
- llm-awq/awq/kernels/csrc/rope_new/fused_rope_with_pos.h +5 -0
- llm-awq/awq/kernels/csrc/w8a8/act.cu +141 -0
- llm-awq/awq/kernels/csrc/w8a8/act.h +29 -0
- llm-awq/awq/kernels/csrc/w8a8/dispatch_utils.h +14 -0
- llm-awq/awq/kernels/csrc/w8a8/layernorm.cu +232 -0
- llm-awq/awq/kernels/csrc/w8a8/layernorm.h +21 -0
- llm-awq/awq/kernels/csrc/w8a8/quantization.cu +113 -0
- llm-awq/awq/kernels/csrc/w8a8/quantization.h +4 -0
- llm-awq/awq/kernels/csrc/w8a8/utils.cuh +469 -0
- llm-awq/awq/kernels/csrc/w8a8/w8a8_gemm_cuda.cu +953 -0
- llm-awq/awq/kernels/csrc/w8a8/w8a8_gemm_cuda.h +4 -0
- llm-awq/awq/quantize/__init__.py +2 -0
- llm-awq/awq/quantize/__pycache__/w8a8_linear.cpython-311.pyc +0 -0
- llm-awq/awq/quantize/auto_clip.py +98 -0
- llm-awq/awq/quantize/auto_scale.py +480 -0
- llm-awq/awq/quantize/pre_quant.py +254 -0
- llm-awq/awq/quantize/qmodule.py +235 -0
- llm-awq/awq/quantize/quantizer.py +165 -0
- llm-awq/awq/quantize/smooth.py +246 -0
- llm-awq/awq/quantize/w8a8_linear.py +276 -0
- llm-awq/awq/utils/__init__.py +0 -0
- llm-awq/awq/utils/__pycache__/__init__.cpython-311.pyc +0 -0
- llm-awq/awq/utils/__pycache__/parallel.cpython-311.pyc +0 -0
- llm-awq/awq/utils/lm_eval_adaptor.py +116 -0
- 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*>(¶ms.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*>(¶ms.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*>(¶ms.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*>(¶ms.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*>(¶ms.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 |
+
¶ms.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*>(¶ms.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 = ¶ms.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 = ¶ms.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 ? ¶ms.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 |
+
¶ms.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 = ¶ms.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 = ¶ms.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*>(¶ms.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 |
+
¶ms.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*>(¶ms.v[v_offset]);
|
| 1522 |
+
}
|
| 1523 |
+
// Trigger the loads from the V bias buffer.
|
| 1524 |
+
// V_vec v_bias = *reinterpret_cast<const V_vec*>(¶ms.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 |
+
¶ms.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*>(¶ms.out[bhi * Dh + vi]), out);
|
| 1593 |
+
}
|
| 1594 |
+
#else
|
| 1595 |
+
// TODO: support int8_mode?
|
| 1596 |
+
*reinterpret_cast<V_vec*>(¶ms.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
|