chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#include <arm_sve.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../../reduce.hpp"
|
||||
#include "../../rms-norm.hpp"
|
||||
#include "../../rope.hpp"
|
||||
#include "../../softmax.hpp"
|
||||
#include "../la/arm_kml.hpp"
|
||||
#include "llama.cpp/ggml-common.h"
|
||||
#include "llama.cpp/ggml.h"
|
||||
|
||||
void bf16_to_fp16(const ggml_bf16_t* src, ggml_fp16_t* dst, size_t n) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
float x = ggml_bf16_to_fp32(src[i]);
|
||||
dst[i] = ggml_fp32_to_fp16(x);
|
||||
}
|
||||
}
|
||||
|
||||
void debug_rope() {
|
||||
float16_t* fp16 = new float16_t[1024 * 64];
|
||||
|
||||
for (size_t i = 0; i < 1024 * 64; i++) {
|
||||
fp16[i] = static_cast<double>(std::rand()) / RAND_MAX;
|
||||
}
|
||||
std::ofstream("before_rope", std::ios::binary).write((char*)fp16, 1024 * 64 * sizeof(float16_t));
|
||||
|
||||
DeepseekV3YarnRotaryEmbedding rope(64, 163840, 10000, 40, 4096, 32, 1, 1, 1);
|
||||
|
||||
rope.init(1024);
|
||||
|
||||
Rope<DeepseekV3YarnRotaryEmbedding, float16_t> rope_applier;
|
||||
rope_applier.apply_multiple(rope, fp16, 64, 64, 0, 1024);
|
||||
|
||||
std::ofstream("cos", std::ios::binary).write((char*)rope.cos(0), 1024 * 32 * sizeof(float));
|
||||
std::ofstream("sin", std::ios::binary).write((char*)rope.sin(0), 1024 * 32 * sizeof(float));
|
||||
|
||||
std::ofstream("after_rope", std::ios::binary).write((char*)fp16, 1024 * 64 * sizeof(float16_t));
|
||||
}
|
||||
|
||||
void debug_softmax() {
|
||||
float16_t* fp16 = new float16_t[64 * 1024];
|
||||
|
||||
for (size_t i = 0; i < 1024 * 64; i++) {
|
||||
fp16[i] = static_cast<double>(std::rand()) / RAND_MAX * 10;
|
||||
if (i % 12 == 0) {
|
||||
fp16[i] -= std::numeric_limits<float16_t>::infinity();
|
||||
}
|
||||
}
|
||||
std::ofstream("before_softmax", std::ios::binary).write((char*)fp16, 1024 * 64 * sizeof(float16_t));
|
||||
|
||||
Softmax<float16_t>::apply_multiple(64, fp16, 1024, 1024);
|
||||
std::ofstream("after_softmax", std::ios::binary).write((char*)fp16, 1024 * 64 * sizeof(float16_t));
|
||||
}
|
||||
|
||||
void debug_inf() {
|
||||
float16_t x, y;
|
||||
// x = std::numeric_limits<float16_t>::infinity(); // 0.00
|
||||
// y = -std::numeric_limits<float16_t>::infinity(); // -0.00
|
||||
// x = 1e10;
|
||||
x = std::numeric_limits<float>::infinity(); // inf
|
||||
y = -std::numeric_limits<float>::infinity(); // -inf
|
||||
printf("x = %f, y = %f\n", x, y);
|
||||
}
|
||||
|
||||
void debug_reduce() {
|
||||
std::vector<float16_t*> fp16s(128);
|
||||
for (size_t i = 0; i < 128; i++) {
|
||||
fp16s[i] = new float16_t[1024];
|
||||
for (size_t j = 0; j < 1024; j++) {
|
||||
fp16s[i][j] = i;
|
||||
}
|
||||
}
|
||||
|
||||
reduce_sum(fp16s.data(), 128, 0, 10);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
printf("%f ", fp16s[0][i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
debug_reduce();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef KML_DEBUG_HPP
|
||||
#define KML_DEBUG_HPP
|
||||
|
||||
#include <arm_sve.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
inline std::string get_env_or_default(const char* var_name, const std::string& default_value) {
|
||||
const char* value = std::getenv(var_name);
|
||||
return (value != nullptr) ? std::string(value) : default_value;
|
||||
}
|
||||
|
||||
inline void dump_bin(std::string file_name, float16_t* data, size_t count) {
|
||||
file_name = get_env_or_default("KML_DEBUG_PATH", "debug") + "/" + file_name + ".f16";
|
||||
std::ofstream f(file_name, std::ios::binary);
|
||||
f.write(reinterpret_cast<const char*>(data), count * sizeof(*data));
|
||||
f.close();
|
||||
}
|
||||
inline void dump_bin(std::string file_name, float* data, size_t count) {
|
||||
file_name = get_env_or_default("KML_DEBUG_PATH", "debug") + "/" + file_name + ".f32";
|
||||
std::ofstream f(file_name, std::ios::binary);
|
||||
f.write(reinterpret_cast<const char*>(data), count * sizeof(*data));
|
||||
f.close();
|
||||
}
|
||||
inline void dump_bin(std::string file_name, int64_t* data, size_t count) {
|
||||
file_name = get_env_or_default("KML_DEBUG_PATH", "debug") + "/" + file_name + ".int64";
|
||||
std::ofstream f(file_name, std::ios::binary);
|
||||
f.write(reinterpret_cast<const char*>(data), count * sizeof(*data));
|
||||
f.close();
|
||||
}
|
||||
|
||||
inline void dump_bin(std::string file_name, int8_t* data, size_t count) {
|
||||
file_name = get_env_or_default("KML_DEBUG_PATH", "debug") + "/" + file_name + ".int8";
|
||||
std::ofstream f(file_name, std::ios::binary);
|
||||
f.write(reinterpret_cast<const char*>(data), count * sizeof(*data));
|
||||
f.close();
|
||||
}
|
||||
|
||||
inline void dump_bin(std::string file_name, int32_t* data, size_t count) {
|
||||
file_name = get_env_or_default("KML_DEBUG_PATH", "debug") + "/" + file_name + ".int32";
|
||||
std::ofstream f(file_name, std::ios::binary);
|
||||
f.write(reinterpret_cast<const char*>(data), count * sizeof(*data));
|
||||
f.close();
|
||||
}
|
||||
|
||||
inline void load_bin(std::string file_name, float* data, size_t count) {
|
||||
file_name = get_env_or_default("KML_DEBUG_PATH", "debug") + "/" + file_name + ".f32";
|
||||
std::ifstream f(file_name, std::ios::binary);
|
||||
if (!f.is_open()) {
|
||||
throw std::runtime_error("Failed to open file: " + file_name);
|
||||
}
|
||||
f.read(reinterpret_cast<char*>(data), count * sizeof(*data));
|
||||
f.close();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../la/arm_kml.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "kblas.h"
|
||||
const int M = 1, K = 7168, N = 8;
|
||||
|
||||
int main() {
|
||||
// 随机生成a, b, c矩阵
|
||||
arm_kml::GemmKernelInt4::BufferA buffer_a(M, K);
|
||||
arm_kml::GemmKernelInt4::BufferB buffer_b(N, K, true);
|
||||
arm_kml::GemmKernelInt4::BufferC buffer_c(M, N);
|
||||
|
||||
arm_kml::GemmKernelInt8::BufferA buffer_a_check(M, K);
|
||||
arm_kml::GemmKernelInt8::BufferB buffer_b_check(N, K, true);
|
||||
arm_kml::GemmKernelInt8::BufferC buffer_c_check(M, N);
|
||||
|
||||
float* a = (float*)aligned_alloc(64, sizeof(float) * M * K);
|
||||
float* b = (float*)aligned_alloc(64, sizeof(float) * K * N);
|
||||
float* c = (float*)aligned_alloc(64, sizeof(float) * M * N);
|
||||
float* c_check = (float*)aligned_alloc(64, sizeof(float) * M * N);
|
||||
int8_t* buffer_a_data = (int8_t*)aligned_alloc(64, buffer_a.required_size());
|
||||
int4_2_t* buffer_b_data = (int4_2_t*)aligned_alloc(64, buffer_b.required_size());
|
||||
int32_t* c_data = (int32_t*)aligned_alloc(64, buffer_c.required_size());
|
||||
int8_t* buffer_a_data_check = (int8_t*)aligned_alloc(64, buffer_a_check.required_size());
|
||||
int8_t* buffer_b_data_check = (int8_t*)aligned_alloc(64, buffer_b_check.required_size());
|
||||
int32_t* c_data_check = (int32_t*)aligned_alloc(64, buffer_c_check.required_size());
|
||||
// 初始化元素内容
|
||||
load_bin("input.bin", a, M * K);
|
||||
load_bin("local_q_a_proj_quant.bin", b, N * K);
|
||||
|
||||
// for (int i = 0; i < M * K; i++) {
|
||||
// // 随机浮点数
|
||||
// // a[i] = (static_cast<float>(rand()) / (float)RAND_MAX) / 25 - 0.02;
|
||||
// a[i] = -(static_cast<float>(rand()) / (float)RAND_MAX) / 25;
|
||||
// // a[i] = i % 10;
|
||||
// // a[i] = 1;
|
||||
// }
|
||||
// for (int i = 0; i < K * N; i++) {
|
||||
// // 随机浮点数
|
||||
// // b[i] = (static_cast<float>(rand()) / (float)RAND_MAX) / 25 - 0.02;
|
||||
// b[i] = -(static_cast<float>(rand()) / (float)RAND_MAX) / 25;
|
||||
// // b[i] = i % 10;
|
||||
// // b[i] = 1;
|
||||
// }
|
||||
// // // // 设置离群值
|
||||
// for (int i = 0; i < N; i++) {
|
||||
// b[i * K] = 0.06f; // 设置第一列为离群值
|
||||
// }
|
||||
// // 打印一下输入矩阵和权重矩阵
|
||||
// printf("Input matrix a:\n");
|
||||
// for (int i = 0; i < M; i++) {
|
||||
// for (int j = 0; j < K; j++) {
|
||||
// printf("%f ", a[i * K + j]);
|
||||
// }
|
||||
// printf("\n");
|
||||
// }
|
||||
// printf("Weight matrix b:\n");
|
||||
// for (int i = 0; i < N; i++) {
|
||||
// for (int j = 0; j < K; j++) {
|
||||
// printf("%f ", b[i * K + j]);
|
||||
// }
|
||||
// printf("\n");
|
||||
// }
|
||||
buffer_a.set_data(buffer_a_data);
|
||||
buffer_b.set_data(buffer_b_data);
|
||||
buffer_c.set_data(c_data);
|
||||
buffer_a_check.set_data(buffer_a_data_check);
|
||||
buffer_b_check.set_data(buffer_b_data_check);
|
||||
buffer_c_check.set_data(c_data_check);
|
||||
// 调用 from mat 进行量化
|
||||
buffer_a.from_mat(M, a, 0, M);
|
||||
for (int i = 0; i <= arm_kml::GemmKernelInt4::recommended_nth(N); i++) {
|
||||
buffer_b.from_mat(b, i, arm_kml::GemmKernelInt4::recommended_nth(N));
|
||||
}
|
||||
buffer_a_check.from_mat(M, a, 0, M);
|
||||
for (int i = 0; i <= arm_kml::GemmKernelInt8::recommended_nth(N); i++) {
|
||||
buffer_b_check.from_mat(b, i, arm_kml::GemmKernelInt8::recommended_nth(N));
|
||||
}
|
||||
// 进行乘法
|
||||
arm_kml::MatRef<int8_t> a_ref(buffer_a.a, M, K, K, CblasRowMajor);
|
||||
arm_kml::MatRef<int4_2_t> b_ref(buffer_b.b, K, N, K, CblasColMajor, CblasNoTrans, buffer_b.if_pack);
|
||||
arm_kml::MatRef<int32_t> c_ref(buffer_c.c, M, N, N, CblasRowMajor);
|
||||
b_ref = b_ref.offset_col(0, N);
|
||||
|
||||
arm_kml::MatRef<int8_t> a_ref_check(buffer_a_check.a, M, K, K, CblasRowMajor);
|
||||
arm_kml::MatRef<int8_t> b_ref_check(buffer_b_check.b, K, N, K, CblasColMajor, CblasNoTrans, buffer_b_check.if_pack);
|
||||
arm_kml::MatRef<int32_t> c_ref_check(buffer_c_check.c, M, N, N, CblasRowMajor);
|
||||
|
||||
arm_kml::decode_mul_mat_clearc(a_ref, b_ref, c_ref);
|
||||
arm_kml::decode_mul_mat_clearc(a_ref_check, b_ref_check, c_ref_check);
|
||||
// 反量化,apply scale
|
||||
arm_kml::GemmKernelInt4::apply_scale(c, N, &buffer_a, &buffer_b, &buffer_c, 0, M, 0, N, true);
|
||||
arm_kml::GemmKernelInt8::apply_scale(c_check, N, &buffer_a_check, &buffer_b_check, &buffer_c_check, 0, M, 0, N, true);
|
||||
// 打印结果,比较 c 和 c_check
|
||||
const float threashold = 0.05;
|
||||
for (int i = 0; i < M * N; i++) {
|
||||
float diff_relative = (c[i] - c_check[i]) / (c_check[i] + 1e-6);
|
||||
|
||||
if (diff_relative > threashold || diff_relative < -threashold) {
|
||||
printf("diff_relative: %f\n", diff_relative);
|
||||
printf("Mismatch at index %d: c = %f, c_check = %f\n", i, c[i], c_check[i]);
|
||||
} else {
|
||||
printf("Match at index %d: c = %f, c_check = %f\n", i, c[i], c_check[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "arm_kml.hpp"
|
||||
|
||||
int main() {
|
||||
const size_t M = 128, N = 64;
|
||||
float16_t* a = new float16_t[M * N];
|
||||
float16_t* b = new float16_t[M * N];
|
||||
float16_t* c = new float16_t[M * M];
|
||||
float16_t* c_check = new float16_t[M * M];
|
||||
for (size_t i = 0; i < M * N; i++) {
|
||||
a[i] = static_cast<double>(std::rand()) / RAND_MAX / 10.0;
|
||||
b[i] = static_cast<double>(std::rand()) / RAND_MAX / 10.0;
|
||||
}
|
||||
|
||||
arm_kml::MatRef<float16_t> aref(a, M, N, M, CblasColMajor);
|
||||
arm_kml::MatRef<float16_t> bref(b, N, M, M, CblasColMajor);
|
||||
arm_kml::MatRef<float16_t> cref(c, M, M, M, CblasColMajor);
|
||||
{
|
||||
memset(c, 0, M * M * sizeof(float16_t));
|
||||
memset(c_check, 0, M * M * sizeof(float16_t));
|
||||
arm_kml::mul_mat(aref, bref, cref);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// #pragma once
|
||||
#ifdef TEST_UTIL
|
||||
#include <arm_neon.h>
|
||||
#include <arm_sve.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline void sve_32xbf16_to_32xfp32(const bfloat16_t* src, float* dst0, float* dst1) {
|
||||
#ifdef __ARM_FEATURE_SVE
|
||||
// 全真谓词,对应每个 16‑bit 元素
|
||||
#else
|
||||
// fallback: scalar or NEON
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void neon_32xbf16_to_32xfp32(const uint16_t* src, float* dst0, float* dst1) {
|
||||
// src 指向 32 个连续的 BF16(uint16_t)
|
||||
// dst0、dst1 各指向 16 个 float 的缓冲
|
||||
|
||||
for (int block = 0; block < 4; ++block) {
|
||||
// 每次处理 8 个 BF16 → 8 个 FP32(拆为两次 4→4 存储)
|
||||
uint16x8_t v_bf16 = vld1q_u16(src + block * 8); // load 8×BF16 :contentReference[oaicite:6]{index=6}
|
||||
|
||||
// 拆低半、高半各 4 个到 u32
|
||||
uint32x4_t lo_u32 = vmovl_u16(vget_low_u16(v_bf16)); // lower 4 → u32 :contentReference[oaicite:7]{index=7}
|
||||
uint32x4_t hi_u32 = vmovl_u16(vget_high_u16(v_bf16)); // upper 4 → u32 :contentReference[oaicite:8]{index=8}
|
||||
|
||||
// 左移 16 位,相当于将 BF16 的 16 位 mantissa+exp 放到 FP32 高位
|
||||
lo_u32 = vshlq_n_u32(lo_u32, 16); // shift left 16 :contentReference[oaicite:9]{index=9}
|
||||
hi_u32 = vshlq_n_u32(hi_u32, 16); // shift left 16 :contentReference[oaicite:10]{index=10}
|
||||
|
||||
// 重新解释为 float32x4_t
|
||||
float32x4_t lo_f32 = vreinterpretq_f32_u32(lo_u32); // bits → FP32 :contentReference[oaicite:11]{index=11}
|
||||
float32x4_t hi_f32 = vreinterpretq_f32_u32(hi_u32); // bits → FP32 :contentReference[oaicite:12]{index=12}
|
||||
|
||||
// 存储到 dst0 或 dst1,每次存 8 个
|
||||
if (block < 2) {
|
||||
vst1q_f32(dst0 + block * 4, lo_f32); // store 4 floats :contentReference[oaicite:13]{index=13}
|
||||
vst1q_f32(dst0 + block * 4 + 4, hi_f32); // store next 4 floats :contentReference[oaicite:14]{index=14}
|
||||
} else {
|
||||
int b = block - 2;
|
||||
vst1q_f32(dst1 + b * 4, lo_f32); // store 4 floats :contentReference[oaicite:15]{index=15}
|
||||
vst1q_f32(dst1 + b * 4 + 4, hi_f32); // store next 4 floats :contentReference[oaicite:16]{index=16}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// 测试代码
|
||||
uint16_t bf16_data[32] = {0}; // 假设这里填充了一些 BF16 数据
|
||||
float f32_data0[16] = {0};
|
||||
float f32_data1[16] = {0};
|
||||
|
||||
neon_32xbf16_to_32xfp32(bf16_data, f32_data0, f32_data1);
|
||||
|
||||
// 打印结果
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
printf("f32_data0[%d]: %f\n", i, f32_data0[i]);
|
||||
printf("f32_data1[%d]: %f\n", i, f32_data1[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user