From 7398af7253a0b6967b2496df8bcd3cd304a25120 Mon Sep 17 00:00:00 2001 From: Fatih Cetinkaya <965295+devfacet@users.noreply.github.com> Date: Sun, 14 Jul 2024 21:16:32 -0400 Subject: [PATCH] Improve tests (#29) * Improve tests * Add _POSIX_C_SOURCE back --- scripts/test/gen/nn_act_func.py | 34 +++++++++++ scripts/test/gen/nn_act_func_identity.py | 22 +++++++ scripts/test/gen/nn_act_func_relu.py | 27 +++++++++ scripts/test/gen/nn_act_func_scalar_batch.py | 33 +++++++++++ scripts/test/gen/nn_act_func_sigmoid.py | 27 +++++++++ scripts/test/gen/nn_act_func_softmax.py | 34 +++++++++++ scripts/test/gen/nn_act_func_tensor_batch.py | 34 +++++++++++ .../test/{layer_gen_tc.py => gen/nn_layer.py} | 2 +- .../nn_layer_multi.py} | 2 +- src/nn_activation.c | 4 -- src/nn_layer.c | 3 + tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c | 8 +-- tests/arch/arm/neon/dot_prod_perf/main.c | 8 +-- tests/arch/generic/activation/activation.h | 8 +++ tests/arch/generic/activation/include.txt | 15 +++++ tests/arch/generic/activation/main.c | 18 ++++++ tests/arch/generic/activation/nn_act_func.c | 56 ++++++++++++++++++ .../generic/activation/nn_act_func_identity.c | 47 +++++++++++++++ .../generic/activation/nn_act_func_init.c | 44 ++++++++++++++ .../generic/activation/nn_act_func_relu.c | 59 +++++++++++++++++++ .../activation/nn_act_func_scalar_batch.c | 56 ++++++++++++++++++ .../generic/activation/nn_act_func_sigmoid.c | 59 +++++++++++++++++++ .../generic/activation/nn_act_func_softmax.c | 56 ++++++++++++++++++ .../activation/nn_act_func_tensor_batch.c | 56 ++++++++++++++++++ .../generic/activation_perf/activation_perf.h | 8 +++ .../arch/generic/activation_perf/include.txt | 15 +++++ tests/arch/generic/activation_perf/main.c | 22 +++++++ .../generic/activation_perf/nn_act_func.c | 24 ++++++++ .../activation_perf/nn_act_func_identity.c | 24 ++++++++ .../activation_perf/nn_act_func_init.c | 29 +++++++++ .../activation_perf/nn_act_func_relu.c | 24 ++++++++ .../nn_act_func_scalar_batch.c | 28 +++++++++ .../activation_perf/nn_act_func_sigmoid.c | 24 ++++++++ .../activation_perf/nn_act_func_softmax.c | 28 +++++++++ .../nn_act_func_tensor_batch.c | 28 +++++++++ tests/arch/generic/dot_prod_perf/main.c | 8 +-- tests/arch/generic/layer/main.c | 2 +- tests/arch/generic/layer_multi/main.c | 2 +- 38 files changed, 958 insertions(+), 20 deletions(-) create mode 100644 scripts/test/gen/nn_act_func.py create mode 100644 scripts/test/gen/nn_act_func_identity.py create mode 100644 scripts/test/gen/nn_act_func_relu.py create mode 100644 scripts/test/gen/nn_act_func_scalar_batch.py create mode 100644 scripts/test/gen/nn_act_func_sigmoid.py create mode 100644 scripts/test/gen/nn_act_func_softmax.py create mode 100644 scripts/test/gen/nn_act_func_tensor_batch.py rename scripts/test/{layer_gen_tc.py => gen/nn_layer.py} (98%) rename scripts/test/{layer_multi_gen_tc.py => gen/nn_layer_multi.py} (99%) create mode 100644 tests/arch/generic/activation/activation.h create mode 100644 tests/arch/generic/activation/include.txt create mode 100644 tests/arch/generic/activation/main.c create mode 100644 tests/arch/generic/activation/nn_act_func.c create mode 100644 tests/arch/generic/activation/nn_act_func_identity.c create mode 100644 tests/arch/generic/activation/nn_act_func_init.c create mode 100644 tests/arch/generic/activation/nn_act_func_relu.c create mode 100644 tests/arch/generic/activation/nn_act_func_scalar_batch.c create mode 100644 tests/arch/generic/activation/nn_act_func_sigmoid.c create mode 100644 tests/arch/generic/activation/nn_act_func_softmax.c create mode 100644 tests/arch/generic/activation/nn_act_func_tensor_batch.c create mode 100644 tests/arch/generic/activation_perf/activation_perf.h create mode 100644 tests/arch/generic/activation_perf/include.txt create mode 100644 tests/arch/generic/activation_perf/main.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_identity.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_init.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_relu.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_scalar_batch.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_sigmoid.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_softmax.c create mode 100644 tests/arch/generic/activation_perf/nn_act_func_tensor_batch.c diff --git a/scripts/test/gen/nn_act_func.py b/scripts/test/gen/nn_act_func.py new file mode 100644 index 0000000..21e318f --- /dev/null +++ b/scripts/test/gen/nn_act_func.py @@ -0,0 +1,34 @@ +# This script generates test cases for nn_act_func_softmax function. + +import numpy as np + +# Returns the softmax activation function result. +def nn_act_func_softmax(x): + exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True)) + return exp_x / np.sum(exp_x, axis=-1, keepdims=True) + +# Generates a test case. +def generate_test_case(input): + input_c = ", ".join(map(str, input.flatten())) + expected_value = nn_act_func_softmax(input) + expected_value_c = ", ".join(map(str, expected_value.flatten())) + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){{1, {len(input)}}}, false, (const NNTensorUnit[]){{{input_c}}}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){{1, {len(input)}}}, false, (const NNTensorUnit[]){{{expected_value_c}}}, NULL), + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [ + np.array([0.8, 0.2, 0.1]), + np.array([-0.6, 0.0, 0.6]), + np.array([0.3, -0.3, 0.0]) +] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/gen/nn_act_func_identity.py b/scripts/test/gen/nn_act_func_identity.py new file mode 100644 index 0000000..f2b4105 --- /dev/null +++ b/scripts/test/gen/nn_act_func_identity.py @@ -0,0 +1,22 @@ +# This script generates test cases for nn_act_func_identity function. + +import numpy as np + +# Generates a test case. +def generate_test_case(input): + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_identity), + .input = {input}, + .expected_value = {input}, + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [-1.0, 0.0, 1.0] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/gen/nn_act_func_relu.py b/scripts/test/gen/nn_act_func_relu.py new file mode 100644 index 0000000..90ee975 --- /dev/null +++ b/scripts/test/gen/nn_act_func_relu.py @@ -0,0 +1,27 @@ +# This script generates test cases for nn_act_func_relu function. + +import numpy as np + +# Returns the ReLU activation function result. +def nn_act_func_relu(x): + return np.maximum(0, x) + +# Generates a test case. +def generate_test_case(input): + expected_value = nn_act_func_relu(input) + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_relu), + .input = {input}, + .expected_value = {expected_value}, + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [-2.0, -1.0, 0.0, 1.0, 2.0] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/gen/nn_act_func_scalar_batch.py b/scripts/test/gen/nn_act_func_scalar_batch.py new file mode 100644 index 0000000..852d2de --- /dev/null +++ b/scripts/test/gen/nn_act_func_scalar_batch.py @@ -0,0 +1,33 @@ +# This script generates test cases for nn_act_func_softmax function. + +import numpy as np + +# Returns the ReLU activation function result. +def nn_act_func_relu(x): + return np.maximum(0, x) + +# Generates a test case. +def generate_test_case(input): + input_c = ", ".join(map(str, input.flatten())) + expected_value = nn_act_func_relu(input) + expected_value_c = ", ".join(map(str, expected_value.flatten())) + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_relu), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){{1, {len(input)}}}, false, (const NNTensorUnit[]){{{input_c}}}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){{1, {len(input)}}}, false, (const NNTensorUnit[]){{{expected_value_c}}}, NULL), + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [ + np.array([0.8, 0.2, -0.1, 0.0]), + np.array([-0.6, 0.0, 0.6, -1.0]), + np.array([0.3, -0.3, 1.0, 0.0]) +] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/gen/nn_act_func_sigmoid.py b/scripts/test/gen/nn_act_func_sigmoid.py new file mode 100644 index 0000000..9ae38f9 --- /dev/null +++ b/scripts/test/gen/nn_act_func_sigmoid.py @@ -0,0 +1,27 @@ +# This script generates test cases for nn_act_func_sigmoid function. + +import numpy as np + +# Returns the sigmoid activation function result. +def nn_act_func_sigmoid(x): + return 1 / (1 + np.exp(-x)) + +# Generates test cases. +def generate_test_case(input): + expected_value = nn_act_func_sigmoid(input) + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_sigmoid), + .input = {input}, + .expected_value = {expected_value}, + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [-2.0, -1.0, 0.0, 1.0, 2.0] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/gen/nn_act_func_softmax.py b/scripts/test/gen/nn_act_func_softmax.py new file mode 100644 index 0000000..39a44ce --- /dev/null +++ b/scripts/test/gen/nn_act_func_softmax.py @@ -0,0 +1,34 @@ +# This script generates test cases for nn_act_func_softmax function. + +import numpy as np + +# Returns the softmax activation function result. +def nn_act_func_softmax(x): + exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True)) + return exp_x / np.sum(exp_x, axis=-1, keepdims=True) + +# Generates a test case. +def generate_test_case(input): + input_c = ", ".join(map(str, input.flatten())) + expected_value = nn_act_func_softmax(input) + expected_value_c = ", ".join(map(str, expected_value.flatten())) + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(1, (const size_t[]){{{len(input)}}}, false, (const NNTensorUnit[]){{{input_c}}}, NULL), + .expected_value = nn_tensor_init_NNTensor(1, (const size_t[]){{{len(input)}}}, false, (const NNTensorUnit[]){{{expected_value_c}}}, NULL), + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [ + np.array([1.0, 2.0, 3.0]), + np.array([-1.0, 0.0, 1.0]), + np.array([0.5, -0.5, 0.0]) +] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/gen/nn_act_func_tensor_batch.py b/scripts/test/gen/nn_act_func_tensor_batch.py new file mode 100644 index 0000000..ccece32 --- /dev/null +++ b/scripts/test/gen/nn_act_func_tensor_batch.py @@ -0,0 +1,34 @@ +# This script generates test cases for nn_act_func_softmax function. + +import numpy as np + +# Returns the softmax activation function result. +def nn_act_func_softmax(x): + exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True)) + return exp_x / np.sum(exp_x, axis=-1, keepdims=True) + +# Generates a test case. +def generate_test_case(input): + input_c = ", ".join(map(str, input.flatten())) + expected_value = nn_act_func_softmax(input) + expected_value_c = ", ".join(map(str, expected_value.flatten())) + return f""" + {{ + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){{1, {len(input)}}}, false, (const NNTensorUnit[]){{{input_c}}}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){{1, {len(input)}}}, false, (const NNTensorUnit[]){{{expected_value_c}}}, NULL), + .expected_tolerance = default_expected_tolerance, + }}""" + +# Generate test cases +np.random.seed(2024) +test_cases = [] +inputs = [ + np.array([-0.1, 0.2, 0.8, 0.0]), + np.array([1.0, 0.5, -0.4, -1.0]), + np.array([0.9, -0.3, 0.1, 0.0]) +] +for input in inputs: + test_cases.append(generate_test_case(input)) + +print(f"TestCase test_cases[] = {{{', '.join(test_cases)},\n}};") diff --git a/scripts/test/layer_gen_tc.py b/scripts/test/gen/nn_layer.py similarity index 98% rename from scripts/test/layer_gen_tc.py rename to scripts/test/gen/nn_layer.py index c4f7762..3084779 100644 --- a/scripts/test/layer_gen_tc.py +++ b/scripts/test/gen/nn_layer.py @@ -1,4 +1,4 @@ -# This script generates test cases for NNLayer. +# This script generates test cases for NNLayer struct. import numpy as np diff --git a/scripts/test/layer_multi_gen_tc.py b/scripts/test/gen/nn_layer_multi.py similarity index 99% rename from scripts/test/layer_multi_gen_tc.py rename to scripts/test/gen/nn_layer_multi.py index 4549814..b328020 100644 --- a/scripts/test/layer_multi_gen_tc.py +++ b/scripts/test/gen/nn_layer_multi.py @@ -1,4 +1,4 @@ -# This script generates test cases for NNLayer. +# This script generates test cases for NNLayer struct. import numpy as np diff --git a/src/nn_activation.c b/src/nn_activation.c index 534d443..b00a126 100644 --- a/src/nn_activation.c +++ b/src/nn_activation.c @@ -6,8 +6,6 @@ #include #include -// TODO: Add tests - NNActFunc nn_act_func_init(NNActFuncType type, void *func) { NN_DEBUG_PRINT(5, "function %s called with type=%d\n", __func__, type); @@ -138,11 +136,9 @@ bool nn_act_func_tensor_batch(const NNActFuncTensor act_func, const NNTensor *in size_t sizes[1] = {sample_size}; NNTensor input_slice; NNTensor output_slice; - for (size_t i = 0; i < batch_size; i++) { nn_tensor_slice(input, i * sample_size, sizes, &input_slice); nn_tensor_slice(output, i * sample_size, sizes, &output_slice); - if (!act_func(&input_slice, &output_slice, error)) { return false; } diff --git a/src/nn_layer.c b/src/nn_layer.c index 44da15c..a8abb71 100644 --- a/src/nn_layer.c +++ b/src/nn_layer.c @@ -172,12 +172,15 @@ bool nn_layer_forward(const NNLayer *layer, const NNTensor *inputs, NNTensor *ou } // TODO: Should we overwrite the weights tensor so that we don't have to allocate a new tensor every time? if (!nn_mat_transpose(layer->weights, weights, error)) { + nn_tensor_destroy_NNTensor(weights); return false; } // Perform matrix multiplication if (!layer->mat_mul_func(inputs, weights, outputs, error)) { + nn_tensor_destroy_NNTensor(weights); return false; } + nn_tensor_destroy_NNTensor(weights); } else { // Perform matrix multiplication if (!layer->mat_mul_func(inputs, layer->weights, outputs, error)) { diff --git a/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c b/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c index c9f33c9..bc0332a 100644 --- a/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c +++ b/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c @@ -21,13 +21,13 @@ int main(int argc, char *argv[]) { struct timespec start, end; long long total_time = 0; const int batch_size = 1024; - const int n_vectors = 4096; + const int vector_size = 4096; NNTensor *vec_a[batch_size]; NNTensor *vec_b[batch_size]; for (int i = 0; i < batch_size; i++) { - vec_a[i] = nn_tensor_init_NNTensor(1, (const size_t[]){4096}, false, NULL, NULL); - vec_b[i] = nn_tensor_init_NNTensor(1, (const size_t[]){4096}, false, NULL, NULL); - for (int j = 0; j < n_vectors; ++j) { + vec_a[i] = nn_tensor_init_NNTensor(1, (const size_t[]){vector_size}, false, NULL, NULL); + vec_b[i] = nn_tensor_init_NNTensor(1, (const size_t[]){vector_size}, false, NULL, NULL); + for (int j = 0; j < vector_size; ++j) { vec_a[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; vec_b[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; } diff --git a/tests/arch/arm/neon/dot_prod_perf/main.c b/tests/arch/arm/neon/dot_prod_perf/main.c index 1b64740..946a19e 100644 --- a/tests/arch/arm/neon/dot_prod_perf/main.c +++ b/tests/arch/arm/neon/dot_prod_perf/main.c @@ -21,13 +21,13 @@ int main(int argc, char *argv[]) { struct timespec start, end; long long total_time = 0; const int batch_size = 1024; - const int n_vectors = 4096; + const int vector_size = 4096; NNTensor *vec_a[batch_size]; NNTensor *vec_b[batch_size]; for (int i = 0; i < batch_size; i++) { - vec_a[i] = nn_tensor_init_NNTensor(1, (const size_t[]){4096}, false, NULL, NULL); - vec_b[i] = nn_tensor_init_NNTensor(1, (const size_t[]){4096}, false, NULL, NULL); - for (int j = 0; j < n_vectors; ++j) { + vec_a[i] = nn_tensor_init_NNTensor(1, (const size_t[]){vector_size}, false, NULL, NULL); + vec_b[i] = nn_tensor_init_NNTensor(1, (const size_t[]){vector_size}, false, NULL, NULL); + for (int j = 0; j < vector_size; ++j) { vec_a[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; vec_b[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; } diff --git a/tests/arch/generic/activation/activation.h b/tests/arch/generic/activation/activation.h new file mode 100644 index 0000000..4a8a7cd --- /dev/null +++ b/tests/arch/generic/activation/activation.h @@ -0,0 +1,8 @@ +void test_nn_act_func_init(); +void test_nn_act_func(); +void test_nn_act_func_identity(); +void test_nn_act_func_sigmoid(); +void test_nn_act_func_relu(); +void test_nn_act_func_softmax(); +void test_nn_act_func_scalar_batch(); +void test_nn_act_func_tensor_batch(); diff --git a/tests/arch/generic/activation/include.txt b/tests/arch/generic/activation/include.txt new file mode 100644 index 0000000..7a72701 --- /dev/null +++ b/tests/arch/generic/activation/include.txt @@ -0,0 +1,15 @@ +tests/arch/generic/activation/nn_act_func_init.c +tests/arch/generic/activation/nn_act_func.c +tests/arch/generic/activation/nn_act_func_identity.c +tests/arch/generic/activation/nn_act_func_sigmoid.c +tests/arch/generic/activation/nn_act_func_relu.c +tests/arch/generic/activation/nn_act_func_softmax.c +tests/arch/generic/activation/nn_act_func_scalar_batch.c +tests/arch/generic/activation/nn_act_func_tensor_batch.c +src/nn_activation.c +src/nn_app.c +src/nn_argmax.c +src/nn_config.c +src/nn_error.c +src/nn_test.c +src/nn_tensor.c diff --git a/tests/arch/generic/activation/main.c b/tests/arch/generic/activation/main.c new file mode 100644 index 0000000..b6eca43 --- /dev/null +++ b/tests/arch/generic/activation/main.c @@ -0,0 +1,18 @@ +#include "./activation.h" +#include "nn_app.h" + +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + + test_nn_act_func_init(); + test_nn_act_func(); + test_nn_act_func_identity(); + test_nn_act_func_sigmoid(); + test_nn_act_func_relu(); + test_nn_act_func_softmax(); + test_nn_act_func_scalar_batch(); + test_nn_act_func_tensor_batch(); + + return 0; +} diff --git a/tests/arch/generic/activation/nn_act_func.c b/tests/arch/generic/activation/nn_act_func.c new file mode 100644 index 0000000..6ea5454 --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func.c @@ -0,0 +1,56 @@ +#include "nn_activation.h" +#include "nn_tensor.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensor *input; + NNTensor *expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.8, 0.2, 0.1}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.48890265771885366, 0.26831546747340185, 0.24278187480774444}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.6, 0.0, 0.6}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.1628071674674988, 0.2966540006808555, 0.5405388318516458}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3, -0.3, 0.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4367518169107908, 0.23969447920584977, 0.32355370388335947}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + NNTensor *output = nn_tensor_init_NNTensor(tc.input->dims, tc.input->sizes, false, NULL, NULL); + bool success = nn_act_func(tc.act_func, tc.input, output, &error); + assert(success); + assert(error.code == NN_ERROR_NONE); + for (size_t j = 0; j < tc.input->sizes[0]; j++) { + assert(fabs(output->data[j] - tc.expected_value->data[j]) < tc.expected_tolerance); + } + printf("passed: %s case=%d\n", __func__, i + 1); + + // Cleanup + nn_tensor_destroy_NNTensor(output); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_identity.c b/tests/arch/generic/activation/nn_act_func_identity.c new file mode 100644 index 0000000..2955cff --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_identity.c @@ -0,0 +1,47 @@ +#include "nn_activation.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensorUnit input; + NNTensorUnit expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func_identity() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func_identity.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_identity), + .input = -1.0, + .expected_value = -1.0, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_identity), + .input = 0.0, + .expected_value = 0.0, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_identity), + .input = 1.0, + .expected_value = 1.0, + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + const NNTensorUnit output = tc.act_func.scalar_func(tc.input); + assert(isnan(output) == false); + assert(fabs(output - tc.expected_value) < tc.expected_tolerance); + printf("passed: %s case=%d\n", __func__, i + 1); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_init.c b/tests/arch/generic/activation/nn_act_func_init.c new file mode 100644 index 0000000..31cb91e --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_init.c @@ -0,0 +1,44 @@ +#include "nn_activation.h" +#include +#include + +typedef struct { + NNActFuncType type; + void *func; + NNActFunc expected_act_func; +} TestCase; + +void test_nn_act_func_init() { + TestCase test_cases[] = { + { + .type = NN_ACT_FUNC_SCALAR, + .func = nn_act_func_identity, + .expected_act_func = { + .type = NN_ACT_FUNC_SCALAR, + .scalar_func = nn_act_func_identity, + }, + }, + { + .type = NN_ACT_FUNC_TENSOR, + .func = nn_act_func_softmax, + .expected_act_func = { + .type = NN_ACT_FUNC_TENSOR, + .tensor_func = nn_act_func_softmax, + }, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNActFunc act_func = nn_act_func_init(tc.type, tc.func); + assert(act_func.type == tc.expected_act_func.type); + if (act_func.type == NN_ACT_FUNC_SCALAR) { + assert(act_func.scalar_func == tc.expected_act_func.scalar_func); + } else { + assert(act_func.tensor_func == tc.expected_act_func.tensor_func); + } + printf("passed: %s case=%d\n", __func__, i + 1); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_relu.c b/tests/arch/generic/activation/nn_act_func_relu.c new file mode 100644 index 0000000..e973710 --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_relu.c @@ -0,0 +1,59 @@ +#include "nn_activation.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensorUnit input; + NNTensorUnit expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func_relu() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func_relu.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_relu), + .input = -2.0, + .expected_value = 0.0, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_relu), + .input = -1.0, + .expected_value = 0.0, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_relu), + .input = 0.0, + .expected_value = 0.0, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_relu), + .input = 1.0, + .expected_value = 1.0, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_relu), + .input = 2.0, + .expected_value = 2.0, + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + const NNTensorUnit output = tc.act_func.scalar_func(tc.input); + assert(isnan(output) == false); + assert(fabs(output - tc.expected_value) < tc.expected_tolerance); + printf("passed: %s case=%d\n", __func__, i + 1); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_scalar_batch.c b/tests/arch/generic/activation/nn_act_func_scalar_batch.c new file mode 100644 index 0000000..a62fc06 --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_scalar_batch.c @@ -0,0 +1,56 @@ +#include "nn_activation.h" +#include "nn_tensor.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensor *input; + NNTensor *expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func_scalar_batch() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func_scalar_batch.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_relu), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.8, 0.2, -0.1, 0.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.8, 0.2, 0.0, 0.0}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_relu), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.6, 0.0, 0.6, -1.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.0, 0.0, 0.6, 0.0}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_relu), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3, -0.3, 1.0, 0.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3, 0.0, 1.0, 0.0}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + NNTensor *output = nn_tensor_init_NNTensor(tc.input->dims, tc.input->sizes, false, NULL, NULL); + bool success = nn_act_func_scalar_batch(tc.act_func.scalar_func, tc.input, output, &error); + assert(success); + assert(error.code == NN_ERROR_NONE); + for (size_t j = 0; j < tc.input->sizes[0]; j++) { + assert(fabs(output->data[j] - tc.expected_value->data[j]) < tc.expected_tolerance); + } + printf("passed: %s case=%d\n", __func__, i + 1); + + // Cleanup + nn_tensor_destroy_NNTensor(output); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_sigmoid.c b/tests/arch/generic/activation/nn_act_func_sigmoid.c new file mode 100644 index 0000000..4f4d372 --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_sigmoid.c @@ -0,0 +1,59 @@ +#include "nn_activation.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensorUnit input; + NNTensorUnit expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func_sigmoid() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func_sigmoid.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_sigmoid), + .input = -2.0, + .expected_value = 0.11920292202211755, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_sigmoid), + .input = -1.0, + .expected_value = 0.2689414213699951, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_sigmoid), + .input = 0.0, + .expected_value = 0.5, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_sigmoid), + .input = 1.0, + .expected_value = 0.7310585786300049, + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_sigmoid), + .input = 2.0, + .expected_value = 0.8807970779778823, + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + const NNTensorUnit output = tc.act_func.scalar_func(tc.input); + assert(isnan(output) == false); + assert(fabs(output - tc.expected_value) < tc.expected_tolerance); + printf("passed: %s case=%d\n", __func__, i + 1); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_softmax.c b/tests/arch/generic/activation/nn_act_func_softmax.c new file mode 100644 index 0000000..0d4af68 --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_softmax.c @@ -0,0 +1,56 @@ +#include "nn_activation.h" +#include "nn_tensor.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensor *input; + NNTensor *expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func_softmax() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func_softmax.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){1.0, 2.0, 3.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.09003057317038046, 0.24472847105479764, 0.6652409557748218}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-1.0, 0.0, 1.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.09003057317038046, 0.24472847105479764, 0.6652409557748218}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.5, -0.5, 0.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.506480391055654, 0.1863237232258476, 0.3071958857184984}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + NNTensor *output = nn_tensor_init_NNTensor(tc.input->dims, tc.input->sizes, false, NULL, NULL); + bool success = tc.act_func.tensor_func(tc.input, output, &error); + assert(success); + assert(error.code == NN_ERROR_NONE); + for (size_t j = 0; j < tc.input->sizes[0]; j++) { + assert(fabs(output->data[j] - tc.expected_value->data[j]) < tc.expected_tolerance); + } + printf("passed: %s case=%d\n", __func__, i + 1); + + // Cleanup + nn_tensor_destroy_NNTensor(output); + } +} diff --git a/tests/arch/generic/activation/nn_act_func_tensor_batch.c b/tests/arch/generic/activation/nn_act_func_tensor_batch.c new file mode 100644 index 0000000..4dc4a63 --- /dev/null +++ b/tests/arch/generic/activation/nn_act_func_tensor_batch.c @@ -0,0 +1,56 @@ +#include "nn_activation.h" +#include "nn_tensor.h" +#include +#include +#include + +typedef struct { + NNActFunc act_func; + NNTensor *input; + NNTensor *expected_value; + NNTensorUnit expected_tolerance; +} TestCase; + +void test_nn_act_func_tensor_batch() { + const NNTensorUnit default_expected_tolerance = 0.000001f; + + // See scripts/test/gen/nn_act_func_tensor_batch.py + TestCase test_cases[] = { + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.1, 0.2, 0.8, 0.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.16907220238197862, 0.2282236015015863, 0.41585051498887204, 0.18685368112756298}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){1.0, 0.5, -0.4, -1.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.5029010078762762, 0.3050248800773461, 0.12401386170546366, 0.06806025034091384}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + { + .act_func = nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_softmax), + .input = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.9, -0.3, 0.1, 0.0}, NULL), + .expected_value = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.4635869089255157, 0.13962969368663453, 0.2083030255658067, 0.18848037182204302}, NULL), + .expected_tolerance = default_expected_tolerance, + }, + }; + + const int n_cases = sizeof(test_cases) / sizeof(test_cases[0]); + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + NNTensor *output = nn_tensor_init_NNTensor(tc.input->dims, tc.input->sizes, false, NULL, NULL); + bool success = nn_act_func_tensor_batch(tc.act_func.tensor_func, tc.input, output, &error); + assert(success); + assert(error.code == NN_ERROR_NONE); + for (size_t j = 0; j < tc.input->sizes[0]; j++) { + assert(fabs(output->data[j] - tc.expected_value->data[j]) < tc.expected_tolerance); + } + printf("passed: %s case=%d\n", __func__, i + 1); + + // Cleanup + nn_tensor_destroy_NNTensor(output); + } +} diff --git a/tests/arch/generic/activation_perf/activation_perf.h b/tests/arch/generic/activation_perf/activation_perf.h new file mode 100644 index 0000000..4a8a7cd --- /dev/null +++ b/tests/arch/generic/activation_perf/activation_perf.h @@ -0,0 +1,8 @@ +void test_nn_act_func_init(); +void test_nn_act_func(); +void test_nn_act_func_identity(); +void test_nn_act_func_sigmoid(); +void test_nn_act_func_relu(); +void test_nn_act_func_softmax(); +void test_nn_act_func_scalar_batch(); +void test_nn_act_func_tensor_batch(); diff --git a/tests/arch/generic/activation_perf/include.txt b/tests/arch/generic/activation_perf/include.txt new file mode 100644 index 0000000..b7e452a --- /dev/null +++ b/tests/arch/generic/activation_perf/include.txt @@ -0,0 +1,15 @@ +tests/arch/generic/activation_perf/nn_act_func_init.c +tests/arch/generic/activation_perf/nn_act_func.c +tests/arch/generic/activation_perf/nn_act_func_identity.c +tests/arch/generic/activation_perf/nn_act_func_sigmoid.c +tests/arch/generic/activation_perf/nn_act_func_relu.c +tests/arch/generic/activation_perf/nn_act_func_softmax.c +tests/arch/generic/activation_perf/nn_act_func_scalar_batch.c +tests/arch/generic/activation_perf/nn_act_func_tensor_batch.c +src/nn_activation.c +src/nn_app.c +src/nn_argmax.c +src/nn_config.c +src/nn_error.c +src/nn_test.c +src/nn_tensor.c diff --git a/tests/arch/generic/activation_perf/main.c b/tests/arch/generic/activation_perf/main.c new file mode 100644 index 0000000..8e968ec --- /dev/null +++ b/tests/arch/generic/activation_perf/main.c @@ -0,0 +1,22 @@ +#include "./activation_perf.h" +#include "nn_app.h" +#include +#include + +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + + srand((unsigned int)time(NULL)); + + test_nn_act_func_init(); + test_nn_act_func(); + test_nn_act_func_identity(); + test_nn_act_func_sigmoid(); + test_nn_act_func_relu(); + test_nn_act_func_softmax(); + test_nn_act_func_scalar_batch(); + test_nn_act_func_tensor_batch(); + + return 0; +} diff --git a/tests/arch/generic/activation_perf/nn_act_func.c b/tests/arch/generic/activation_perf/nn_act_func.c new file mode 100644 index 0000000..2375b99 --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func.c @@ -0,0 +1,24 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNActFunc act_func = nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_identity); + NNTensor *input = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, NULL, NULL); + NNTensor *output = nn_tensor_init_NNTensor(input->dims, input->sizes, false, NULL, NULL); + NNError error = {0}; + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func(act_func, input, output, &error); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_identity.c b/tests/arch/generic/activation_perf/nn_act_func_identity.c new file mode 100644 index 0000000..2ad82bd --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_identity.c @@ -0,0 +1,24 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_identity() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNTensorUnit inputs[iterations]; + for (int i = 0; i < iterations; i++) { + inputs[i] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_identity(inputs[i]); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_identity\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_init.c b/tests/arch/generic/activation_perf/nn_act_func_init.c new file mode 100644 index 0000000..0d341f6 --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_init.c @@ -0,0 +1,29 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_init() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_init(NN_ACT_FUNC_SCALAR, nn_act_func_identity); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_init details=NN_ACT_FUNC_SCALAR\n", total_time / iterations, total_time / 1000000); + + total_time = 0; + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_init(NN_ACT_FUNC_TENSOR, nn_act_func_sigmoid); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_init details=NN_ACT_FUNC_TENSOR\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_relu.c b/tests/arch/generic/activation_perf/nn_act_func_relu.c new file mode 100644 index 0000000..a7e2123 --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_relu.c @@ -0,0 +1,24 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_relu() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNTensorUnit inputs[iterations]; + for (int i = 0; i < iterations; i++) { + inputs[i] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_relu(inputs[i]); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_relu\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_scalar_batch.c b/tests/arch/generic/activation_perf/nn_act_func_scalar_batch.c new file mode 100644 index 0000000..66273bb --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_scalar_batch.c @@ -0,0 +1,28 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_scalar_batch() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNTensor *inputs[iterations]; + NNTensor *outputs[iterations]; + for (int i = 0; i < iterations; i++) { + inputs[i] = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, NULL, NULL); + outputs[i] = nn_tensor_init_NNTensor(inputs[i]->dims, inputs[i]->sizes, false, NULL, NULL); + inputs[i]->data[0] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + NNError error = {0}; + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_scalar_batch(nn_act_func_identity, inputs[i], outputs[i], &error); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_scalar_batch\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_sigmoid.c b/tests/arch/generic/activation_perf/nn_act_func_sigmoid.c new file mode 100644 index 0000000..5c57cf3 --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_sigmoid.c @@ -0,0 +1,24 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_sigmoid() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNTensorUnit inputs[iterations]; + for (int i = 0; i < iterations; i++) { + inputs[i] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_sigmoid(inputs[i]); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_sigmoid\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_softmax.c b/tests/arch/generic/activation_perf/nn_act_func_softmax.c new file mode 100644 index 0000000..e9f3f30 --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_softmax.c @@ -0,0 +1,28 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_softmax() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNTensor *inputs[iterations]; + NNTensor *outputs[iterations]; + for (int i = 0; i < iterations; i++) { + inputs[i] = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, NULL, NULL); + outputs[i] = nn_tensor_init_NNTensor(inputs[i]->dims, inputs[i]->sizes, false, NULL, NULL); + inputs[i]->data[0] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + NNError error = {0}; + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_softmax(inputs[i], outputs[i], &error); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_softmax\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/activation_perf/nn_act_func_tensor_batch.c b/tests/arch/generic/activation_perf/nn_act_func_tensor_batch.c new file mode 100644 index 0000000..0bb3e99 --- /dev/null +++ b/tests/arch/generic/activation_perf/nn_act_func_tensor_batch.c @@ -0,0 +1,28 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_activation.h" +#include "nn_test.h" +#include +#include + +void test_nn_act_func_tensor_batch() { + struct timespec start, end; + long long total_time = 0; + const int iterations = 100000; + NNTensor *inputs[iterations]; + NNTensor *outputs[iterations]; + for (int i = 0; i < iterations; i++) { + inputs[i] = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, NULL, NULL); + outputs[i] = nn_tensor_init_NNTensor(inputs[i]->dims, inputs[i]->sizes, false, NULL, NULL); + inputs[i]->data[0] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + NNError error = {0}; + + clock_gettime(CLOCK_MONOTONIC, &start); + for (int i = 0; i < iterations; i++) { + nn_act_func_tensor_batch(nn_act_func_softmax, inputs[i], outputs[i], &error); + } + clock_gettime(CLOCK_MONOTONIC, &end); + total_time = nn_timespec_diff_ns(&start, &end); + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_act_func_tensor_batch\n", total_time / iterations, total_time / 1000000); +} diff --git a/tests/arch/generic/dot_prod_perf/main.c b/tests/arch/generic/dot_prod_perf/main.c index 7481145..b282892 100644 --- a/tests/arch/generic/dot_prod_perf/main.c +++ b/tests/arch/generic/dot_prod_perf/main.c @@ -20,13 +20,13 @@ int main(int argc, char *argv[]) { struct timespec start, end; long long total_time = 0; const int batch_size = 1024; - const int n_vectors = 4096; + const int vector_size = 4096; NNTensor *vec_a[batch_size]; NNTensor *vec_b[batch_size]; for (int i = 0; i < batch_size; i++) { - vec_a[i] = nn_tensor_init_NNTensor(1, (const size_t[]){4096}, false, NULL, NULL); - vec_b[i] = nn_tensor_init_NNTensor(1, (const size_t[]){4096}, false, NULL, NULL); - for (int j = 0; j < n_vectors; ++j) { + vec_a[i] = nn_tensor_init_NNTensor(1, (const size_t[]){vector_size}, false, NULL, NULL); + vec_b[i] = nn_tensor_init_NNTensor(1, (const size_t[]){vector_size}, false, NULL, NULL); + for (int j = 0; j < vector_size; ++j) { vec_a[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; vec_b[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; } diff --git a/tests/arch/generic/layer/main.c b/tests/arch/generic/layer/main.c index fb251e9..746173a 100644 --- a/tests/arch/generic/layer/main.c +++ b/tests/arch/generic/layer/main.c @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) { const int n_test_cases = 256; const float default_output_tolerance = 0.000001f; - // Use scripts/test/layer_gen_tc.py to generate test cases + // Use scripts/test/gen to generate test cases TestCase test_cases[] = { { .batch_size = 1, diff --git a/tests/arch/generic/layer_multi/main.c b/tests/arch/generic/layer_multi/main.c index 536705c..e8f2db0 100644 --- a/tests/arch/generic/layer_multi/main.c +++ b/tests/arch/generic/layer_multi/main.c @@ -115,7 +115,7 @@ int main(int argc, char *argv[]) { const int n_test_cases = 256; const float default_output_tolerance = 0.000001f; - // Use scripts/test/layer_multi_gen_tc.py to generate the test cases + // Use scripts/test/gen to generate test cases TestCase test_cases[] = { { .batch_size = 1,