voice_audio_multi/tests/unittests/test_neon_tensor_ops.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

78 lines
4.2 KiB
C++

#include "engine/framework/neon/execution.h"
#include <algorithm>
#include <cmath>
#include <iostream>
#include <stdexcept>
namespace n = engine::neon;
void expect(const std::vector<float> &actual, const std::vector<float> &expected, float tolerance = 0) {
if (actual.size() != expected.size()) throw std::runtime_error("NEON sequence shape mismatch");
for (size_t i = 0; i < actual.size(); ++i) {
if (!std::isfinite(actual[i]) || std::abs(actual[i] - expected[i]) > tolerance) {
throw std::runtime_error("NEON sequence scalar parity failed at " + std::to_string(i));
}
}
}
int main() try {
for (int threads : {1, 4}) {
n::ExecutionPlan plan;
const auto a = plan.input(), b = plan.input();
const auto joined = plan.add(n::Concat(1), {a, b});
const auto sliced = plan.add(n::Slice(1, 1, 3), {joined});
const auto transposed = plan.add(n::Transpose2d(), {sliced});
plan.set_output(plan.add(n::Reshape({6, 1}), {transposed}));
expect(plan.run({n::TensorView(std::vector<float>{1,2,3,4,5,6}, {2,3}),
n::TensorView(std::vector<float>{7,8,9,10}, {2,2})}, threads).values,
{2,5,3,6,7,9});
for (float scale : {0.25f, 0.07f, 1.0f / 256}) for (int zero_point : {-128, 0, 128}) {
const int minimum = zero_point == 128 ? 0 : -128, maximum = zero_point == 128 ? 255 : 127;
std::vector<float> input{-100, -32.125f, -1.375f, -0.375f, -0.125f, 0, 0.125f, 0.375f, 1.375f, 31.875f, 100};
input.push_back(-0.5f * scale);
input.push_back(0.5f * scale);
std::vector<float> expected;
for (float value : input) expected.push_back(std::clamp(std::round(value * (1.0f / scale)), float(minimum - zero_point), float(maximum - zero_point)) * scale);
n::ExecutionPlan quantization;
const auto in = quantization.input();
quantization.set_output(quantization.add(n::QuantizeDequantize(scale, zero_point, minimum, maximum), {in}));
expect(quantization.run({n::TensorView(input, {1,int(input.size())})}, threads).values, expected);
}
n::ExecutionPlan activation;
const auto in = activation.input();
const auto value = activation.add(n::Clamp(-2, 2), {in});
activation.set_output(activation.add(n::Activation(n::ActivationKind::Sigmoid), {value}));
expect(activation.run({n::TensorView(std::vector<float>{-8,-1,0,1,8}, {1,5})}, threads).values,
{1/(1+std::exp(2.0f)), 1/(1+std::exp(1.0f)), 0.5f, 1/(1+std::exp(-1.0f)), 1/(1+std::exp(-2.0f))});
for (int kernel : {1, 3, 5}) for (int stride : {1, 2}) for (int dilation : {1, 2}) {
const int channels = 3, frames = 15;
std::vector<float> input(channels * frames), weight(channels * kernel), bias{0.1f, -0.2f, 0.3f};
for (size_t i = 0; i < input.size(); ++i) input[i] = std::sin(float(i));
for (size_t i = 0; i < weight.size(); ++i) weight[i] = std::cos(float(i));
n::Conv1dConfig config{channels, channels, kernel, stride, dilation, 1, 2};
const int count = (frames + 3 - dilation * (kernel - 1) - 1) / stride + 1;
std::vector<float> expected(channels * count);
for (int channel = 0; channel < channels; ++channel) for (int frame = 0; frame < count; ++frame) {
float sum = bias[channel];
for (int tap = 0; tap < kernel; ++tap) {
const int at = frame * stride - 1 + tap * dilation;
if (at >= 0 && at < frames) sum += input[channel * frames + at] * weight[channel * kernel + tap];
}
expected[channel * count + frame] = sum;
}
n::ExecutionPlan convolution;
const auto signal = convolution.input();
convolution.set_output(convolution.add(n::DepthwiseConv1d(config, weight, bias), {signal}));
expect(convolution.run({n::TensorView(input, {channels, frames})}, threads).values, expected, 2e-6f);
}
}
std::cout << "NEON tensor operators passed\n";
return 0;
} catch (const std::exception &error) {
std::cerr << error.what() << '\n';
return 1;
}