voice_audio_multi/tests/unittests/test_tq2_1.cpp
Fabio c36510c21e
Some checks failed
Linux Build / Linux cpu (push) Has been cancelled
Linux Build / Linux cpu-clang (push) Has been cancelled
Linux Build / Linux vulkan (push) Has been cancelled
mac-build / macOS CPU (push) Has been cancelled
Nix Build / Nix (cpu) (push) Has been cancelled
Nix Build / Nix (vulkan) (push) Has been cancelled
windows-build / Windows CPU (push) Has been cancelled
Initial import: audio.cpp with Orange Pi documentation
2026-11-04 19:05:22 +01:00

85 lines
4 KiB
C++

#include "test_assert.h"
#include "ggml.h"
#include "ggml-cpu.h"
#include "ggml-quants.h"
#include <cmath>
#include <cstring>
#include <iostream>
#include <memory>
#include <vector>
namespace {
void test_matrix(int64_t columns, int64_t rows, int64_t batch) {
std::vector<float> weights(static_cast<size_t>(columns * rows));
for (size_t i = 0; i < weights.size(); ++i) {
const float scale = (i / 128) % 3 == 0 ? 0.0f : ((i / 128) % 2 ? 0.125f : 0.5f);
weights[i] = (static_cast<int>(i % 3) - 1) * scale;
}
std::vector<block_tq2_1> packed(weights.size() / 256);
quantize_row_tq2_1_ref(weights.data(), packed.data(), static_cast<int64_t>(weights.size()));
engine::test::require(ggml_validate_row_data(GGML_TYPE_TQ2_1, packed.data(), packed.size() * sizeof(block_tq2_1)),
"valid ternary blocks rejected");
std::vector<float> restored(weights.size());
dequantize_row_tq2_1(packed.data(), restored.data(), static_cast<int64_t>(weights.size()));
engine::test::require(restored == weights, "independent 128-weight scales were not preserved exactly");
auto invalid = packed;
invalid.front().qs[0] |= 3;
engine::test::require(!ggml_validate_row_data(GGML_TYPE_TQ2_1, invalid.data(), invalid.size() * sizeof(block_tq2_1)),
"reserved ternary code accepted");
invalid = packed;
invalid.front().d[1] = ggml_fp32_to_fp16(INFINITY);
engine::test::require(!ggml_validate_row_data(GGML_TYPE_TQ2_1, invalid.data(), invalid.size() * sizeof(block_tq2_1)),
"nonfinite second scale accepted");
std::vector<float> input(static_cast<size_t>(columns * batch));
for (size_t i = 0; i < input.size(); ++i) input[i] = (static_cast<int>((i * 17) % 129) - 64) * 0.125f;
std::vector<block_q8_K> activation(input.size() / 256);
quantize_row_q8_K_ref(input.data(), activation.data(), static_cast<int64_t>(input.size()));
std::vector<float> quantized_input(input.size());
dequantize_row_q8_K(activation.data(), quantized_input.data(), static_cast<int64_t>(input.size()));
std::unique_ptr<ggml_context, decltype(&ggml_free)> context(
ggml_init({16 * 1024 * 1024, nullptr, false}), ggml_free);
engine::test::require(context != nullptr, "context allocation failed");
auto * w = ggml_new_tensor_2d(context.get(), GGML_TYPE_TQ2_1, columns, rows);
auto * x = ggml_new_tensor_2d(context.get(), GGML_TYPE_F32, columns, batch);
std::memcpy(w->data, packed.data(), packed.size() * sizeof(block_tq2_1));
std::memcpy(x->data, input.data(), input.size() * sizeof(float));
auto * output = ggml_mul_mat(context.get(), w, x);
auto * graph = ggml_new_graph(context.get());
ggml_build_forward_expand(graph, output);
engine::test::require(ggml_graph_compute_with_ctx(context.get(), graph, 2) == GGML_STATUS_SUCCESS,
"ternary CPU graph failed");
const auto * actual = static_cast<const float *>(output->data);
for (int64_t b = 0; b < batch; ++b) {
for (int64_t r = 0; r < rows; ++r) {
float expected = 0.0f;
for (int64_t c = 0; c < columns; ++c) {
expected += weights[r * columns + c] * quantized_input[b * columns + c];
}
engine::test::require_close(actual[b * rows + r], expected,
1e-4f + 1e-5f * std::abs(expected), "ternary matrix multiplication");
}
}
}
} // namespace
int main() {
try {
engine::test::require(GGML_TYPE_I2_S == 43 && GGML_TYPE_TQ2_1 == 44,
"existing GGUF type IDs changed");
engine::test::require(ggml_row_size(GGML_TYPE_TQ2_1, 256) == 68, "incorrect ternary block size");
for (const int64_t columns : {256, 512, 1536}) {
for (const int64_t batch : {1, 3, 32}) test_matrix(columns, 7, batch);
}
std::cout << "tq2_1_test passed\n";
return 0;
} catch (const std::exception & error) {
std::cerr << error.what() << '\n';
return 1;
}
}