Files
wehub-resource-sync ec436095dd
Book-CI / test (macos-latest) (push) Has been cancelled
Book-CI / test (ubuntu-latest) (push) Has been cancelled
Book-CI / test (windows-latest) (push) Has been cancelled
Release Fake Tag / publish (push) Has been cancelled
Deploy / deploy (macos-latest) (push) Has been cancelled
Deploy / deploy (ubuntu-latest) (push) Has been cancelled
Deploy / deploy (windows-latest) (push) Has been cancelled
Release to PyPI / Build & publish sglang-kt (push) Has been cancelled
Release to PyPI / Build kt-kernel (Python 3.11) (push) Has been cancelled
Release to PyPI / Build kt-kernel (Python 3.12) (push) Has been cancelled
Release to PyPI / Publish kt-kernel to PyPI (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:30:03 +08:00

256 lines
7.3 KiB
C++

#ifndef AMX_QUANTIZATION_HPP
#define AMX_QUANTIZATION_HPP
#include <algorithm>
#include <cmath>
#include "amx_config.hpp"
#include "llama.cpp/ggml-impl.h"
#include "llama.cpp/ggml-quants.h"
#include "utils.hpp"
namespace amx {
struct blocks_aligned_q4_0_ref {
static constexpr int block_size = 64;
static constexpr double bytes_per_element = double(sizeof(ggml_half) + double(block_size) / 2) / block_size;
ggml_half* d;
uint8_t* qs;
blocks_aligned_q4_0_ref offset(size_t blck_cnt) const {
blocks_aligned_q4_0_ref re;
re.d = &d[blck_cnt];
re.qs = &qs[blck_cnt * block_size / 2];
return re;
}
static size_t expected_data_size(int64_t k) {
assert(k % block_size == 0);
return (sizeof(ggml_half) + block_size / 2) * (k / block_size);
}
uint8_t* get_qs(int block_idx) { return offset_pointer(qs, block_idx * (block_size / 2)); }
static blocks_aligned_q4_0_ref quantize(const float* RESTRICT x, void* RESTRICT data, int64_t k) {
assert(reinterpret_cast<intptr_t>(data) % 64 == 0);
blocks_aligned_q4_0_ref re;
re.qs = reinterpret_cast<uint8_t*>(data);
re.d = reinterpret_cast<ggml_half*>(offset_pointer(re.qs, k / 2));
static const int qk = block_size;
assert(k % qk == 0);
const int nb = k / qk;
for (int i = 0; i < nb; i++) {
float amax = 0.0f; // absolute max
float max = 0.0f;
for (int j = 0; j < qk; j++) {
const float v = x[i * qk + j];
if (amax < fabsf(v)) {
amax = fabsf(v);
max = v;
}
}
const float d = max / -8;
const float id = d ? 1.0f / d : 0.0f;
re.d[i] = GGML_FP32_TO_FP16(d);
for (int j = 0; j < qk / 2; ++j) {
const float x0 = x[i * qk + 0 + j] * id;
const float x1 = x[i * qk + qk / 2 + j] * id;
const uint8_t xi0 = MIN(15, (int8_t)(x0 + 8.5f));
const uint8_t xi1 = MIN(15, (int8_t)(x1 + 8.5f));
re.get_qs(i)[j] = xi0;
re.get_qs(i)[j] |= xi1 << 4;
}
}
return re;
}
void dequantize(float* y, int64_t k) {
static const int qk = block_size;
assert(k % qk == 0);
const int nb = k / qk;
for (int i = 0; i < nb; i++) {
const float d = GGML_FP16_TO_FP32(this->d[i]);
for (int j = 0; j < qk / 2; ++j) {
const int x0 = (get_qs(i)[j] & 0x0F) - 8;
const int x1 = (get_qs(i)[j] >> 4) - 8;
y[i * qk + j + 0] = x0 * d;
y[i * qk + j + qk / 2] = x1 * d;
}
}
}
};
struct blocks_aligned_q8_0_ref {
static constexpr int block_size = 64;
static constexpr double bytes_per_element = double(sizeof(ggml_half) + block_size) / block_size;
ggml_half* d;
int8_t* qs;
blocks_aligned_q8_0_ref offset(size_t blck_cnt) const {
blocks_aligned_q8_0_ref re;
re.d = &d[blck_cnt];
re.qs = &qs[blck_cnt * block_size];
return re;
}
static size_t expected_data_size(int64_t k) {
assert(k % block_size == 0);
return (sizeof(ggml_half) + block_size) * (k / block_size);
}
int8_t* get_qs(int block_idx) { return offset_pointer(qs, block_idx * block_size); }
static blocks_aligned_q8_0_ref quantize(const float* RESTRICT x, void* RESTRICT data, int64_t k) {
assert(k % block_size == 0);
assert(reinterpret_cast<intptr_t>(data) % 64 == 0);
blocks_aligned_q8_0_ref re;
re.qs = reinterpret_cast<int8_t*>(data);
re.d = reinterpret_cast<ggml_half*>(offset_pointer(re.qs, k));
const int nb = k / block_size;
for (int i = 0; i < nb; i++) {
float amax = 0.0f; // absolute max
for (int j = 0; j < block_size; j++) {
const float v = x[i * block_size + j];
amax = MAX(amax, fabsf(v));
}
const float d = amax / ((1 << 7) - 1);
const float id = d ? 1.0f / d : 0.0f;
re.d[i] = GGML_FP32_TO_FP16(d);
for (int j = 0; j < block_size; ++j) {
const float x0 = x[i * block_size + j] * id;
re.get_qs(i)[j] = roundf(x0);
}
}
return re;
}
void dequantize(float* y, int64_t k) {
static const int qk = block_size;
assert(k % qk == 0);
const int nb = k / qk;
for (int i = 0; i < nb; i++) {
const float d = GGML_FP16_TO_FP32(this->d[i]);
for (int j = 0; j < qk; ++j) {
y[i * qk + j] = get_qs(i)[j] * d;
}
}
}
};
#define MM256_SET_M128I(a, b) _mm256_insertf128_si256(_mm256_castsi128_si256(b), (a), 1)
template <typename Block>
struct Dequantizer {};
const __m256i MASK256_LO = _mm256_set1_epi8(0x0f);
const __m256i MASK256_4HI = _mm256_set1_epi8(0xf0);
const __m256i MASK256_8 = _mm256_set1_epi8(8);
const __m512i MASK512_LO = _mm512_set1_epi8(0x0f);
const __m512i MASK512_4HI = _mm512_set1_epi8(0xf0);
const __m512i MASK512_8 = _mm512_set1_epi8(8);
inline __m256i dequant4x32(const uint8_t* qs) {
const __m128i aux128 = _mm_loadu_si128((const __m128i*)qs);
return _mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(aux128, 4), aux128), MASK256_LO);
}
inline __m256i unaligned_copy8x32(const int8_t* qs) { return _mm256_loadu_si256((const __m256i*)qs); }
inline __m512i copy8x64(const int8_t* qs) { return _mm512_load_si512((const __m512i*)qs); }
inline __m256i lo4bit(const uint8_t* qs) {
return _mm256_and_si256(_mm256_loadu_si256((const __m256i*)qs), MASK256_LO);
}
inline __m256i hi4bit(const uint8_t* qs) {
return _mm256_srli_epi16(_mm256_and_si256(_mm256_loadu_si256((const __m256i*)qs), MASK256_4HI), 4);
}
inline __m128i make_q4K_scale_and_min(const uint8_t* scales8) {
__m128i re;
uint32_t* aux32 = (uint32_t*)&re;
const uint16_t* scales = (const uint16_t*)scales8;
const uint32_t a0 = scales[0] | (scales[1] << 16);
const uint32_t a1 = scales[2] | (scales[3] << 16);
const uint32_t a2 = scales[4] | (scales[5] << 16);
aux32[3] = ((a2 >> 4) & 0x0f0f0f0f) | ((a1 >> 2) & 0x30303030);
aux32[1] = ((a2 >> 0) & 0x0f0f0f0f) | ((a0 >> 2) & 0x30303030);
aux32[2] = a1 & 0x3f3f3f3f;
aux32[0] = a0 & 0x3f3f3f3f;
// aux32[1:0] is scale
// aux32[3:2] is min
return re;
}
inline __m256i merge_q8K_bsum(block_q8_K* b) {
return _mm256_madd_epi16(_mm256_loadu_si256((__m256i*)b->bsums), _mm256_set1_epi16(1));
}
inline __m512i _mm512_dpbusd_epi32_compat(__m512i src, __m512i a, __m512i b) {
#if defined(__AVX512VNNI__)
return _mm512_dpbusd_epi32(src, a, b);
#else
const __m512i mask_lo = _mm512_set1_epi16(0x00FF);
const __m512i ones16 = _mm512_set1_epi16(1);
__m512i a_even = _mm512_and_si512(a, mask_lo);
__m512i b_even = _mm512_srai_epi16(_mm512_slli_epi16(b, 8), 8);
__m512i a_odd = _mm512_srli_epi16(a, 8);
__m512i b_odd = _mm512_srai_epi16(b, 8);
__m512i prod_even = _mm512_mullo_epi16(a_even, b_even);
__m512i prod_odd = _mm512_mullo_epi16(a_odd, b_odd);
__m512i sum_even = _mm512_madd_epi16(prod_even, ones16);
__m512i sum_odd = _mm512_madd_epi16(prod_odd, ones16);
return _mm512_add_epi32(src, _mm512_add_epi32(sum_even, sum_odd));
#endif
}
inline __m512i _mm512_dpbssd_epi32(__m512i src, __m512i a, __m512i b) {
__m256i a_lo = _mm512_extracti64x4_epi64(a, 0);
__m256i a_hi = _mm512_extracti64x4_epi64(a, 1);
__m256i b_lo = _mm512_extracti64x4_epi64(b, 0);
__m256i b_hi = _mm512_extracti64x4_epi64(b, 1);
b_lo = _mm256_sign_epi8(b_lo, a_lo);
b_hi = _mm256_sign_epi8(b_hi, a_hi);
b = _mm512_inserti64x4(b, b_lo, 0);
b = _mm512_inserti64x4(b, b_hi, 1);
a = _mm512_abs_epi8(a);
return _mm512_dpbusd_epi32_compat(src, a, b);
}
} // namespace amx
#endif // AMX_QUANTIZATION_HPP