| 34 | } |
| 35 | |
| 36 | torch::Tensor quantize_q3_k(torch::Tensor& input) { |
| 37 | // Row-major quantization (equivalent to block size [1, 256]) |
| 38 | // of input tensor using Q3_K scheme. |
| 39 | TORCH_CHECK(input.ndimension() == 2, "input must be 2D"); |
| 40 | TORCH_CHECK(input.size(1) % QK_K == 0, "ncols must be divisible by QK_K"); |
| 41 | TORCH_CHECK(input.dtype() == torch::kFloat32, "input must be float32"); |
| 42 | if (!input.is_contiguous()) { |
| 43 | input = input.contiguous(); |
| 44 | } |
| 45 | const int64_t nrows = input.size(0); |
| 46 | const int64_t ncols = input.size(1); |
| 47 | const int64_t blocks_per_row = ncols / QK_K; |
| 48 | const int64_t block_size = sizeof(block_q3_K); |
| 49 | |
| 50 | auto options = torch::TensorOptions().dtype(torch::kUInt8).device(torch::kCPU); |
| 51 | auto output = torch::empty({nrows, blocks_per_row * block_size}, options); |
| 52 | |
| 53 | const float* input_ptr = input.data_ptr<float>(); |
| 54 | uint8_t* output_ptr = output.data_ptr<uint8_t>(); |
| 55 | |
| 56 | // Parallelize over rows |
| 57 | #pragma omp parallel for |
| 58 | for (int64_t row = 0; row < nrows; row++) { |
| 59 | const float* row_input = input_ptr + row * ncols; |
| 60 | block_q3_K* row_output = reinterpret_cast<block_q3_K*>(output_ptr + row * blocks_per_row * block_size); |
| 61 | |
| 62 | quantize_row_q3_K_ref(row_input, row_output, ncols); |
| 63 | } |
| 64 | |
| 65 | return output; |
| 66 | } |
| 67 | |
| 68 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { |
| 69 | m.def("quantize_q2_k", &quantize_q2_k, "Quantize a tensor to Q2_K format"); |
nothing calls this directly
no test coverage detected