Copyright (c) 2025-2025 Huawei Technologies Co., Ltd.
sysHAX-adapter is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
PURPOSE.
See the Mulan PSL v2 for more details.
Created: 2026-1-31
Desc: CPU inference model weight base class
*/
#include "model_weight_base.h"
#include <iostream>
#include <utility>
#include <sched.h>
#include <numa.h>
#include <cstdlib>
#include <set>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <regex>
#include <pthread.h>
#include "utils.h"
#include "tp_method.h"
#include "cpu_utils.h"
namespace cpu_inference {
const std::unordered_map<std::string, std::unordered_map<std::string, StoreType> > model_weight_store = {
{"qwen2", qwen2_split_method},
{"qwen3_moe", qwen3_moe_name_store},
};
ModelWeightBase::ModelWeightBase(const std::string& model_type, const std::string& quantization_type,
const std::map<int, std::vector<int>>& cpu_affinity){
this->set_model_type(model_type);
this->set_quantization_type(quantization_type);
this->set_cpu_affinity(cpu_affinity);
this->name_store_map = model_weight_store.at(model_type);
}
bool ModelWeightBase::add_weight(const std::string& weight_name, std::string dtype,
std::vector<int> shape, void* data)
{
std::regex pattern(R"((\d+)_(.+))");
std::smatch match;
std::string weight_type = "";
if (std::regex_match(weight_name, match, pattern)) {
weight_type = match[2].str();
}
else {
std::cerr << "weight type is't valid.\n";
}
StoreType weight_store_type = this->name_store_map[weight_type];
std::vector<int> cur_numa_list;
std::vector<int> cur_shape;
if (weight_store_type == StoreType::FULL_IN_FIRST_NUMA) {
cur_numa_list.push_back(numa_list[0]);
cur_shape = shape;
} else if (weight_store_type == StoreType::FULL_IN_ALL_NUMA) {
cur_numa_list = numa_list;
cur_shape = shape;
}
else if(weight_store_type == StoreType::ROW_SPLIT){
cur_numa_list = numa_list;
cur_shape = split_weight_row(shape);
}
return this->add_weight(weight_name, cur_numa_list, cur_shape, dtype, data);
}
bool ModelWeightBase::add_weight(const std::string& weight_name,
const std::vector<int>& cur_numa_list,
const std::vector<int>& cur_shape,
std::string dtype,
void* data)
{
auto [weight_it, _] = this->weight_map.insert_or_assign(weight_name, Weight(weight_name,
cur_numa_list, cur_shape, dtype, this->quantization_type));
Weight& weight = weight_it->second;
const std::vector<int>& orignal_shape = weight.get_orignal_shape();
size_t first_dim = orignal_shape[0];
size_t elem_cnt = weight.compute_num_elements(orignal_shape) / first_dim;
void* src_ptr = data;
#pragma omp parallel
{
WorkDivider work;
init_work_divider(&work, cur_numa_list.size());
SingleNumaWorkRange pstSingleRange;
divide_work_single_numa(&work, first_dim, &pstSingleRange);
if(pstSingleRange.work_per_thread > 0){
if (this->quantization_type == "q8align"){
int block_cnt_in_row = orignal_shape[2] / QK8_ALIGN;
void** ptr = (void**)weight.at(work.my_numa);
void* cur_src_ptr = (void*)((char*)src_ptr + pstSingleRange.begin_thread * elem_cnt * sizeof(float16_t));
void* dst_ptr_val = (void*)((char*)ptr[0] + pstSingleRange.begin_thread * elem_cnt * sizeof(int8_t));
void* dst_ptr_d = (void*)((char*)ptr[1] + pstSingleRange.begin_thread * elem_cnt / QK8_ALIGN * 2 * sizeof(float));
Q8Align::q8align_quantize((float16_t*)cur_src_ptr, (int8_t*)dst_ptr_val, (float*)dst_ptr_d, 0,
pstSingleRange.work_per_thread * elem_cnt / QK8_ALIGN, block_cnt_in_row, false);
}else{
void* cur_src_ptr = (void*)((char*)src_ptr + pstSingleRange.begin_thread * elem_cnt * sizeof(float16_t));
void* dst_ptr = weight.at(work.my_numa, pstSingleRange.begin_thread);
quantize_weight(cur_src_ptr, dst_ptr, pstSingleRange.work_per_thread * elem_cnt);
}
}
}
return true;
}
const Weight& ModelWeightBase::get_weight(const std::string& weight_name) const
{
return this->weight_map.at(weight_name);
}
void ModelWeightBase::set_model_type(std::string model_type)
{
this->model_type = model_type;
}
void ModelWeightBase::set_quantization_type(std::string quantization_type)
{
this->quantization_type = quantization_type;
}
void ModelWeightBase::set_cpu_affinity(std::map<int, std::vector<int>> cpu_affinity)
{
this->cpu_affinity = cpu_affinity;
for(auto it = cpu_affinity.begin(); it != cpu_affinity.end(); ++it) {
this->numa_list.push_back(it->first);
}
}
void ModelWeightBase::quantize_weight(const void* const src_data, void* dst_data, size_t element_cnt)
{
if(this->quantization_type == "fp32") {
QuantizationBase<float16_t>::dequantize(
static_cast<const float16_t*>(src_data), static_cast<float32_t*>(dst_data), element_cnt, "fp32");
} else if(this->quantization_type == "fp16") {
memcpy(dst_data, src_data, element_cnt * sizeof(float16_t));
} else if(this->quantization_type == "q8_0" || this->quantization_type == "q4_0") {
if (this->quantization_type == "q8_0") {
this->template quantize_weight_impl<block_q8_0>(src_data, dst_data, element_cnt, QK8_0);
} else if (this->quantization_type == "q4_0") {
this->template quantize_weight_impl<block_q4_0>(src_data, dst_data, element_cnt, QK4_0);
}
} else {
std::cerr << "Unsupported quantization type: " << this->quantization_type << std::endl;
}
}
std::vector<int> ModelWeightBase::split_weight_row(const std::vector<int>& shape) const
{
std::vector<int> shape_res = shape;
const size_t numa_cnt = this->numa_list.size();
int split_size = (shape[0] + numa_cnt - 1) / numa_cnt;
shape_res[0] = split_size;
return shape_res;
}
};