From a132ed9b78e1233068b2fe2bc26f4be1d8dfcd0d Mon Sep 17 00:00:00 2001 From: Fatih Cetinkaya <965295+devfacet@users.noreply.github.com> Date: Sat, 11 May 2024 20:09:12 -0400 Subject: [PATCH 1/5] Refactoring for NNTensor --- .github/workflows/test.yaml | 10 +- Makefile | 92 +- README.md | 18 +- examples/arch/generic/layer/main.c | 80 - include/arch/arm/cmsis-dsp/nn_dot_prod.h | 18 + include/arch/arm/cmsis-dsp/nn_dot_product.h | 14 - include/arch/arm/neon/nn_dot_prod.h | 18 + include/arch/arm/neon/nn_dot_product.h | 14 - include/nn_activation.h | 119 +- include/nn_app.h | 36 +- include/nn_config.h | 48 +- include/nn_debug.h | 8 +- include/nn_dot_prod.h | 29 + include/nn_dot_product.h | 17 - include/nn_error.h | 55 +- include/nn_layer.h | 152 +- include/nn_mat_mul.h | 31 + include/nn_mat_transpose.h | 29 + include/nn_neuron.h | 44 - include/nn_tensor.h | 242 + include/nn_test.h | 9 +- scripts/docker/Dockerfile.amd64 | 6 +- scripts/docker/Dockerfile.amd64-generic | 11 +- scripts/docker/Dockerfile.arm | 8 +- scripts/docker/Dockerfile.arm-cmsis-dsp | 11 +- scripts/docker/Dockerfile.arm-neon | 11 +- scripts/docker/Dockerfile.armv7-neon | 11 +- scripts/docker/Dockerfile.armv8-neon | 11 +- scripts/shell/build_artifact.sh | 36 +- scripts/shell/run_artifact.sh | 2 +- scripts/test/layer_gen_tc.py | 92 + scripts/test/layer_multi_gen_tc.py | 134 + src/arch/arm/cmsis-dsp/nn_dot_prod.c | 28 + src/arch/arm/cmsis-dsp/nn_dot_product.c | 16 - src/arch/arm/neon/nn_dot_prod.c | 41 + src/arch/arm/neon/nn_dot_product.c | 32 - src/nn_activation.c | 147 +- src/nn_app.c | 17 +- src/nn_config.c | 74 +- src/nn_dot_prod.c | 28 + src/nn_dot_product.c | 18 - src/nn_error.c | 47 +- src/nn_layer.c | 245 +- src/nn_mat_mul.c | 34 + src/nn_mat_transpose.c | 48 + src/nn_neuron.c | 101 - src/nn_test.c | 2 +- tests/arch/arm/cmsis-dsp/dot_prod/include.txt | 8 + tests/arch/arm/cmsis-dsp/dot_prod/main.c | 70 + .../arm/cmsis-dsp/dot_prod_perf/include.txt | 8 + tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c | 46 + .../arm/cmsis-dsp/dot_product_perf/main.c | 41 - tests/arch/arm/cmsis-dsp/neuron/main.c | 140 - tests/arch/arm/cmsis-dsp/neuron_perf/main.c | 60 - tests/arch/arm/neon/dot_prod/include.txt | 5 + tests/arch/arm/neon/dot_prod/main.c | 70 + tests/arch/arm/neon/dot_prod_perf/include.txt | 5 + tests/arch/arm/neon/dot_prod_perf/main.c | 46 + tests/arch/arm/neon/dot_product_perf/main.c | 41 - tests/arch/arm/neon/neuron/main.c | 140 - tests/arch/arm/neon/neuron_perf/main.c | 61 - tests/arch/generic/dot_prod/include.txt | 5 + tests/arch/generic/dot_prod/main.c | 70 + tests/arch/generic/dot_prod_perf/include.txt | 5 + tests/arch/generic/dot_prod_perf/main.c | 45 + tests/arch/generic/dot_product/main.c | 73 - tests/arch/generic/dot_product_perf/main.c | 36 - tests/arch/generic/layer/include.txt | 8 + tests/arch/generic/layer/main.c | 3879 +++- tests/arch/generic/layer_multi/include.txt | 8 + tests/arch/generic/layer_multi/main.c | 17256 +++++++++++++++- tests/arch/generic/neuron/main.c | 138 - tests/arch/generic/neuron_perf/main.c | 55 - tests/arch/generic/softmax/main.c | 76 - 74 files changed, 22677 insertions(+), 2012 deletions(-) delete mode 100644 examples/arch/generic/layer/main.c create mode 100644 include/arch/arm/cmsis-dsp/nn_dot_prod.h delete mode 100644 include/arch/arm/cmsis-dsp/nn_dot_product.h create mode 100644 include/arch/arm/neon/nn_dot_prod.h delete mode 100644 include/arch/arm/neon/nn_dot_product.h create mode 100644 include/nn_dot_prod.h delete mode 100644 include/nn_dot_product.h create mode 100644 include/nn_mat_mul.h create mode 100644 include/nn_mat_transpose.h delete mode 100644 include/nn_neuron.h create mode 100644 include/nn_tensor.h create mode 100644 scripts/test/layer_gen_tc.py create mode 100644 scripts/test/layer_multi_gen_tc.py create mode 100644 src/arch/arm/cmsis-dsp/nn_dot_prod.c delete mode 100644 src/arch/arm/cmsis-dsp/nn_dot_product.c create mode 100644 src/arch/arm/neon/nn_dot_prod.c delete mode 100644 src/arch/arm/neon/nn_dot_product.c create mode 100644 src/nn_dot_prod.c delete mode 100644 src/nn_dot_product.c create mode 100644 src/nn_mat_mul.c create mode 100644 src/nn_mat_transpose.c delete mode 100644 src/nn_neuron.c create mode 100644 tests/arch/arm/cmsis-dsp/dot_prod/include.txt create mode 100644 tests/arch/arm/cmsis-dsp/dot_prod/main.c create mode 100644 tests/arch/arm/cmsis-dsp/dot_prod_perf/include.txt create mode 100644 tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c delete mode 100644 tests/arch/arm/cmsis-dsp/dot_product_perf/main.c delete mode 100644 tests/arch/arm/cmsis-dsp/neuron/main.c delete mode 100644 tests/arch/arm/cmsis-dsp/neuron_perf/main.c create mode 100644 tests/arch/arm/neon/dot_prod/include.txt create mode 100644 tests/arch/arm/neon/dot_prod/main.c create mode 100644 tests/arch/arm/neon/dot_prod_perf/include.txt create mode 100644 tests/arch/arm/neon/dot_prod_perf/main.c delete mode 100644 tests/arch/arm/neon/dot_product_perf/main.c delete mode 100644 tests/arch/arm/neon/neuron/main.c delete mode 100644 tests/arch/arm/neon/neuron_perf/main.c create mode 100644 tests/arch/generic/dot_prod/include.txt create mode 100644 tests/arch/generic/dot_prod/main.c create mode 100644 tests/arch/generic/dot_prod_perf/include.txt create mode 100644 tests/arch/generic/dot_prod_perf/main.c delete mode 100644 tests/arch/generic/dot_product/main.c delete mode 100644 tests/arch/generic/dot_product_perf/main.c create mode 100644 tests/arch/generic/layer/include.txt create mode 100644 tests/arch/generic/layer_multi/include.txt delete mode 100644 tests/arch/generic/neuron/main.c delete mode 100644 tests/arch/generic/neuron_perf/main.c delete mode 100644 tests/arch/generic/softmax/main.c diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1dd84e9..42ea469 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -85,18 +85,18 @@ jobs: - name: Test run: | if [ "${{ matrix.test }}" == "arm-neon" ]; then - TESTS=arch/arm/neon/dot_product_perf,arch/arm/neon/neuron,arch/arm/neon/neuron_perf + TESTS=make test ARCH=arm FILTERS=neon elif [ "${{ matrix.test }}" == "arm-cmsis-dsp" ]; then - TESTS=arch/arm/cmsis-dsp/dot_product_perf,arch/arm/cmsis-dsp/neuron,arch/arm/cmsis-dsp/neuron_perf + TESTS=make test ARCH=arm FILTERS=cmsis-dsp elif [ "${{ matrix.test }}" == "amd64-generic" ]; then - TESTS=arch/generic/dot_product,arch/generic/dot_product_perf,arch/generic/layer,arch/generic/layer_multi,arch/generic/neuron,arch/generic/neuron_perf + TESTS=make test ARCH=generic else echo "unknown test" exit 1 fi - IFS=',' read -ra TESTS <<< "$TESTS" + IFS='|' read -ra TESTS <<< "$TESTS" for TEST in "${TESTS[@]}"; do echo "running ${TEST}" - docker run --platform ${{ matrix.platform }} ${{ matrix.tag }} "/nn/build/tests/${TEST}" + docker run --platform ${{ matrix.platform }} ${{ matrix.tag }} "${TEST}" echo " " done diff --git a/Makefile b/Makefile index eabf46e..bde1a9b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ ARCH := generic endif export ARCH -.PHONY: help run-arm-examples +.PHONY: help all: help help: Makefile @echo @@ -27,76 +27,44 @@ clean: echo "build directory does not exist, skipping"; \ fi -## test Run tests (e.g., make test ARCH=generic) +## test Run tests (e.g., make test ARCH=generic OR make test ARCH=arm FILTERS=neon,cmsis-dsp) test: - @$(MAKE) build-tests ARCH=$(ARCH) TECH=$(TECH) + @echo testing ARCH=$(ARCH) FILTERS=$(FILTERS) ARGS=$(ARGS) + @$(MAKE) build-artifacts PREFIX=tests/arch/$(ARCH) FILTERS=$(FILTERS) @echo " " - @$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) - @$(eval TESTS := $(shell find tests/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|tests/||')) - @for test in $(TESTS); do \ - $(MAKE) run-test ARCH=$(ARCH) TECH=$(TECH) TEST=$$test || exit 1; \ - done + @$(MAKE) run-artifacts PREFIX=tests/arch/$(ARCH) FILTERS=$(FILTERS) ARGS="$(ARGS)" -## test-all Run tests (e.g., make test ARCH=generic) +## test-all Run tests (e.g., make test-all ARCH=generic) test-all: - @$(MAKE) build-tests ARCH=generic - @$(MAKE) build-tests ARCH=arm TECH=neon - @$(MAKE) build-tests ARCH=arm TECH=cmsis-dsp - @echo " " - @$(MAKE) run-tests ARCH=generic - @$(MAKE) run-tests ARCH=arm TECH=neon - @$(MAKE) run-tests ARCH=arm TECH=cmsis-dsp - -## build-test Build a test (e.g., make build-test ARCH=generic TEST=arch/generic/neuron) -build-test: - @echo building $(TEST) - @ARCH=$(ARCH) TECH=$(TECH) ARTIFACT=tests/$(TEST) scripts/shell/build_artifact.sh - -## build-tests Build tests (e.g., make build-tests ARCH=generic) -build-tests: - @$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) - @$(eval TESTS := $(shell find tests/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|tests/||')) - @for test in $(TESTS); do \ - $(MAKE) build-test ARCH=$(ARCH) TECH=$(TECH) TEST=$$test || exit 1; \ - done - -## run-test Run a test (e.g., make run-test ARCH=generic TEST=arch/generic/neuron) -run-test: - @echo running $(TEST) - @ARCH=$(ARCH) TECH=$(TECH) ARTIFACT=tests/$(TEST) ARGS="$(ARGS)" scripts/shell/run_artifact.sh + @$(MAKE) build-artifacts PREFIX=tests/arch/generic + @$(MAKE) build-artifacts PREFIX=tests/arch/arm FILTERS=neon,cmsis-dsp @echo " " + @$(MAKE) run-artifacts PREFIX=tests/arch/generic + @$(MAKE) run-artifacts PREFIX=tests/arch/arm FILTERS=neon,cmsis-dsp -## run-tests Run tests (e.g., make run-tests ARCH=generic) -run-tests: - @$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) - @$(eval TESTS := $(shell find tests/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|tests/||')) - @for test in $(TESTS); do \ - $(MAKE) run-test ARCH=$(ARCH) TECH=$(TECH) TEST=$$test || exit 1; \ - done - -## build-example Build an example (e.g., make build-example ARCH=generic EXAMPLE=arch/generic/layer) -build-example: - @echo building $(EXAMPLE) - @ARCH=$(ARCH) TECH=$(TECH) ARTIFACT=examples/$(EXAMPLE) scripts/shell/build_artifact.sh +## build-artifact Build an artifact (e.g., make build-artifact ARTIFACT=tests/arch/generic/layer) +build-artifact: + @echo building ARTIFACT=$(ARTIFACT) + @ARTIFACT=$(ARTIFACT) scripts/shell/build_artifact.sh -## build-examples Build examples (e.g., make build-examples ARCH=generic) -build-examples: - @$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) - @$(eval EXAMPLES := $(shell find examples/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|examples/||')) - @for example in $(EXAMPLES); do \ - $(MAKE) build-example ARCH=$(ARCH) TECH=$(TECH) EXAMPLE=$$example || exit 1; \ +## build-artifacts Build artifacts (e.g., make build-artifacts PREFIX=tests/arch/generic) +build-artifacts: + @$(eval FILTERS_GREP := $(if $(FILTERS),$(shell echo $(FILTERS) | tr ',' '|'),.*)) + @$(eval ARTIFACTS := $(shell find $(PREFIX) -type f -name 'main.c' | grep -E "$(FILTERS_GREP)" | sed 's|/main.c||' | sort)) + @for artifact in $(ARTIFACTS); do \ + $(MAKE) build-artifact ARTIFACT=$$artifact || exit 1; \ done -## run-example Run an examples (e.g., make run-example ARCH=generic EXAMPLE=arch/generic/layer) -run-example: - @echo running $(EXAMPLE) $(ARGS) - @ARCH=$(ARCH) ARTIFACT=examples/$(EXAMPLE) ARGS="$(ARGS)" scripts/shell/run_artifact.sh +## run-artifact Run an artifact (e.g., make run-artifact ARTIFACT=tests/arch/generic/layer) +run-artifact: + @echo running ARTIFACT=$(ARTIFACT) ARGS=$(ARGS) + @ARTIFACT=$(ARTIFACT) ARGS="$(ARGS)" scripts/shell/run_artifact.sh @echo " " -## run-examples Run examples (e.g., make run-examples ARCH=generic) -run-examples: - @$(eval TECH_FILTER := $(if $(TECH),$(shell echo $(TECH) | tr ',' '|'),.*)) - @$(eval EXAMPLES := $(shell find examples/arch/$(ARCH) -type f -name 'main.c' | grep -E "$(TECH_FILTER)" | sed 's|/main.c||' | sed 's|examples/||')) - @for example in $(EXAMPLES); do \ - $(MAKE) run-example ARCH=$(ARCH) TECH=$(TECH) EXAMPLE=$$example || exit 1; \ +## run-artifacts Run tests (e.g., make run-artifacts PREFIX=tests/arch/generic) +run-artifacts: + @$(eval FILTERS_GREP := $(if $(FILTERS),$(shell echo $(FILTERS) | tr ',' '|'),.*)) + @$(eval ARTIFACTS := $(shell find $(PREFIX) -type f -name 'main.c' | grep -E "$(FILTERS_GREP)" | sed 's|/main.c||' | sort)) + @for artifact in $(ARTIFACTS); do \ + $(MAKE) run-artifact ARTIFACT=$$artifact ARGS="$(ARGS)" || exit 1; \ done diff --git a/README.md b/README.md index 43e1e7a..774c663 100644 --- a/README.md +++ b/README.md @@ -26,19 +26,21 @@ git submodule update --init ## Usage -### Build and run examples - -```shell -make build-examples ARCH=generic -make run-examples ARCH=generic -``` - ## Test ```shell +# Test the default architecture (generic) make test + +# Test a specific architecture make test ARCH=generic -make test ARCH=arm TECH=neon,cmsis-dsp +make test ARCH=arm + +# Test a specific architecture with filters +make test ARCH=generic FILTERS=dot_prod +make test ARCH=arm FILTERS=neon,cmsis-dsp + +# Test all architectures make test-all ``` diff --git a/examples/arch/generic/layer/main.c b/examples/arch/generic/layer/main.c deleted file mode 100644 index c464655..0000000 --- a/examples/arch/generic/layer/main.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "nn_activation.h" -#include "nn_dot_product.h" -#include "nn_layer.h" -#include -#include -#include - -int main() { - srand((unsigned int)time(NULL)); - - // Init vars - NNLayer layer; - NNError error; - const int input_size = 4; - const int output_size = 3; - const int batch_size = 2; - - // Initialize a layer with the given input and output sizes, ReLU activation function, and dot product function - if (!nn_layer_init(&layer, input_size, output_size, &error)) { - fprintf(stderr, "error: %s\n", error.message); - return 1; - } - - // Initialize the weights of the layer with Gaussian random values scaled by 0.01 - if (!nn_layer_init_weights_gaussian(&layer, 0.01f, &error)) { - fprintf(stderr, "error: %s\n", error.message); - return 1; - } - - // Initialize the biases of the layer to zero - if (!nn_layer_init_biases_zeros(&layer, &error)) { - fprintf(stderr, "error: %s\n", error.message); - return 1; - } - - // Set the dot product function of the layer - if (!nn_layer_set_dot_prod_func(&layer, nn_dot_prod, &error)) { - fprintf(stderr, "error: %s\n", error.message); - return 1; - } - - // Generate random inputs - float inputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - for (size_t i = 0; i < batch_size; ++i) { - for (size_t j = 0; j < input_size; ++j) { - inputs[i][j] = (float)rand() / (float)RAND_MAX; - } - } - - // Compute the layer with the given inputs - float outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE]; - if (!nn_layer_forward(&layer, inputs, outputs, batch_size, &error)) { - fprintf(stderr, "error: %s\n", error.message); - return 1; - } - - // Compute the ReLU activation function on the outputs - for (size_t i = 0; i < batch_size; ++i) { - if (!nn_act_func_forward_scalar(nn_act_func_relu, outputs[i], outputs[i], output_size, &error)) { - fprintf(stderr, "error: %s\n", error.message); - return 1; - } - } - - // Print the inputs - for (size_t i = 0; i < batch_size; ++i) { - for (size_t j = 0; j < input_size; ++j) { - printf("inputs[%zu][%zu] = %f\n", i, j, inputs[i][j]); - } - } - - // Print the outputs - for (size_t i = 0; i < batch_size; ++i) { - for (size_t j = 0; j < output_size; ++j) { - printf("outputs[%zu][%zu] = %f\n", i, j, outputs[i][j]); - } - } - - return 0; -} diff --git a/include/arch/arm/cmsis-dsp/nn_dot_prod.h b/include/arch/arm/cmsis-dsp/nn_dot_prod.h new file mode 100644 index 0000000..e43b93b --- /dev/null +++ b/include/arch/arm/cmsis-dsp/nn_dot_prod.h @@ -0,0 +1,18 @@ +#ifndef NN_DOT_PROD_CMSIS_DSP_H +#define NN_DOT_PROD_CMSIS_DSP_H + +#include "nn_error.h" +#include "nn_tensor.h" + +/** + * @brief Returns the dot product of two 1-dimensional tensors. + * + * @param a The first tensor. + * @param b The second tensor. + * @param error The error instance to set if an error occurs. + * + * @return The result of the dot product or NAN if an error occurs. + */ +NNTensorUnit nn_dot_prod_cmsis_dsp(const NNTensor *a, const NNTensor *b, NNError *error); + +#endif // NN_DOT_PROD_CMSIS_DSP_H diff --git a/include/arch/arm/cmsis-dsp/nn_dot_product.h b/include/arch/arm/cmsis-dsp/nn_dot_product.h deleted file mode 100644 index 41858e5..0000000 --- a/include/arch/arm/cmsis-dsp/nn_dot_product.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef NN_DOT_PRODUCT_CMSIS_H -#define NN_DOT_PRODUCT_CMSIS_H - -#include - -// NN_DOT_PROD_MAX_VECTOR_SIZE defines the maximum size of a vector. -#ifndef NN_DOT_PROD_MAX_VECTOR_SIZE -#define NN_DOT_PROD_MAX_VECTOR_SIZE 64 -#endif - -// nn_dot_product_cmsis calculates the dot product of two vectors. -float nn_dot_product_cmsis(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size); - -#endif // NN_DOT_PRODUCT_CMSIS_H diff --git a/include/arch/arm/neon/nn_dot_prod.h b/include/arch/arm/neon/nn_dot_prod.h new file mode 100644 index 0000000..b52872c --- /dev/null +++ b/include/arch/arm/neon/nn_dot_prod.h @@ -0,0 +1,18 @@ +#ifndef NN_DOT_PROD_NEON_H +#define NN_DOT_PROD_NEON_H + +#include "nn_error.h" +#include "nn_tensor.h" + +/** + * @brief Returns the dot product of two 1-dimensional tensors. + * + * @param a The first tensor. + * @param b The second tensor. + * @param error The error instance to set if an error occurs. + * + * @return The result of the dot product or NAN if an error occurs. + */ +NNTensorUnit nn_dot_prod_neon(const NNTensor *a, const NNTensor *b, NNError *error); + +#endif // NN_DOT_PROD_NEON_H diff --git a/include/arch/arm/neon/nn_dot_product.h b/include/arch/arm/neon/nn_dot_product.h deleted file mode 100644 index 8bb7a0a..0000000 --- a/include/arch/arm/neon/nn_dot_product.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef NN_DOT_PRODUCT_NEON_H -#define NN_DOT_PRODUCT_NEON_H - -#include - -// NN_DOT_PROD_MAX_VECTOR_SIZE defines the maximum size of a vector. -#ifndef NN_DOT_PROD_MAX_VECTOR_SIZE -#define NN_DOT_PROD_MAX_VECTOR_SIZE 64 -#endif - -// nn_dot_product_neon calculates the dot product of two vectors. -float nn_dot_product_neon(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size); - -#endif // NN_DOT_PRODUCT_NEON_H diff --git a/include/nn_activation.h b/include/nn_activation.h index 86278ea..1c1fb9b 100644 --- a/include/nn_activation.h +++ b/include/nn_activation.h @@ -1,40 +1,109 @@ -#ifndef NN_ACTIVATION_FUNCTION_H -#define NN_ACTIVATION_FUNCTION_H +#ifndef NN_ACTIVATION_H +#define NN_ACTIVATION_H #include "nn_error.h" +#include "nn_tensor.h" #include #include -#ifndef NN_AF_FORWARD_MAX_SIZE -#define NN_AF_FORWARD_MAX_SIZE 64 -#endif +/** + * @brief Represents a scalar activation function. + * + * @param n The input value. + * + * @return The output value. + */ +typedef NNTensorUnit (*NNActFuncScalar)(NNTensorUnit n); -#ifndef NN_AF_VECTOR_MAX_SIZE -#define NN_AF_VECTOR_MAX_SIZE 64 -#endif +/** + * @brief Represents a tensor activation function. + * + * @param input The input tensor. + * @param output The output tensor. + * @param error The error instance to set if an error occurs. + * + * @return True if the operation was successful, false otherwise. + */ +typedef bool (*NNActFuncTensor)(const NNTensor *input, NNTensor *output, NNError *error); -// NNActFuncScalar represents a scalar activation function. -typedef float (*NNActFuncScalar)(float); +/** + * @brief Represents the type of activation function. + */ +typedef enum { + NN_ACT_FUNC_SCALAR, + NN_ACT_FUNC_TENSOR +} NNActFuncType; -// NNActFuncVector represents a vector activation function. -typedef bool (*NNActFuncVector)(const float input[NN_AF_VECTOR_MAX_SIZE], float output[NN_AF_VECTOR_MAX_SIZE], size_t input_size, NNError *error); +/** + * @brief Represents the activation function. + */ +typedef union { + NNActFuncScalar scalar_func; + NNActFuncTensor tensor_func; +} NNActFunc; -// nn_act_func_forward_scalar computes the given activation function with the given input and stores the result in output. -bool nn_act_func_forward_scalar(NNActFuncScalar act_func, const float input[NN_AF_FORWARD_MAX_SIZE], float output[NN_AF_FORWARD_MAX_SIZE], size_t input_size, NNError *error); +/** + * @brief Returns the identity activation function result. + * + * @param n The input value. + * + * @return The input value. + * + * @note Implemented for testing and theoretical purposes. Not recommended for practical use. + */ +NNTensorUnit nn_act_func_identity(NNTensorUnit n); -// nn_act_func_forward_vector computes the given activation function with the given input and stores the result in output. -bool nn_act_func_forward_vector(NNActFuncVector act_func, const float input[NN_AF_FORWARD_MAX_SIZE], float output[NN_AF_FORWARD_MAX_SIZE], size_t input_size, NNError *error); +/** + * @brief Returns the sigmoid activation function result. + * + * @param n The input value. + * + * @return Sigmoid of the input value. + */ +NNTensorUnit nn_act_func_sigmoid(NNTensorUnit n); -// nn_act_func_identity returns x. -float nn_act_func_identity(float x); +/** + * @brief Returns the ReLU activation function result. + * + * @param n The input value. + * + * @return ReLU of the input value. + */ +NNTensorUnit nn_act_func_relu(NNTensorUnit n); -// nn_act_func_sigmoid returns the sigmoid of x. -float nn_act_func_sigmoid(float x); +/** + * @brief Calculates the softmax of the input tensor and stores the result in the output tensor. + * + * @param input The input tensor. + * @param output The output tensor. + * @param error The error instance to set if an error occurs. + * + * @return True or false. + */ +bool nn_act_func_softmax(const NNTensor *input, NNTensor *output, NNError *error); -// nn_act_func_relu returns the ReLU of x. -float nn_act_func_relu(float x); +/** + * @brief Calculates the scalar activation function result for each element in the input tensor and stores the result in the output tensor. + * + * @param act_func The scalar activation function. + * @param input The input tensor. + * @param output The output tensor. + * @param error The error instance to set if an error occurs. + * + * @return True or false. + */ +bool nn_act_func_scalar_batch(const NNActFuncScalar act_func, const NNTensor *input, NNTensor *output, NNError *error); -// nn_act_func_softmax calculates the softmax of the input and stores the result in the output. -bool nn_act_func_softmax(const float input[NN_AF_VECTOR_MAX_SIZE], float output[NN_AF_VECTOR_MAX_SIZE], size_t input_size, NNError *error); +/** + * @brief Calculates the tensor activation function result for the input tensor and stores the result in the output tensor. + * + * @param act_func The tensor activation function. + * @param input The input tensor. + * @param output The output tensor. + * @param error The error instance to set if an error occurs. + * + * @return True or false. + */ +bool nn_act_func_tensor_batch(const NNActFuncTensor act_func, const NNTensor *input, NNTensor *output, NNError *error); -#endif // NN_ACTIVATION_FUNCTION_H +#endif // NN_ACTIVATION_H diff --git a/include/nn_app.h b/include/nn_app.h index 763441e..073e148 100644 --- a/include/nn_app.h +++ b/include/nn_app.h @@ -1,16 +1,42 @@ #ifndef NN_APP_H #define NN_APP_H -// nn_init_app initializes an application with the given command line arguments. +#include + +/** + * @brief Initializes the running app with the given command line arguments. + * + * @param argc The number of command line arguments. + * @param argv The command line arguments. + * + * @example + * int main(int argc, char *argv[]) { + * nn_init_app(argc, argv); + * return 0; + * } + */ void nn_init_app(int argc, char *argv[]); -// nn_parse_args parses the given command line arguments. +/** + * @brief Parses the given command line arguments. + * + * @param argc The number of command line arguments. + * @param argv The command line arguments. + */ void nn_parse_args(int argc, char *argv[]); -// nn_lookup_flag checks if a specific flag exists. -int nn_lookup_flag(const char *flag); +/** + * @brief Looks up a specific flag. + * + * @param flag The flag to look up. + */ +bool nn_lookup_flag(const char *flag); -// nn_get_flag returns the value of a specific flag. +/** + * @brief Returns the value of a specific flag. + * + * @param flag The flag to get. + */ const char *nn_get_flag(const char *flag); #endif // NN_APP_H diff --git a/include/nn_config.h b/include/nn_config.h index ff24c46..5158744 100644 --- a/include/nn_config.h +++ b/include/nn_config.h @@ -4,40 +4,56 @@ #include "nn_error.h" #include +/** + * @brief Defines whether ARM NEON is available. + * + * @note Available for certain ARM architectures. + */ #if defined(__ARM_NEON) || defined(__ARM_NEON__) #define NN_NEON_AVAILABLE 1 #else #define NN_NEON_AVAILABLE 0 #endif +/** + * @brief Defines whether ARM CMSIS-DSP is available. + * + * @note Available for all ARM architectures. + */ #if defined(__ARM_ARCH) #define NN_CMSIS_DSP_AVAILABLE 1 #else #define NN_CMSIS_DSP_AVAILABLE 0 #endif -// nn_get_debug_level returns the debug level. +/** + * @brief Returns the debug level. + * + * @return The debug level. + */ int nn_get_debug_level(); -// nn_set_debug_level sets the debug level. +/** + * @brief Sets the debug level. + * + * @param level The debug level. + * + * @return True or false. + */ bool nn_set_debug_level(int level); -// nn_neon_available returns whether ARM NEON is available. +/** + * @brief Returns whether ARM NEON is available. + * + * @return True or false. + */ bool nn_neon_available(); -// nn_get_use_neon returns the ARM NEON use flag. -bool nn_get_use_neon(); - -// nn_set_use_neon sets the ARM NEON use flag. -bool nn_set_use_neon(bool flag, NNError *error); - -// nn_cmsis_dsp_available returns whether ARM CMSIS-DSP is available. +/** + * @brief Returns whether ARM CMSIS-DSP is available. + * + * @return True or false. + */ bool nn_cmsis_dsp_available(); -// nn_get_use_cmsis returns the ARM CMSIS-DSP flag. -bool nn_get_use_cmsis(); - -// nn_set_use_cmsis_dsp sets the ARM CMSIS-DSP flag. -bool nn_set_use_cmsis_dsp(bool flag, NNError *error); - #endif // NN_CONFIG_H diff --git a/include/nn_debug.h b/include/nn_debug.h index a9eddff..5556149 100644 --- a/include/nn_debug.h +++ b/include/nn_debug.h @@ -4,7 +4,13 @@ #include "nn_config.h" #include -// NN_DEBUG_PRINT defines a macro for printing debug messages. +/** + * @brief Prints a debug message. + * + * @param level The debug level. + * @param fmt The format string. + * @param ... The arguments. + */ #define NN_DEBUG_PRINT(level, fmt, ...) \ do { \ if (nn_get_debug_level() >= level) \ diff --git a/include/nn_dot_prod.h b/include/nn_dot_prod.h new file mode 100644 index 0000000..5365649 --- /dev/null +++ b/include/nn_dot_prod.h @@ -0,0 +1,29 @@ +#ifndef NN_DOT_PROD_H +#define NN_DOT_PROD_H + +#include "nn_error.h" +#include "nn_tensor.h" + +/** + * @brief Represents a dot product function. + * + * @param a The first tensor. + * @param b The second tensor. + * @param error The error instance to set if an error occurs. + * + * @return The result of the dot product or NAN if an error occurs. + */ +typedef NNTensorUnit (*NNDotProdFunc)(const NNTensor *a, const NNTensor *b, NNError *error); + +/** + * @brief Returns the dot product of two 1-dimensional tensors. + * + * @param a The first tensor. + * @param b The second tensor. + * @param error The error instance to set if an error occurs. + * + * @return The result of the dot product or NAN if an error occurs. + */ +NNTensorUnit nn_dot_prod(const NNTensor *a, const NNTensor *b, NNError *error); + +#endif // NN_DOT_PROD_H diff --git a/include/nn_dot_product.h b/include/nn_dot_product.h deleted file mode 100644 index 0cdcc45..0000000 --- a/include/nn_dot_product.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef NN_DOT_PRODUCT_H -#define NN_DOT_PRODUCT_H - -#include - -// NN_DOT_PROD_MAX_VECTOR_SIZE defines the maximum size of a vector. -#ifndef NN_DOT_PROD_MAX_VECTOR_SIZE -#define NN_DOT_PROD_MAX_VECTOR_SIZE 64 -#endif - -// NNDotProdFunc represents a function that calculates the dot product of two vectors. -typedef float (*NNDotProdFunc)(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size); - -// nn_dot_prod calculates the dot product of two vectors. -float nn_dot_prod(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size); - -#endif // NN_DOT_PRODUCT_H diff --git a/include/nn_error.h b/include/nn_error.h index c8deb38..00c7560 100644 --- a/include/nn_error.h +++ b/include/nn_error.h @@ -3,26 +3,53 @@ #include -// NNErrorCode defines the error codes. +/** + * @brief Represents an error code. + */ typedef enum { - NN_ERROR_NONE = 0, // no error - NN_ERROR_NOT_IMPLEMENTED, // not implemented - NN_ERROR_INVALID_INSTANCE, // invalid instance - NN_ERROR_INVALID_SIZE, // invalid size - NN_ERROR_INVALID_VALUE, // invalid value - NN_ERROR_INVALID_TYPE, // invalid type - NN_ERROR_INVALID_FUNCTION, // invalid function - NN_ERROR_NEON_NOT_AVAILABLE, // NEON instructions not available - NN_ERROR_CMSIS_DSP_NOT_AVAILABLE, // CMSIS-DSP functions not available + NN_ERROR_NONE = 0, // no error + NN_ERROR_INIT, // initialization error + NN_ERROR_INVALID_ARGUMENT, // invalid argument + NN_ERROR_INVALID_FUNCTION, // invalid function + NN_ERROR_INVALID_INSTANCE, // invalid instance + NN_ERROR_INVALID_SIZE, // invalid size + NN_ERROR_INVALID_TYPE, // invalid type + NN_ERROR_INVALID_VALUE, // invalid value + NN_ERROR_MEMORY_ALLOCATION, // memory allocation error + NN_ERROR_NOT_IMPLEMENTED, // not implemented + NN_ERROR_ARM_CMSIS_DSP_NOT_AVAILABLE, // ARM CMSIS-DSP functions not available + NN_ERROR_ARM_NEON_NOT_AVAILABLE, // ARM NEON instructions not available } NNErrorCode; -// NNError represents an error. +/** + * @brief Represents an error. + * + * @param code The error code. + * @param message_size The size of the error message. + * @param message The error message. + */ typedef struct { - NNErrorCode code; // error code - const char *message; // error message + NNErrorCode code; + size_t message_size; + const char *message; } NNError; -// nn_error_set sets the error code and message. +/** + * @brief Sets the error with the given code and message. + * + * @param error The error to set. + * @param code The error code. + * @param message The error message. + */ void nn_error_set(NNError *error, NNErrorCode code, const char *message); +/** + * @brief Sets the error with the given code and formatted message. + * + * @param error The error to set. + * @param code The error code. + * @param format The formatted error message. + */ +void nn_error_setf(NNError *error, NNErrorCode code, const char *format, ...); + #endif // NN_ERROR_H diff --git a/include/nn_layer.h b/include/nn_layer.h index b6e538e..7ddfde4 100644 --- a/include/nn_layer.h +++ b/include/nn_layer.h @@ -2,65 +2,131 @@ #define NN_LAYER_H #include "nn_activation.h" -#include "nn_dot_product.h" +#include "nn_dot_prod.h" #include "nn_error.h" +#include "nn_mat_mul.h" +#include "nn_mat_transpose.h" +#include "nn_tensor.h" #include #include #include -// M_PI is not defined in some compilers. -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +/** + * @brief Represents flags that can be set on a neural network layer. + */ +typedef enum { + NN_LAYER_FLAG_NONE = 0x00, // no flags set + NN_LAYER_FLAG_INIT = 0x01, // initialized + NN_LAYER_FLAG_WEIGHTS_SET = 0x02, // weights set + NN_LAYER_FLAG_BIASES_SET = 0x04, // biases set + NN_LAYER_FLAG_FORWARD_READY = 0x08, // ready for forward pass + NN_LAYER_FLAG_MAT_MUL_FUNC_SET = 0x10, // matrix multiplication function set + NN_LAYER_FLAG_MAT_TRANSPOSE_FUNC_SET = 0x20, // matrix transpose function set + NN_LAYER_FLAG_ACT_FUNC_SET = 0x40, // activation function set + NN_LAYER_FLAG_ACT_FUNC_SCALAR = 0x80, // scalar activation function set + NN_LAYER_FLAG_ACT_FUNC_TENSOR = 0x100 // tensor activation function set +} NNLayerFlags; -// NN_LAYER_MAX_INPUT_SIZE defines the maximum input size a layer can have. -#ifndef NN_LAYER_MAX_INPUT_SIZE -#define NN_LAYER_MAX_INPUT_SIZE 64 -#endif - -// NN_LAYER_MAX_OUTPUT_SIZE defines the maximum output size a layer can have. -#ifndef NN_LAYER_MAX_OUTPUT_SIZE -#define NN_LAYER_MAX_OUTPUT_SIZE 64 -#endif - -// NN_LAYER_MAX_BIASES defines the maximum number of biases a layer can have. -#ifndef NN_LAYER_MAX_BIASES -#define NN_LAYER_MAX_BIASES 64 -#endif - -// NN_LAYER_MAX_BATCH_SIZE defines the maximum batch size a layer can have. -#ifndef NN_LAYER_MAX_BATCH_SIZE -#define NN_LAYER_MAX_BATCH_SIZE 32 -#endif - -// NNLayer represents a single layer in a neural network. +/** + * @brief Represents a neural network layer. + * + * @param flags The flags set on the layer. + * @param input_size The number of inputs to the layer. + * @param output_size The number of outputs from the layer. + * @param mat_mul_func The matrix multiplication function. + * @param mat_transpose_func The matrix transpose function. + * @param act_func The activation function. + * @param weights The weights of the layer. + * @param biases The biases of the layer. + * + * @note Use the `nn_layer_init` function to create and `nn_layer_destroy` to destroy. + */ typedef struct { + NNLayerFlags flags; size_t input_size; size_t output_size; - float weights[NN_LAYER_MAX_OUTPUT_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - float biases[NN_LAYER_MAX_BIASES]; - NNDotProdFunc dot_prod_func; + NNMatMulFunc mat_mul_func; + NNMatTransposeFunc mat_transpose_func; + NNActFunc act_func; + NNTensor *weights; + NNTensor *biases; + } NNLayer; -// nn_layer_init initializes a layer with the given arguments. -bool nn_layer_init(NNLayer *layer, size_t input_size, size_t output_size, NNError *error); +/** + * @brief Initializes a new neural network layer. + * + * @param input_size The number of inputs to the layer. + * @param output_size The number of outputs from the layer. + * @param error The error instance to set if an error occurs. + * + * @return The pointer to the newly created layer instance or NULL if an error occurs. + */ +NNLayer *nn_layer_init(size_t input_size, size_t output_size, NNError *error); + +/** + * @brief Sets the weights for the specified layer. + * + * @param layer The layer instance. + * @param weights The weights to set. + * @param error The error instance to set if an error occurs. + */ +bool nn_layer_set_weights(NNLayer *layer, const NNTensor *weights, NNError *error); -// nn_layer_init_weights_gaussian initializes the weights of the layer with a Gaussian distribution. -bool nn_layer_init_weights_gaussian(NNLayer *layer, float scale, NNError *error); +/** + * @brief Sets the biases for the specified layer. + * + * @param layer The layer instance. + * @param biases The biases to set. + * @param error The error instance to set if an error occurs. + */ +bool nn_layer_set_biases(NNLayer *layer, const NNTensor *biases, NNError *error); -// nn_layer_init_biases_zeros initializes the biases of the layer to zero. -bool nn_layer_init_biases_zeros(NNLayer *layer, NNError *error); +/** + * @brief Sets the matrix multiplication function for the specified layer. + * + * @param layer The layer instance. + * @param mat_mul_func The matrix multiplication function to set. + * @param error The error instance to set if an error occurs. + */ +bool nn_layer_set_mat_mul_func(NNLayer *layer, NNMatMulFunc mat_mul_func, NNError *error); -// nn_layer_set_weights sets the weights of the given layer. -bool nn_layer_set_weights(NNLayer *layer, const float weights[NN_LAYER_MAX_OUTPUT_SIZE][NN_LAYER_MAX_INPUT_SIZE], NNError *error); +/** + * @brief Sets the matrix transpose function for the specified layer. + * + * @param layer The layer instance. + * @param mat_transpose_func The matrix transpose function to set. + * @param error The error instance to set if an error occurs. + */ +bool nn_layer_set_mat_transpose_func(NNLayer *layer, NNMatTransposeFunc mat_transpose_func, NNError *error); -// nn_layer_set_biases sets the biases of the given layer. -bool nn_layer_set_biases(NNLayer *layer, const float biases[NN_LAYER_MAX_BIASES], NNError *error); +/** + * @brief Sets the activation function for the specified layer. + * + * @param layer The layer instance. + * @param act_func_type The type of activation function. + * @param act_func The activation function to set. + * @param error The error instance to set if an error occurs. + */ +bool nn_layer_set_act_func(NNLayer *layer, NNActFuncType act_func_type, NNActFunc act_func, NNError *error); -// nn_layer_set_dot_prod_func sets the dot product function of the given layer. -bool nn_layer_set_dot_prod_func(NNLayer *layer, NNDotProdFunc dot_prod_func, NNError *error); +/** + * @brief Computes the forward pass of the given layer with the given inputs. + * + * @param layer The layer instance. + * @param inputs The inputs to the layer. + * @param outputs The tensor instance to set the outputs to. + * @param error The error instance to set if an error occurs. + * + * @return True or false + */ +bool nn_layer_forward(const NNLayer *layer, const NNTensor *inputs, NNTensor *outputs, NNError *error); -// nn_layer_forward computes the given layer with the given inputs and stores the result in outputs. -bool nn_layer_forward(const NNLayer *layer, const float inputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_INPUT_SIZE], float outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE], size_t batch_size, NNError *error); +/** + * @brief Destroys the specified layer. + * + * @param layer The layer instance to destroy. + */ +void nn_layer_destroy(NNLayer *layer); #endif // NN_LAYER_H diff --git a/include/nn_mat_mul.h b/include/nn_mat_mul.h new file mode 100644 index 0000000..b64a56e --- /dev/null +++ b/include/nn_mat_mul.h @@ -0,0 +1,31 @@ +#ifndef NN_MAT_MUL_H +#define NN_MAT_MUL_H + +#include "nn_error.h" +#include "nn_tensor.h" + +/** + * @brief Represents a matrix multiplication function. + * + * @param a The first tensor. + * @param b The second tensor. + * @param result The tensor instance to store the result. + * @param error The error instance to set if an error occurs. + * + * @return True or false + */ +typedef bool (*NNMatMulFunc)(const NNTensor *a, const NNTensor *b, NNTensor *result, NNError *error); + +/** + * @brief Computes a matrix multiplication of two 2-dimensional tensors. + * + * @param a The first tensor. + * @param b The second tensor. + * @param result The tensor instance to store the result. + * @param error The error instance to set if an error occurs. + * + * @return True or false + */ +bool nn_mat_mul(const NNTensor *a, const NNTensor *b, NNTensor *result, NNError *error); + +#endif // NN_MAT_MUL_H diff --git a/include/nn_mat_transpose.h b/include/nn_mat_transpose.h new file mode 100644 index 0000000..eb38217 --- /dev/null +++ b/include/nn_mat_transpose.h @@ -0,0 +1,29 @@ +#ifndef NN_MAT_TRANSPOSE_H +#define NN_MAT_TRANSPOSE_H + +#include "nn_error.h" +#include "nn_tensor.h" + +/** + * @brief Represents a matrix transpose function. + * + * @param input The tensor to transpose. + * @param output The tensor instance to store the transposed tensor. + * @param error The error instance to set if an error occurs. + * + * @return True or false + */ +typedef bool (*NNMatTransposeFunc)(const NNTensor *input, NNTensor *output, NNError *error); + +/** + * @brief Computes a transpose of a 2-dimensional tensor. + * + * @param input The tensor to transpose. + * @param output The tensor instance to store the transposed tensor. + * @param error The error instance to set if an error occurs. + * + * @return True or false + */ +bool nn_mat_transpose(const NNTensor *input, NNTensor *output, NNError *error); + +#endif // NN_MAT_TRANSPOSE_H diff --git a/include/nn_neuron.h b/include/nn_neuron.h deleted file mode 100644 index bb50669..0000000 --- a/include/nn_neuron.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef NN_NEURON_H -#define NN_NEURON_H - -#include "nn_activation.h" -#include "nn_dot_product.h" -#include "nn_error.h" -#include -#include - -// NN_NEURON_MAX_WEIGHTS defines the maximum number of weights a neuron can have. -#ifndef NN_NEURON_MAX_WEIGHTS -#define NN_NEURON_MAX_WEIGHTS 64 -#endif - -// NNNeuron represents a single neuron in a neural network. -// It is intended for experimentation and prototyping, and not recommended for -// real-world applications since it's not optimized for performance. -typedef struct { - float weights[NN_NEURON_MAX_WEIGHTS]; - size_t input_size; - float bias; - NNDotProdFunc dot_prod_func; - NNActFuncScalar act_func; -} NNNeuron; - -// nn_neuron_init initializes a neuron with the given arguments. -bool nn_neuron_init(NNNeuron *neuron, const float weights[NN_NEURON_MAX_WEIGHTS], size_t input_size, float bias, NNError *error); - -// nn_neuron_set_weights sets the weights of the given neuron. -bool nn_neuron_set_weights(NNNeuron *neuron, const float weights[NN_NEURON_MAX_WEIGHTS], NNError *error); - -// nn_neuron_set_bias sets the bias of the given neuron. -bool nn_neuron_set_bias(NNNeuron *neuron, float bias, NNError *error); - -// nn_neuron_set_dot_prod_func sets the dot product function of the given neuron. -bool nn_neuron_set_dot_prod_func(NNNeuron *neuron, NNDotProdFunc dot_prod_func, NNError *error); - -// nn_neuron_set_act_func sets the activation function of the given neuron. -bool nn_neuron_set_act_func(NNNeuron *neuron, NNActFuncScalar act_func, NNError *error); - -// nn_neuron_compute computes the given neuron and returns the output. -float nn_neuron_compute(const NNNeuron *neuron, const float inputs[NN_NEURON_MAX_WEIGHTS], NNError *error); - -#endif // NN_NEURON_H diff --git a/include/nn_tensor.h b/include/nn_tensor.h new file mode 100644 index 0000000..f4fd328 --- /dev/null +++ b/include/nn_tensor.h @@ -0,0 +1,242 @@ +#ifndef NN_TENSOR_H +#define NN_TENSOR_H + +#include "nn_error.h" +#include +#include +#include +#include +#include + +/** + * @brief Represents the tensor flags. + */ +typedef enum { + NN_TENSOR_FLAG_NONE = 0x00, // no flags set + NN_TENSOR_FLAG_INIT = 0x01, // initialized +} NNTensorFlags; + +/** + * @brief Represents the unit type of a tensor. + * + * @note Different hardware platforms may have different unit types. + * Also, on certain platforms `int` is faster than `float`. + */ +#define NN_TENSOR_DEFINE_UNIT_TYPE(type, name) \ + typedef type name##Unit; + +/** + * @brief Represents a multi dimensional array. + * + * @param flags The flags set on the tensor. + * @param dims The number of dimensions. + * @param sizes The array of sizes for each dimension. + * @param data The array of values in row-major order. + * + * @note Use the `nn_tensor_init` and `nn_tensor_destroy` functions to create and destroy tensors. + */ +#define NN_TENSOR_DEFINE_TYPE(type, name) \ + typedef struct { \ + NNTensorFlags flags; \ + size_t dims; \ + size_t *sizes; \ + name##Unit *data; \ + } name; + +/** + * @brief Returns a new tensor with the specified dimensions, sizes, and values. + * + * @param dims The number of dimensions. + * @param sizes The array of sizes for each dimension. + * @param zero Whether to initialize the data array to zero using calloc. + * @param values The optional values to set (row-major order). + * @param error The error instance to set if an error occurs. + * + * @return The pointer to the newly created tensor instance or NULL if an error occurs. + * + * @note It makes separate memory allocations for, struct, sizes array, and data array. + * If zero is true and values is NULL then it initializes the data array to zero. + * If zero is false and values is NULL then it initializes the data array to an uninitialized state. + */ +#define NN_TENSOR_DEFINE_INIT(type, name) \ + static inline name *nn_tensor_init_##name(size_t dims, const size_t *sizes, bool zero, const type *values, NNError *error) { \ + name *tensor = (name *)malloc(sizeof(name)); \ + if (!tensor) { \ + nn_error_set(error, NN_ERROR_MEMORY_ALLOCATION, "could not allocate memory for the new tensor"); \ + return NULL; \ + } \ + \ + tensor->flags = NN_TENSOR_FLAG_NONE; \ + tensor->dims = dims; \ + tensor->sizes = (size_t *)malloc(dims * sizeof(size_t)); \ + if (!tensor->sizes) { \ + free(tensor); \ + return NULL; \ + } \ + size_t total_elements = 1; \ + for (size_t i = 0; i < dims; i++) { \ + tensor->sizes[i] = sizes[i]; \ + total_elements *= sizes[i]; \ + } \ + \ + if (values) { \ + tensor->data = (type *)malloc(total_elements * sizeof(type)); \ + if (!tensor->data) { \ + free(tensor->sizes); \ + free(tensor); \ + return NULL; \ + } \ + memcpy(tensor->data, values, total_elements * sizeof(type)); \ + } else if (zero) { \ + tensor->data = (type *)calloc(total_elements, sizeof(type)); \ + if (!tensor->data) { \ + free(tensor->sizes); \ + free(tensor); \ + return NULL; \ + } \ + } else { \ + tensor->data = (type *)malloc(total_elements * sizeof(type)); \ + if (!tensor->data) { \ + free(tensor->sizes); \ + free(tensor); \ + return NULL; \ + } \ + } \ + tensor->flags = NN_TENSOR_FLAG_INIT; \ + \ + return tensor; \ + } + +/** + * @brief Destroys the given tensor instance and frees the allocated memory. + * + * @param tensor The tensor instance to destroy. + */ +#define NN_TENSOR_DEFINE_DESTROY(name) \ + static inline void nn_tensor_destroy_##name(name *tensor) { \ + if (tensor) { \ + free(tensor->data); \ + free(tensor->sizes); \ + free(tensor); \ + } \ + } + +/** + * @brief Get dimension values of the given tensor instance. + * + * @param tensor The tensor instance to get values from. + * @param indices The indices specifying the dimension to get. + * @param indices_size The number of indices. + * @param values The tensor instance to set the values to. + * @param error The error instance to set if an error occurs. + * + * @return True or false + * + * @note: If indices is NULL then it gets the entire tensor values. + * Some of the checks are omitted for performance reasons. + */ +#define NN_TENSOR_DEFINE_GET(type, name) \ + static inline bool nn_tensor_get_##name(name *tensor, size_t *indices, size_t indices_size, name *values, NNError *error) { \ + if (tensor == NULL) { \ + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor is NULL"); \ + return false; \ + } else if (values == NULL) { \ + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "values are NULL"); \ + return false; \ + } \ + \ + if (indices == NULL) { \ + size_t total_elements = 1; \ + for (size_t i = 0; i < tensor->dims; i++) { \ + total_elements *= tensor->sizes[i]; \ + } \ + memcpy(values->data, tensor->data, total_elements * sizeof(type)); \ + return true; \ + } \ + \ + size_t block_size = 1; \ + size_t flat_index = 0; \ + size_t stride = 1; \ + for (size_t i = tensor->dims - 1; i != (size_t) - 1; i--) { \ + if (i >= tensor->dims - indices_size) { \ + flat_index += indices[tensor->dims - 1 - i] * stride; \ + } else { \ + block_size *= tensor->sizes[i]; \ + } \ + stride *= tensor->sizes[i]; \ + } \ + memcpy(values->data, &tensor->data[flat_index], block_size * sizeof(type)); \ + \ + return true; \ + } + +/** + * @brief Set dimension values of the given tensor instance. + * + * @param tensor The tensor instance to set values to. + * @param indices The indices specifying the dimension to set. + * @param indices_size The number of indices. + * @param values The tensor instance to set the values from. + * @param error The error instance to set if an error occurs. + * + * @return True or false + * + * @note: If indices is NULL then it sets the entire tensor values. + * Some of the checks are omitted for performance reasons. + */ +#define NN_TENSOR_DEFINE_SET(type, name) \ + static inline bool nn_tensor_set_##name(name *tensor, size_t *indices, size_t indices_size, const name *values, NNError *error) { \ + if (tensor == NULL) { \ + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor is NULL"); \ + return false; \ + } else if (values == NULL) { \ + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "values are NULL"); \ + return false; \ + } \ + \ + if (indices == NULL) { \ + size_t total_elements = 1; \ + for (size_t i = 0; i < tensor->dims; i++) { \ + total_elements *= tensor->sizes[i]; \ + } \ + memcpy(tensor->data, values->data, total_elements * sizeof(type)); \ + return true; \ + } \ + \ + size_t block_size = 1; \ + size_t flat_index = 0; \ + size_t stride = 1; \ + for (size_t i = tensor->dims - 1; i != (size_t) - 1; i--) { \ + if (i >= tensor->dims - indices_size) { \ + flat_index += indices[tensor->dims - 1 - i] * stride; \ + } else { \ + block_size *= tensor->sizes[i]; \ + } \ + stride *= tensor->sizes[i]; \ + } \ + memcpy(&tensor->data[flat_index], values->data, block_size * sizeof(type)); \ + \ + return true; \ + } + +// Define the default tensor type if not defined +#ifndef NN_TENSOR_DEFINED +#define NN_TENSOR_DEFINED +#if defined(__ARM_ARCH) && !defined(__ARM_FP) +NN_TENSOR_DEFINE_UNIT_TYPE(int, NNTensor); +NN_TENSOR_DEFINE_TYPE(int, NNTensor); +NN_TENSOR_DEFINE_INIT(int, NNTensor); +NN_TENSOR_DEFINE_GET(int, NNTensor); +NN_TENSOR_DEFINE_SET(int, NNTensor); +NN_TENSOR_DEFINE_DESTROY(NNTensor); +#else +NN_TENSOR_DEFINE_UNIT_TYPE(float, NNTensor); +NN_TENSOR_DEFINE_TYPE(float, NNTensor); +NN_TENSOR_DEFINE_INIT(float, NNTensor); +NN_TENSOR_DEFINE_GET(float, NNTensor); +NN_TENSOR_DEFINE_SET(float, NNTensor); +NN_TENSOR_DEFINE_DESTROY(NNTensor); +#endif +#endif // NN_TENSOR_DEFINED + +#endif // NN_TENSOR_H diff --git a/include/nn_test.h b/include/nn_test.h index 6055d02..d3dd63d 100644 --- a/include/nn_test.h +++ b/include/nn_test.h @@ -3,7 +3,14 @@ #include -// nn_timespec_diff_ns returns the difference between two timespec structs in nanoseconds. +/** + * @brief Returns the difference between two timespec in nanoseconds. + * + * @param start The start timespec. + * @param end The end timespec. + * + * @return The difference between the two timespec structures in nanoseconds. + */ long long nn_timespec_diff_ns(struct timespec *start, struct timespec *end); #endif // NN_TEST_H diff --git a/scripts/docker/Dockerfile.amd64 b/scripts/docker/Dockerfile.amd64 index 63a1802..68389d6 100644 --- a/scripts/docker/Dockerfile.amd64 +++ b/scripts/docker/Dockerfile.amd64 @@ -4,11 +4,15 @@ # Run: # docker run --rm -it --platform linux/amd64 nntbn:amd64 make test ARCH=generic LDFLAGS="-lm" -FROM ubuntu:latest +# Base +FROM ubuntu:latest as base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ clang \ lld + +# Build +FROM base as build COPY . /nn WORKDIR /nn diff --git a/scripts/docker/Dockerfile.amd64-generic b/scripts/docker/Dockerfile.amd64-generic index c114445..d3c2257 100644 --- a/scripts/docker/Dockerfile.amd64-generic +++ b/scripts/docker/Dockerfile.amd64-generic @@ -2,17 +2,20 @@ # Build: # docker buildx build --platform linux/amd64 -f scripts/docker/Dockerfile.amd64-generic -t nntbn:amd64-generic . --load # Run: -# docker run --rm -it --platform linux/amd64 nntbn:amd64-generic /nn/build/tests/arch/generic/neuron +# docker run --rm -it --platform linux/amd64 nntbn:amd64-generic /nn/build/tests/arch/generic/dot_prod_perf -# Build -FROM ubuntu:latest as build +# Base +FROM ubuntu:latest as base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ clang \ lld + +# Build +FROM base as build COPY . /nn WORKDIR /nn -RUN make build-tests ARCH=generic LDFLAGS="-lm" +RUN make build-artifacts PREFIX=tests/arch/generic LDFLAGS="-lm" # Runtime FROM ubuntu:latest diff --git a/scripts/docker/Dockerfile.arm b/scripts/docker/Dockerfile.arm index d54aef5..bf6713a 100644 --- a/scripts/docker/Dockerfile.arm +++ b/scripts/docker/Dockerfile.arm @@ -2,15 +2,19 @@ # Build: # docker buildx build --platform linux/arm64 -f scripts/docker/Dockerfile.arm -t nntbn:arm . --load # Run: -# docker run --rm -it --platform linux/arm64 nntbn:arm make test ARCH=arm TECH=cmsis-dsp LDFLAGS="-lm" +# docker run --rm -it --platform linux/arm64 nntbn:arm make test ARCH=arm FILTERS=cmsis-dsp LDFLAGS="-lm" -FROM ubuntu:latest +# Base +FROM ubuntu:latest as base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ clang \ lld \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi + +# Build +FROM base as build COPY . /nn WORKDIR /nn diff --git a/scripts/docker/Dockerfile.arm-cmsis-dsp b/scripts/docker/Dockerfile.arm-cmsis-dsp index d30145c..0af6e22 100644 --- a/scripts/docker/Dockerfile.arm-cmsis-dsp +++ b/scripts/docker/Dockerfile.arm-cmsis-dsp @@ -2,10 +2,10 @@ # Build: # docker buildx build --platform linux/arm64 -f scripts/docker/Dockerfile.arm-cmsis-dsp -t nntbn:arm-cmsis-dsp . --load # Run: -# docker run --rm -it --platform linux/arm64 nntbn:arm-cmsis-dsp /nn/build/tests/arch/arm/cmsis-dsp/neuron +# docker run --rm -it --platform linux/arm64 nntbn:arm-cmsis-dsp /nn/build/tests/arch/arm/cmsis-dsp/dot_prod_perf -# Build -FROM ubuntu:latest as build +# Base +FROM ubuntu:latest as base ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -13,9 +13,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lld \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi + +# Build +FROM base as build COPY . /nn WORKDIR /nn -RUN make build-tests ARCH=arm TECH=cmsis-dsp LDFLAGS="-lm" +RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=cmsis-dsp LDFLAGS="-lm" # Runtime FROM ubuntu:latest diff --git a/scripts/docker/Dockerfile.arm-neon b/scripts/docker/Dockerfile.arm-neon index d6449be..39cd7e9 100644 --- a/scripts/docker/Dockerfile.arm-neon +++ b/scripts/docker/Dockerfile.arm-neon @@ -2,10 +2,10 @@ # Build: # docker buildx build --platform linux/arm64 -f scripts/docker/Dockerfile.arm-neon -t nntbn:arm-neon . --load # Run: -# docker run --rm -it --platform linux/arm64 nntbn:arm-neon /nn/build/tests/arch/arm/neon/neuron +# docker run --rm -it --platform linux/arm64 nntbn:arm-neon /nn/build/tests/arch/arm/neon/dot_prod_perf -# Build -FROM ubuntu:latest as build +# Base +FROM ubuntu:latest as base ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -13,9 +13,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lld \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi + +# Build +FROM base as build COPY . /nn WORKDIR /nn -RUN make build-tests ARCH=arm TECH=neon LDFLAGS="-lm" +RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" # Runtime FROM ubuntu:latest diff --git a/scripts/docker/Dockerfile.armv7-neon b/scripts/docker/Dockerfile.armv7-neon index 04da36d..889adfb 100644 --- a/scripts/docker/Dockerfile.armv7-neon +++ b/scripts/docker/Dockerfile.armv7-neon @@ -2,10 +2,10 @@ # Build: # docker buildx build --platform linux/arm/v7 -f scripts/docker/Dockerfile.armv7-neon -t nntbn:armv7-neon . --load # Run: -# docker run --rm -it --platform linux/arm/v7 nntbn:armv7-neon /nn/build/tests/arch/arm/neon/neuron +# docker run --rm -it --platform linux/arm/v7 nntbn:armv7-neon /nn/build/tests/arch/arm/neon/dot_prod_perf -# Build -FROM arm32v7/ubuntu:latest as build +# Base +FROM arm32v7/ubuntu:latest as base ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -13,9 +13,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lld \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi + +# Build +FROM base as build COPY . /nn WORKDIR /nn -RUN make build-tests ARCH=arm TECH=neon LDFLAGS="-lm" CFLAGS="-mfpu=neon-vfpv4" +RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" CFLAGS="-mfpu=neon-vfpv4" # Runtime FROM arm32v7/ubuntu:latest diff --git a/scripts/docker/Dockerfile.armv8-neon b/scripts/docker/Dockerfile.armv8-neon index 17749bb..dc48ce2 100644 --- a/scripts/docker/Dockerfile.armv8-neon +++ b/scripts/docker/Dockerfile.armv8-neon @@ -2,10 +2,10 @@ # Build: # docker buildx build --platform linux/arm/v8 -f scripts/docker/Dockerfile.armv8-neon -t nntbn:armv8-neon . --load # Run: -# docker run --rm -it --platform linux/arm/v8 nntbn:armv8-neon /nn/build/tests/arch/arm/neon/neuron +# docker run --rm -it --platform linux/arm/v8 nntbn:armv8-neon /nn/build/tests/arch/arm/neon/dot_prod_perf -# Build -FROM arm64v8/ubuntu:latest as build +# Base +FROM arm64v8/ubuntu:latest as base ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -13,9 +13,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lld \ gcc-arm-none-eabi \ libnewlib-arm-none-eabi + +# Build +FROM base as build COPY . /nn WORKDIR /nn -RUN make build-tests ARCH=arm TECH=neon LDFLAGS="-lm" +RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" # Runtime FROM arm64v8/ubuntu:latest diff --git a/scripts/shell/build_artifact.sh b/scripts/shell/build_artifact.sh index 98fa23d..fad16b3 100755 --- a/scripts/shell/build_artifact.sh +++ b/scripts/shell/build_artifact.sh @@ -3,8 +3,6 @@ set -euo pipefail IFS=$'\n\t' # Init vars -ARCH="${ARCH-}" -TECH="${TECH-}" ARTIFACT="${ARTIFACT-}" CC="${CC:-clang}" CFLAGS_ARRAY=(-Wall -fdiagnostics-color=always -std=c99) @@ -22,14 +20,8 @@ else LDFLAGS_ARRAY=() fi -# If the ARCH environment variable is not set then -if [ -z "$ARCH" ]; then - echo "invalid ARCH value" - exit 1 -fi - # If the ARTIFACT environment variable is not set then -if [ -z "$ARTIFACT" ] || [ "$ARTIFACT" = "examples/" ] || [ "$ARTIFACT" = "tests/" ]; then +if [ -z "$ARTIFACT" ] ; then echo "invalid ARTIFACT value" exit 1 fi @@ -37,25 +29,19 @@ fi # Ensure that the build directory exists mkdir -p "$(pwd)/build/$(dirname "$ARTIFACT")" -# Compile -CC_PARTS=() -# Convert comma-separated TECH to an array -IFS=',' read -ra TECHS <<< "$TECH" -for tech in "${TECHS[@]:-}"; do - if [ "$tech" = "neon" ]; then - # Arm NEON - CC_PARTS+=(src/arch/arm/neon/*.c) - fi - if [ "$tech" = "cmsis-dsp" ]; then - # Arm CMSIS-DSP - CC_PARTS+=(-Ilib/CMSIS_6/CMSIS/Core/Include -Ilib/CMSIS-DSP/Include lib/CMSIS-DSP/Source/BasicMathFunctions/arm_dot_prod_f32.c src/arch/arm/cmsis-dsp/*.c) - fi -done +# Read source files from includes.txt in the ARTIFACT directory +SRC_FILES=() +while IFS= read -r line; do + SRC_FILES+=("$line") +done < "$(pwd)/$ARTIFACT/include.txt" + +# For debugging +# CFLAGS_ARRAY+=(-E) +# SRC_FILES=() COMPILE_CMD=("$CC" "${CFLAGS_ARRAY[@]}" \ -Iinclude/ \ - "${CC_PARTS[@]:-}" \ - src/*.c \ + "${SRC_FILES[@]:-}" \ "$(pwd)/$ARTIFACT"/main.c \ -o "$(pwd)/build/$ARTIFACT") diff --git a/scripts/shell/run_artifact.sh b/scripts/shell/run_artifact.sh index 9c2d074..c57f349 100755 --- a/scripts/shell/run_artifact.sh +++ b/scripts/shell/run_artifact.sh @@ -7,7 +7,7 @@ ARGS="${ARGS-}" ARTIFACT="${ARTIFACT-}" # If the ARTIFACT environment variable is not set then -if [ -z "$ARTIFACT" ] || [ "$ARTIFACT" = "examples/" ] || [ "$ARTIFACT" = "tests/" ]; then +if [ -z "$ARTIFACT" ] ; then echo "invalid ARTIFACT value" exit 1 fi diff --git a/scripts/test/layer_gen_tc.py b/scripts/test/layer_gen_tc.py new file mode 100644 index 0000000..c17be10 --- /dev/null +++ b/scripts/test/layer_gen_tc.py @@ -0,0 +1,92 @@ +# This script generates test cases for NNLayer. + +import numpy as np + +# Returns the identity activation function result. +def nn_act_func_identity(x): + return x + +# Returns the sigmoid activation function result. +def nn_act_func_sigmoid(x): + return 1 / (1 + np.exp(-x)) + +# Returns the ReLU activation function result. +def nn_act_func_relu(x): + return np.maximum(0, x) + +# 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) + +# Activation function map +act_func_map = { + "identity": "nn_act_func_identity", + "sigmoid": "nn_act_func_sigmoid", + "relu": "nn_act_func_relu", + "softmax": "nn_act_func_softmax" +} + +# Returns a test case by the given parameters. +def generate_test_case(batch_size, inputs_size, output_size, act_func_name): + # Init vars + weights = np.random.uniform(-0.5, 0.5, (output_size, inputs_size)) + biases = np.random.uniform(-0.5, 0.5, output_size) + inputs = np.random.uniform(-2.0, 2.0, (batch_size, inputs_size)) + + # Determine activation function + if act_func_name == "softmax": + act_func_c = f".tensor_func = {act_func_map[act_func_name]}" + act_func_type = "NN_ACT_FUNC_TENSOR" + act_func = nn_act_func_softmax + else: + act_func_c = f".scalar_func = {act_func_map[act_func_name]}" + act_func_type = "NN_ACT_FUNC_SCALAR" + act_func = globals()[f"nn_act_func_{act_func_name}"] + + # Calculate expected outputs + raw_outputs = np.dot(inputs, weights.T) + biases + expected_outputs = act_func(raw_outputs) + + # Generate the partial C code + weights_c = ", ".join(map(str, weights.flatten())) + biases_c = ", ".join(map(str, biases)) + inputs_c = ", ".join(map(str, inputs.flatten())) + expected_outputs_c = ", ".join(map(str, expected_outputs.flatten())) + return f""" + {{ + .batch_size = {batch_size}, + .inputs_size = {inputs_size}, + .output_size = {output_size}, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = {act_func_type}, + .act_func = {{ {act_func_c} }}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){{{output_size}, {inputs_size}}}, false, (const NNTensorUnit[]){{{weights_c}}}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){{{output_size}}}, false, (const NNTensorUnit[]){{{biases_c}}}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){{{batch_size}, {inputs_size}}}, false, (const NNTensorUnit[]){{{inputs_c}}}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){{{batch_size}, {output_size}}}, false, (const NNTensorUnit[]){{{expected_outputs_c}}}, NULL), + .output_tolerance = default_output_tolerance, + }}""" + +# Returns test cases by the given parameters. +def generate_test_cases(batch_sizes, input_sizes, output_sizes, act_functions): + test_cases = [] + for batch_size in batch_sizes: + for inputs_size in input_sizes: + for output_size in output_sizes: + for act_func_name in act_functions: + test_case = generate_test_case(batch_size, inputs_size, output_size, act_func_name) + test_cases.append(test_case) + + return test_cases + +# Generate test cases +np.random.seed(2024) +batch_sizes = [1, 2, 3, 4] +input_sizes = [1, 2, 3, 4] +output_sizes = [1, 2, 3, 4] +act_functions = ["identity", "sigmoid", "relu", "softmax"] +test_cases = generate_test_cases(batch_sizes, input_sizes, output_sizes, act_functions) + +print(f"TestCase test_cases[] = {{{','.join(test_cases)},\n}};") diff --git a/scripts/test/layer_multi_gen_tc.py b/scripts/test/layer_multi_gen_tc.py new file mode 100644 index 0000000..20a7e18 --- /dev/null +++ b/scripts/test/layer_multi_gen_tc.py @@ -0,0 +1,134 @@ +# This script generates test cases for NNLayer. + +import numpy as np + +# Returns the identity activation function result. +def nn_act_func_identity(x): + return x + +# Returns the sigmoid activation function result. +def nn_act_func_sigmoid(x): + return 1 / (1 + np.exp(-x)) + +# Returns the ReLU activation function result. +def nn_act_func_relu(x): + return np.maximum(0, x) + +# 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) + +# Activation function map +act_func_map = { + "identity": "nn_act_func_identity", + "sigmoid": "nn_act_func_sigmoid", + "relu": "nn_act_func_relu", + "softmax": "nn_act_func_softmax" +} + +# Layer represents a layer. +class Layer: + def __init__(self, inputs_size, output_size, layer_idx, layer_type, act_func_name, weights=None, biases=None): + self.layer_idx = layer_idx + self.layer_type = layer_type + self.inputs_size = inputs_size + self.output_size = output_size + self.act_func_name = act_func_name + self.act_func = globals()[f"nn_act_func_{act_func_name}"] + self.weights = weights + self.biases = biases + + def compute_outputs(self, inputs): + if self.weights is None: + return inputs + z = np.dot(inputs, self.weights.T) + if self.biases is not None: + z += self.biases + return self.act_func(z) + +# Returns test cases by the given parameters. +def generate_test_cases(batch_sizes, input_sizes, output_sizes, hidden_layers): + test_cases = [] + for batch_size in batch_sizes: + for inputs_size in input_sizes: + for output_size in output_sizes: + for hidden_layer in hidden_layers: + # Init vars + layers = [] + inputs = np.random.uniform(-1.0, 1.0, (batch_size, inputs_size)) + + # Input layer (no activation function, no weights, no biases) + layer = Layer(inputs_size, inputs_size, 0, 0, "identity") + layers.append(layer) + last_outputs = layer.compute_outputs(inputs) + last_outputs_size = inputs_size + + # Hidden layers (only non-linear activation functions) + for i in range(hidden_layer): + hidden_layer_size = np.random.choice(output_sizes) + weights = np.random.uniform(-0.5, 0.5, (hidden_layer_size, last_outputs_size)) + biases = np.random.uniform(-0.5, 0.5, hidden_layer_size) + layer = Layer(last_outputs_size, hidden_layer_size, i+1, 1, "relu", weights, biases) + layers.append(layer) + last_outputs = layer.compute_outputs(last_outputs) + last_outputs_size = hidden_layer_size + + # Output layer (softmax or sigmoid activation function) + act_func_name = "softmax" if output_size > 1 else "sigmoid" + weights = np.random.uniform(-0.5, 0.5, (output_size, last_outputs_size)) + biases = np.random.uniform(-0.5, 0.5, output_size) + layer = Layer(last_outputs_size, output_size, len(layers), 2, act_func_name, weights, biases) + layers.append(layer) + last_outputs = layer.compute_outputs(last_outputs) + + # Generate the partial C code + expected_outputs_c = ", ".join(map(str, last_outputs.flatten())) + layer_configs_c = [] + for layer in layers: + if layer.act_func_name == "softmax": + act_func_c = f".tensor_func = {act_func_map[layer.act_func_name]}" + act_func_type = "NN_ACT_FUNC_TENSOR" + else: + act_func_c = f".scalar_func = {act_func_map[layer.act_func_name]}" + act_func_type = "NN_ACT_FUNC_SCALAR" + + weights_c = ", ".join(map(str, layer.weights.flatten())) if layer.weights is not None else None + biases_c = ", ".join(map(str, layer.biases.flatten())) if layer.biases is not None else None + inputs_c = ", ".join(map(str, inputs.flatten())) if layer.layer_idx == 0 else None + layer_configs_c.append(f""" + {{ + .layer_idx = {layer.layer_idx}, + .layer_type = {layer.layer_type}, + .inputs_size = {layer.inputs_size}, + .output_size = {layer.output_size}, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = {act_func_type}, + .act_func = {{ {act_func_c} }}, + .weights = {"nn_tensor_init_NNTensor(2, (const size_t[]){" + str(layer.output_size) + ", " + str(layer.inputs_size) + "}, false, (const NNTensorUnit[]){ " + weights_c + "}, NULL)" if weights_c is not None else 'NULL'}, + .biases = {"nn_tensor_init_NNTensor(1, (const size_t[]){" + str(layer.output_size) + "}, false, (const NNTensorUnit[]){ " + biases_c + "}, NULL)" if biases_c is not None else 'NULL'}, + .inputs = {"nn_tensor_init_NNTensor(2, (const size_t[]){" + str(batch_size) + ", " + str(layer.inputs_size) + "}, false, (const NNTensorUnit[]){ " + inputs_c + "}, NULL)" if inputs_c is not None else 'NULL'}, + }},""") + + test_case = f""" + {{ + .batch_size = {batch_size}, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){{{batch_size}, {output_size}}}, false, (const NNTensorUnit[]){{{expected_outputs_c}}}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = {len(layers)}, + .layers = (TestCaseLayer[]){{ {''.join(layer_configs_c)}\n}}, + }}""" + test_cases.append(test_case) + + return test_cases + +# Generate test cases +np.random.seed(2024) +batch_sizes = [1, 2, 3, 4] +input_sizes = [1, 2, 3, 4] +output_sizes = [1, 2, 3, 4] +hidden_layers = [1, 2, 3, 4] +test_cases = generate_test_cases(batch_sizes, input_sizes, output_sizes, hidden_layers) + +print(f"TestCase test_cases[] = {{{','.join(test_cases)},\n}};") diff --git a/src/arch/arm/cmsis-dsp/nn_dot_prod.c b/src/arch/arm/cmsis-dsp/nn_dot_prod.c new file mode 100644 index 0000000..a1baa51 --- /dev/null +++ b/src/arch/arm/cmsis-dsp/nn_dot_prod.c @@ -0,0 +1,28 @@ +#include "arch/arm/cmsis-dsp/nn_dot_prod.h" +#include "arm_math.h" +#include "nn_debug.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include +#include + +NNTensorUnit nn_dot_prod_cmsis_dsp(const NNTensor *a, const NNTensor *b, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with a.dims=%zu b.dims=%zu\n", __func__, a->dims, b->dims); + + if (a == NULL || b == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "a or b is NULL"); + return NAN; + } else if (a->dims != 1 || b->dims != 1 || a->sizes[0] != b->sizes[0]) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 1-dimensional tensors of the same size are allowed"); + return false; + } + + NNTensorUnit result = 0.0f; + + // Calculate the dot product + size_t size = a->sizes[0]; + // TODO: Implement other data types based in the tensor data type + arm_dot_prod_f32(a->data, b->data, size, &result); + + return result; +} diff --git a/src/arch/arm/cmsis-dsp/nn_dot_product.c b/src/arch/arm/cmsis-dsp/nn_dot_product.c deleted file mode 100644 index d2c32e1..0000000 --- a/src/arch/arm/cmsis-dsp/nn_dot_product.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/arm/cmsis-dsp/nn_dot_product.h" -#include "arm_math.h" -#include "nn_debug.h" -#include - -// nn_dot_product_neon calculates the dot product of two vectors. -float nn_dot_product_cmsis(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size) { - NN_DEBUG_PRINT(5, "function %s called with vector_size = %zu\n", __func__, vector_size); - - float result = 0.0f; - - // CMSIS-DSP provides arm_dot_prod_f32 for Cortex-M cores with FPU - arm_dot_prod_f32(a, b, vector_size, &result); - - return result; -} diff --git a/src/arch/arm/neon/nn_dot_prod.c b/src/arch/arm/neon/nn_dot_prod.c new file mode 100644 index 0000000..210fff2 --- /dev/null +++ b/src/arch/arm/neon/nn_dot_prod.c @@ -0,0 +1,41 @@ +#include "arch/arm/neon/nn_dot_prod.h" +#include "nn_debug.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include +#include +#include + +NNTensorUnit nn_dot_prod_neon(const NNTensor *a, const NNTensor *b, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with a.dims=%zu b.dims=%zu\n", __func__, a->dims, b->dims); + + if (a == NULL || b == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "a or b is NULL"); + return NAN; + } else if (a->dims != 1 || b->dims != 1 || a->sizes[0] != b->sizes[0]) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 1-dimensional tensors of the same size are allowed"); + return false; + } + + // TODO: Implement other data types based in the tensor data type + // NEON SIMD registers are 128 bits wide, which can hold 4 float32 values + float32x4_t sumVec = vdupq_n_f32(0.0); + size_t i; + size_t size = a->sizes[0]; + for (i = 0; i + 3 < size; i += 4) { + float32x4_t aVec = vld1q_f32(a->data + i); // load 4 elements from a + float32x4_t bVec = vld1q_f32(b->data + i); // load 4 elements from b + float32x4_t prodVec = vmulq_f32(aVec, bVec); // multiply elements + sumVec = vaddq_f32(sumVec, prodVec); // add to sum + } + + // Reduce the sum vector to a single sum value + NNTensorUnit result = vgetq_lane_f32(sumVec, 0) + vgetq_lane_f32(sumVec, 1) + vgetq_lane_f32(sumVec, 2) + vgetq_lane_f32(sumVec, 3); + + // Handle remaining elements + for (; i < size; i++) { + result += a->data[i] * b->data[i]; + } + + return result; +} diff --git a/src/arch/arm/neon/nn_dot_product.c b/src/arch/arm/neon/nn_dot_product.c deleted file mode 100644 index 29619f7..0000000 --- a/src/arch/arm/neon/nn_dot_product.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "arch/arm/neon/nn_dot_product.h" -#include "nn_debug.h" -#include -#include - -// nn_dot_product_neon calculates the dot product of two vectors. -float nn_dot_product_neon(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size) { - NN_DEBUG_PRINT(5, "function %s called with vector_size = %zu\n", __func__, vector_size); - - // Initialize vector sum to 0 - float32x4_t sumVec = vdupq_n_f32(0.0); - - // Process 4 elements at a time using NEON SIMD instructions - // NEON SIMD registers are 128 bits wide, which can hold 4 float32 values - size_t i; - for (i = 0; i + 3 < vector_size; i += 4) { - float32x4_t aVec = vld1q_f32(a + i); // load 4 elements from a - float32x4_t bVec = vld1q_f32(b + i); // load 4 elements from b - float32x4_t prodVec = vmulq_f32(aVec, bVec); // multiply elements - sumVec = vaddq_f32(sumVec, prodVec); // add to sum - } - - // Reduce the sum vector to a single sum value - float result = vgetq_lane_f32(sumVec, 0) + vgetq_lane_f32(sumVec, 1) + vgetq_lane_f32(sumVec, 2) + vgetq_lane_f32(sumVec, 3); - - // Handle remaining elements - for (; i < vector_size; ++i) { - result += a[i] * b[i]; - } - - return result; -} diff --git a/src/nn_activation.c b/src/nn_activation.c index 92550cb..2cb236b 100644 --- a/src/nn_activation.c +++ b/src/nn_activation.c @@ -1,88 +1,131 @@ #include "nn_activation.h" +#include "nn_debug.h" #include "nn_error.h" +#include "nn_tensor.h" #include #include +#include // TODO: Add tests -// nn_act_func_forward_scalar computes the given activation function with the given input and stores the result in output. -bool nn_act_func_forward_scalar(NNActFuncScalar act_func, const float input[NN_AF_FORWARD_MAX_SIZE], float output[NN_AF_FORWARD_MAX_SIZE], size_t input_size, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (act_func == NULL) { - nn_error_set(error, NN_ERROR_INVALID_FUNCTION, "act_func is NULL"); +NNTensorUnit nn_act_func_identity(NNTensorUnit n) { + NN_DEBUG_PRINT(5, "function %s called with n=%f\n", __func__, n); + + return n; +} + +NNTensorUnit nn_act_func_sigmoid(NNTensorUnit n) { + NN_DEBUG_PRINT(5, "function %s called with n=%f\n", __func__, n); + + // TODO: Implement exp macro for handling different types + return 1 / (1 + expf(-n)); +} + +NNTensorUnit nn_act_func_relu(NNTensorUnit n) { + NN_DEBUG_PRINT(5, "function %s called with n=%f\n", __func__, n); + + return n > 0 ? n : 0; +} + +bool nn_act_func_softmax(const NNTensor *input, NNTensor *output, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with input.dims=%zu output.dims=%zu\n", __func__, input->dims, output->dims); + + if (!(input->flags & NN_TENSOR_FLAG_INIT) || !(input->flags & NN_TENSOR_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor input or output is not initialized"); return false; - } else if (input_size == 0 || input_size > NN_AF_FORWARD_MAX_SIZE) { - nn_error_set(error, NN_ERROR_INVALID_SIZE, "invalid input size"); + } else if (input->dims != 1 || output->dims != 1 || input->sizes[0] != output->sizes[0]) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 1-dimensional tensors of the same size are allowed"); return false; } - for (size_t i = 0; i < input_size; ++i) { - output[i] = act_func(input[i]); + // Find the maximum input value + size_t input_size = input->sizes[0]; + NNTensorUnit max_input = 0; + for (size_t i = 0; i < input_size; i++) { + if (input->data[i] > max_input) { + max_input = input->data[i]; + } } - return true; -} + // Compute exp(input[i] - max_input) to prevent overflow + NNTensorUnit sum = 0; + for (size_t i = 0; i < input_size; i++) { + // TODO: Implement exp macro for handling different types + output->data[i] = expf(input->data[i] - max_input); + sum += output->data[i]; + } -// nn_act_func_forward_vector computes the given activation function with the given input and stores the result in output. -bool nn_act_func_forward_vector(NNActFuncVector act_func, const float input[NN_AF_FORWARD_MAX_SIZE], float output[NN_AF_FORWARD_MAX_SIZE], size_t input_size, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (act_func == NULL) { - nn_error_set(error, NN_ERROR_INVALID_FUNCTION, "act_func is NULL"); - return false; - } else if (input_size == 0 || input_size > NN_AF_FORWARD_MAX_SIZE) { - nn_error_set(error, NN_ERROR_INVALID_SIZE, "invalid input size"); + if (sum == 0) { + nn_error_set(error, NN_ERROR_INVALID_VALUE, "sum is zero"); return false; } - return act_func(input, output, input_size, error); -} + // Normalize to form a probability distribution + for (size_t i = 0; i < input_size; i++) { + output->data[i] /= sum; + } -// nn_act_func_identity returns x. -float nn_act_func_identity(float x) { - return x; + return true; } -// nn_act_func_sigmoid returns the sigmoid of x. -float nn_act_func_sigmoid(float x) { - return 1.0f / (1.0f + expf(-x)); +static void nn_tensor_create_slice(const NNTensor *tensor, const size_t offset, const size_t *sizes, NNTensor *slice) { + slice->flags = NN_TENSOR_FLAG_INIT; + slice->dims = 1; + slice->sizes = (size_t *)sizes; + slice->data = &tensor->data[offset]; } -// nn_act_func_relu returns the ReLU of x. -float nn_act_func_relu(float x) { - return fmaxf(0, x); -} +bool nn_act_func_scalar_batch(const NNActFuncScalar act_func, const NNTensor *input, NNTensor *output, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with input.dims=%zu output.dims=%zu\n", __func__, input->dims, output->dims); -// nn_act_func_softmax calculates the softmax of the input and stores the result in the output. -bool nn_act_func_softmax(const float input[NN_AF_VECTOR_MAX_SIZE], float output[NN_AF_VECTOR_MAX_SIZE], size_t input_size, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (input_size == 0 || input_size > NN_AF_VECTOR_MAX_SIZE) { - nn_error_set(error, NN_ERROR_INVALID_SIZE, "invalid input size"); + if (!(input->flags & NN_TENSOR_FLAG_INIT) || !(output->flags & NN_TENSOR_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor input or output is not initialized"); + return false; + } else if (input->dims != 2 || output->dims != 2 || input->sizes[0] != output->sizes[0]) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 2-dimensional tensors of the same size are allowed"); return false; } - // Find the maximum input value - float max_input = input[0]; - for (size_t i = 1; i < input_size; ++i) { - if (input[i] > max_input) { - max_input = input[i]; + // Apply the activation function to each element in the input tensor + size_t batch_size = input->sizes[0]; + size_t sample_size = input->sizes[1]; + size_t sizes[1] = {sample_size}; + NNTensor input_slice; + for (size_t i = 0; i < batch_size; i++) { + nn_tensor_create_slice(input, i * sample_size, sizes, &input_slice); + for (size_t j = 0; j < sample_size; ++j) { + output->data[i * sample_size + j] = act_func(input_slice.data[j]); } } - // Compute exp(input[i] - max_input) to prevent overflow - float sum = 0.0f; - for (size_t i = 0; i < input_size; ++i) { - output[i] = expf(input[i] - max_input); - sum += output[i]; - } + return true; +} - if (sum == 0.0f) { - nn_error_set(error, NN_ERROR_INVALID_VALUE, "sum is zero"); +bool nn_act_func_tensor_batch(const NNActFuncTensor act_func, const NNTensor *input, NNTensor *output, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with input.dims=%zu output.dims=%zu\n", __func__, input->dims, output->dims); + + if (!(input->flags & NN_TENSOR_FLAG_INIT) || !(output->flags & NN_TENSOR_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor input or output is not initialized"); + return false; + } else if (input->dims != 2 || output->dims != 2 || input->sizes[0] != output->sizes[0] || input->sizes[1] != output->sizes[1]) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 2-dimensional tensors of the same size are allowed"); return false; } - // Normalize to form a probability distribution - for (size_t i = 0; i < input_size; ++i) { - output[i] /= sum; + // Apply the activation function to each sample in the batch + size_t batch_size = input->sizes[0]; + size_t sample_size = input->sizes[1]; + size_t sizes[1] = {sample_size}; + NNTensor input_slice; + NNTensor output_slice; + + for (size_t i = 0; i < batch_size; i++) { + nn_tensor_create_slice(input, i * sample_size, sizes, &input_slice); + nn_tensor_create_slice(output, i * sample_size, sizes, &output_slice); + + if (!act_func(&input_slice, &output_slice, error)) { + return false; + } } return true; diff --git a/src/nn_app.c b/src/nn_app.c index 5ba13fd..40ba7c6 100644 --- a/src/nn_app.c +++ b/src/nn_app.c @@ -10,39 +10,28 @@ static int arg_count = 0; static char **args = NULL; -// nn_init_app initializes an application with the given command line arguments. void nn_init_app(int argc, char *argv[]) { nn_parse_args(argc, argv); if (nn_get_flag("--debug-level")) { nn_set_debug_level(atoi(nn_get_flag("--debug-level"))); } - if (nn_lookup_flag("--neon-enabled")) { - NNError error; - if (!nn_set_use_neon(1, &error)) { - printf("error: %s\n", error.message); - exit(1); - } - } } -// nn_parse_args parses the given command line arguments. void nn_parse_args(int argc, char *argv[]) { arg_count = argc; args = argv; } -// nn_lookup_flag checks if a specific flag exists. -int nn_lookup_flag(const char *flag) { +bool nn_lookup_flag(const char *flag) { for (int i = 1; i < arg_count; i++) { // If the argument starts with the flag and is followed by either '\0' or '=' then if (strncmp(args[i], flag, strlen(flag)) == 0 && (args[i][strlen(flag)] == '\0' || args[i][strlen(flag)] == '=')) { - return 1; + return true; } } - return 0; + return false; } -// nn_get_flag returns the value of a specific flag. const char *nn_get_flag(const char *flag) { size_t flag_len = strlen(flag); for (int i = 1; i < arg_count; i++) { diff --git a/src/nn_config.c b/src/nn_config.c index 00b17d5..14e9997 100644 --- a/src/nn_config.c +++ b/src/nn_config.c @@ -1,86 +1,34 @@ #include "nn_config.h" -#include "nn_error.h" #include -#include // TODO: Add tests -// debug_level holds the debug level. +/** + * @brief debug_level holds the debug level. + */ static int debug_level = 0; -// use_neon holds the flag for using ARM NEON instructions. -static bool use_neon = false; - -// use_cmsis holds the flag for using ARM CMSIS-DSP functions. -static bool use_cmsis = false; - -// neon_available holds whether ARM NEON is available. -#if NN_NEON_AVAILABLE -static bool neon_available = true; -#else -static bool neon_available = false; -#endif - -// cmsis_dsp_available holds whether ARM CMSIS-DSP is available. -#if NN_CMSIS_DSP_AVAILABLE -static bool cmsis_dsp_available = true; -#else -static bool cmsis_dsp_available = false; -#endif - -// nn_get_debug_level returns the debug level. int nn_get_debug_level() { return debug_level; } -// nn_set_debug_level sets the debug level. bool nn_set_debug_level(int level) { debug_level = level; return true; } -// nn_neon_available returns whether ARM NEON is available. bool nn_neon_available() { - return neon_available; -} - -// nn_get_use_neon returns the ARM NEON use flag. -bool nn_get_use_neon() { - return use_neon; -} - -// nn_set_use_neon sets the ARM NEON use flag. -bool nn_set_use_neon(bool flag, NNError *error) { - if (neon_available) { - use_neon = flag; - return true; - } - if (error) { - error->code = NN_ERROR_NEON_NOT_AVAILABLE; - error->message = "ARM NEON not available"; - } +#if NN_NEON_AVAILABLE + return true; +#else return false; +#endif } -// nn_cmsis_dsp_available returns whether ARM CMSIS-DSP is available. bool nn_cmsis_dsp_available() { - return cmsis_dsp_available; -} - -// nn_get_use_cmsis returns the ARM CMSIS-DSP flag. -bool nn_get_use_cmsis() { - return use_cmsis; -} - -// nn_set_use_cmsis_dsp sets the ARM CMSIS-DSP flag. -bool nn_set_use_cmsis_dsp(bool flag, NNError *error) { - if (cmsis_dsp_available) { - use_cmsis = flag; - return true; - } - if (error) { - error->code = NN_ERROR_CMSIS_DSP_NOT_AVAILABLE; - error->message = "ARM CMSIS-DSP not available"; - } +#if NN_CMSIS_DSP_AVAILABLE + return true; +#else return false; +#endif } diff --git a/src/nn_dot_prod.c b/src/nn_dot_prod.c new file mode 100644 index 0000000..97edf11 --- /dev/null +++ b/src/nn_dot_prod.c @@ -0,0 +1,28 @@ +#include "nn_dot_prod.h" +#include "nn_debug.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include +#include + +NNTensorUnit nn_dot_prod(const NNTensor *a, const NNTensor *b, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with a.dims=%zu b.dims=%zu\n", __func__, a->dims, b->dims); + + if (a == NULL || b == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "a or b is NULL"); + return NAN; + } else if (a->dims != 1 || b->dims != 1 || a->sizes[0] != b->sizes[0]) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 1-dimensional tensors of the same size are allowed"); + return false; + } + + NNTensorUnit result = 0; + + // Calculate the dot product + size_t size = a->sizes[0]; + for (size_t i = 0; i < size; i++) { + result += a->data[i] * b->data[i]; + } + + return result; +} diff --git a/src/nn_dot_product.c b/src/nn_dot_product.c deleted file mode 100644 index 9016d4e..0000000 --- a/src/nn_dot_product.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "nn_dot_product.h" -#include "nn_debug.h" -#include - -// nn_dot_product_neon calculates the dot product of two vectors. -float nn_dot_prod(const float a[NN_DOT_PROD_MAX_VECTOR_SIZE], const float b[NN_DOT_PROD_MAX_VECTOR_SIZE], size_t vector_size) { - NN_DEBUG_PRINT(5, "function %s called with vector_size = %zu\n", __func__, vector_size); - - // Initialize vector sum to 0 - float result = 0.0f; - - // Iterate over the elements of the vectors - for (size_t i = 0; i < vector_size; ++i) { - result += a[i] * b[i]; - } - - return result; -} diff --git a/src/nn_error.c b/src/nn_error.c index e851de5..fb29390 100644 --- a/src/nn_error.c +++ b/src/nn_error.c @@ -1,9 +1,48 @@ #include "nn_error.h" +#include +#include +#include +#include + +// TODO: Add tests +// TODO: Optimize theses functions -// nn_error_set sets the error code and message. void nn_error_set(NNError *error, NNErrorCode code, const char *message) { - if (error) { - error->code = code; - error->message = message; + if (!error) { + error = malloc(sizeof(NNError)); + } + + error->code = code; + if (error->message) { + free((void *)error->message); } + error->message_size = strlen(message) + 1; // include the null terminator + error->message = malloc(error->message_size); + if (error->message) { + strncpy((char *)error->message, message, error->message_size); + } +} + +void nn_error_setf(NNError *error, NNErrorCode code, const char *format, ...) { + if (!error) { + error = malloc(sizeof(NNError)); + } + + va_list args; + va_start(args, format); + int size = vsnprintf(NULL, 0, format, args); + va_end(args); + if (size < 0) { + return; + } + char *message = malloc(size + 1); // include the null terminator + if (!message) { + return; + } + va_start(args, format); + vsnprintf(message, size + 1, format, args); + va_end(args); + + nn_error_set(error, code, message); + free(message); } diff --git a/src/nn_layer.c b/src/nn_layer.c index 20a1735..a6e1f0c 100644 --- a/src/nn_layer.c +++ b/src/nn_layer.c @@ -1,131 +1,228 @@ #include "nn_layer.h" +#include "nn_error.h" +#include "nn_mat_mul.h" +#include "nn_mat_transpose.h" +#include "nn_tensor.h" #include #include #include #include #include -// nn_layer_init initializes a layer with the given arguments. -bool nn_layer_init(NNLayer *layer, size_t input_size, size_t output_size, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); +/** + * @brief Checks if the layer is ready for forward pass. + * + * @param layer The layer instance to check. + * + * @return True or false. + */ +static bool nn_layer_check_forward_ready(NNLayer *layer) { if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); return false; + } else if (layer->flags & NN_LAYER_FLAG_FORWARD_READY) { + return true; } - if (input_size == 0) { - nn_error_set(error, NN_ERROR_INVALID_SIZE, "invalid input size"); - return false; + + int required_flags = NN_LAYER_FLAG_INIT; + + if ((layer->flags & required_flags) == required_flags) { + layer->flags |= NN_LAYER_FLAG_FORWARD_READY; + return true; } - if (output_size == 0) { - nn_error_set(error, NN_ERROR_INVALID_SIZE, "invalid output size"); - return false; + + return false; +} + +NNLayer *nn_layer_init(size_t input_size, size_t output_size, NNError *error) { + NNLayer *layer = (NNLayer *)malloc(sizeof(NNLayer)); + if (!layer) { + nn_error_set(error, NN_ERROR_MEMORY_ALLOCATION, "could not allocate memory for the new layer"); + return NULL; } + + // Init the layer + layer->flags = NN_LAYER_FLAG_NONE; layer->input_size = input_size; layer->output_size = output_size; - return true; + // Init the weights + layer->weights = nn_tensor_init_NNTensor(2, (const size_t[]){output_size, input_size}, true, NULL, error); // initialized to 0 + if (!layer->weights) { + nn_layer_destroy(layer); + nn_error_setf(error, NN_ERROR_MEMORY_ALLOCATION, "could create weights tensor: %s", error->message); + return NULL; + } + + // Init the biases + layer->biases = nn_tensor_init_NNTensor(1, (const size_t[]){output_size}, true, NULL, error); // initialized to 0 + if (!layer->biases) { + nn_layer_destroy(layer); + nn_error_setf(error, NN_ERROR_MEMORY_ALLOCATION, "could create biases tensor: %s", error->message); + return NULL; + } + layer->flags = NN_LAYER_FLAG_INIT; + + return layer; } -// nn_layer_init_weights_gaussian initializes the weights of the layer with a Gaussian distribution. -bool nn_layer_init_weights_gaussian(NNLayer *layer, float scale, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); +bool nn_layer_set_weights(NNLayer *layer, const NNTensor *weights, NNError *error) { + if (layer == NULL || !(layer->flags & NN_LAYER_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "layer is not initialized"); + return false; + } else if (weights == NULL || weights->data == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "given weights are NULL"); + return false; + } else if (!nn_tensor_set_NNTensor(layer->weights, NULL, 0, weights, error)) { return false; } - // Initialize weights with Gaussian random values scaled by 'scale' - for (size_t i = 0; i < layer->output_size; ++i) { - for (size_t j = 0; j < layer->input_size; ++j) { - float u1 = (float)rand() / (float)RAND_MAX; - float u2 = (float)rand() / (float)RAND_MAX; - float rand_std_normal = sqrt(-2.0 * log(u1)) * cos(2.0 * M_PI * u2); // Box-Muller transform - layer->weights[i][j] = scale * rand_std_normal; - } - } + // TODO: Check if there is a "better" way to set the dims and sizes + layer->weights->dims = weights->dims; + layer->weights->sizes = weights->sizes; + + layer->flags |= NN_LAYER_FLAG_WEIGHTS_SET; + nn_layer_check_forward_ready(layer); return true; } -// nn_layer_init_biases_zeros initializes the biases of the layer to zero. -bool nn_layer_init_biases_zeros(NNLayer *layer, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); +bool nn_layer_set_biases(NNLayer *layer, const NNTensor *biases, NNError *error) { + if (layer == NULL || !(layer->flags & NN_LAYER_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "layer is not initialized"); + return false; + } else if (biases == NULL || biases->data == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "given biases are NULL"); + return false; + } else if (!nn_tensor_set_NNTensor(layer->biases, NULL, 0, biases, error)) { return false; } - - // Initialize biases to zero - for (size_t i = 0; i < layer->output_size; ++i) { - layer->biases[i] = 0.0; - } + layer->flags |= NN_LAYER_FLAG_BIASES_SET; + nn_layer_check_forward_ready(layer); return true; } -// nn_layer_set_weights sets the weights of the given layer. -bool nn_layer_set_weights(NNLayer *layer, const float weights[NN_LAYER_MAX_OUTPUT_SIZE][NN_LAYER_MAX_INPUT_SIZE], NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); +bool nn_layer_set_mat_mul_func(NNLayer *layer, NNMatMulFunc mat_mul_func, NNError *error) { + if (layer == NULL || !(layer->flags & NN_LAYER_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "layer is not initialized"); + return false; + } else if (mat_mul_func == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "matrix multiplication function is NULL"); return false; } - for (size_t i = 0; i < layer->output_size; ++i) { - for (size_t j = 0; j < layer->input_size; ++j) { - layer->weights[i][j] = weights[i][j]; - } - } + layer->mat_mul_func = mat_mul_func; + layer->flags |= NN_LAYER_FLAG_MAT_MUL_FUNC_SET; + nn_layer_check_forward_ready(layer); return true; } -// nn_layer_set_biases sets the biases of the given layer. -bool nn_layer_set_biases(NNLayer *layer, const float biases[NN_LAYER_MAX_BIASES], NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); +bool nn_layer_set_mat_transpose_func(NNLayer *layer, NNMatTransposeFunc mat_transpose_func, NNError *error) { + if (layer == NULL || !(layer->flags & NN_LAYER_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "layer is not initialized"); + return false; + } else if (mat_transpose_func == NULL) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "matrix transpose function is NULL"); return false; } - for (size_t i = 0; i < layer->output_size; ++i) { - layer->biases[i] = biases[i]; - } + layer->mat_transpose_func = mat_transpose_func; + layer->flags |= NN_LAYER_FLAG_MAT_TRANSPOSE_FUNC_SET; + nn_layer_check_forward_ready(layer); return true; } -// nn_layer_set_dot_prod_func sets the dot product function of the given layer. -bool nn_layer_set_dot_prod_func(NNLayer *layer, NNDotProdFunc dot_prod_func, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); +bool nn_layer_set_act_func(NNLayer *layer, NNActFuncType act_func_type, NNActFunc act_func, NNError *error) { + if (layer == NULL || !(layer->flags & NN_LAYER_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "layer is not initialized"); return false; } - layer->dot_prod_func = dot_prod_func; + layer->act_func = act_func; + layer->flags |= NN_LAYER_FLAG_ACT_FUNC_SET; + if (act_func_type == NN_ACT_FUNC_SCALAR) { + layer->flags |= NN_LAYER_FLAG_ACT_FUNC_SCALAR; + } else if (act_func_type == NN_ACT_FUNC_TENSOR) { + layer->flags |= NN_LAYER_FLAG_ACT_FUNC_TENSOR; + } + nn_layer_check_forward_ready(layer); return true; } -// nn_layer_forward computes the given layer with the given inputs and stores the result in outputs. -bool nn_layer_forward(const NNLayer *layer, const float inputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_INPUT_SIZE], float outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE], size_t batch_size, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (layer == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is NULL"); +bool nn_layer_forward(const NNLayer *layer, const NNTensor *inputs, NNTensor *outputs, NNError *error) { + if (layer == NULL || !(layer->flags & NN_LAYER_FLAG_FORWARD_READY)) { + nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "layer is not ready for forward pass"); return false; - } else if (batch_size == 0) { - nn_error_set(error, NN_ERROR_INVALID_SIZE, "invalid batch size"); - return false; - } else if (layer->dot_prod_func == NULL) { - nn_error_set(error, NN_ERROR_INVALID_FUNCTION, "dot product function is NULL"); + } else if (inputs == NULL || outputs == NULL) { + nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "inputs or outputs are NULL"); return false; } - // Iterate over batch inputs - for (size_t i = 0; i < batch_size; ++i) { - // Iterate over output neurons - for (size_t j = 0; j < layer->output_size; ++j) { - outputs[i][j] = layer->dot_prod_func(inputs[i], layer->weights[j], layer->input_size) + layer->biases[j]; + // Check if matrix multiplication function is set + if (layer->flags & NN_LAYER_FLAG_WEIGHTS_SET) { + if (layer->flags & NN_LAYER_FLAG_MAT_MUL_FUNC_SET) { + // Check if matrix transpose function is set + if (layer->flags & NN_LAYER_FLAG_MAT_TRANSPOSE_FUNC_SET) { + // Transpose weights + NNTensor *weights = nn_tensor_init_NNTensor(layer->weights->dims, layer->weights->sizes, true, NULL, error); + if (!weights) { + return false; + } + if (!nn_mat_transpose(layer->weights, weights, error)) { + return false; + } + // Perform matrix multiplication + if (!layer->mat_mul_func(inputs, weights, outputs, error)) { + return false; + } + } else { + // Perform matrix multiplication + if (!layer->mat_mul_func(inputs, layer->weights, outputs, error)) { + return false; + } + } + } else { + nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "matrix multiplication function is not set"); + return false; + } + } else { + // If weights are not set, just copy the inputs to the outputs + if (!nn_tensor_set_NNTensor(outputs, NULL, 0, inputs, error)) { + return false; + } + } + + // Add biases + if (layer->flags & NN_LAYER_FLAG_BIASES_SET) { + size_t batch_size = outputs->sizes[0]; + size_t sample_size = outputs->sizes[1]; + for (size_t i = 0; i < batch_size; i++) { + for (size_t j = 0; j < sample_size; ++j) { + outputs->data[i * sample_size + j] += layer->biases->data[j]; + } + } + } + + // Apply activation function + if (layer->flags & NN_LAYER_FLAG_ACT_FUNC_SET) { + if (layer->flags & NN_LAYER_FLAG_ACT_FUNC_SCALAR) { + if (!nn_act_func_scalar_batch(layer->act_func.scalar_func, outputs, outputs, error)) { + return false; + } + } else if (layer->flags & NN_LAYER_FLAG_ACT_FUNC_TENSOR) { + if (!nn_act_func_tensor_batch(layer->act_func.tensor_func, outputs, outputs, error)) { + return false; + } } } return true; } + +void nn_layer_destroy(NNLayer *layer) { + if (layer) { + nn_tensor_destroy_NNTensor(layer->weights); + nn_tensor_destroy_NNTensor(layer->biases); + free(layer); + } +} diff --git a/src/nn_mat_mul.c b/src/nn_mat_mul.c new file mode 100644 index 0000000..ce2874b --- /dev/null +++ b/src/nn_mat_mul.c @@ -0,0 +1,34 @@ +#include "nn_mat_mul.h" +#include "nn_debug.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include + +bool nn_mat_mul(const NNTensor *a, const NNTensor *b, NNTensor *result, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with a.dims=%zu b.dims=%zu\n", __func__, a->dims, b->dims); + + if (!(a->flags & NN_TENSOR_FLAG_INIT) || !(b->flags & NN_TENSOR_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor a or b is not initialized"); + return NULL; + } else if (a->dims != 2 || b->dims != 2 || a->sizes[1] != b->sizes[0]) { + nn_error_setf(error, NN_ERROR_INVALID_ARGUMENT, "only 2-dimensional tensors with matching inner dimensions are allowed, a.dims=%zu b.dims=%zu a.sizes[1]=%zu b.sizes[0]=%zu", a->dims, b->dims, a->sizes[1], b->sizes[0]); + return NULL; + } + + size_t m = a->sizes[0]; // number of rows in a + size_t n = a->sizes[1]; // number of columns in a, rows in b (b->sizes[0]) + size_t p = b->sizes[1]; // number of columns in b + + // Perform matrix multiplication + for (size_t i = 0; i < m; i++) { + for (size_t j = 0; j < p; j++) { + NNTensorUnit sum = 0; + for (size_t k = 0; k < n; k++) { + sum += a->data[i * n + k] * b->data[k * p + j]; + } + result->data[i * p + j] = sum; + } + } + + return result; +} diff --git a/src/nn_mat_transpose.c b/src/nn_mat_transpose.c new file mode 100644 index 0000000..abcbe48 --- /dev/null +++ b/src/nn_mat_transpose.c @@ -0,0 +1,48 @@ +#include "nn_mat_transpose.h" +#include "nn_debug.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include + +bool nn_mat_transpose(const NNTensor *input, NNTensor *output, NNError *error) { + NN_DEBUG_PRINT(5, "function %s called with input.dims=%zu output.dims=%zu\n", __func__, input->dims, output->dims); + + if (!(input->flags & NN_TENSOR_FLAG_INIT) || !(output->flags & NN_TENSOR_FLAG_INIT)) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "tensor input or output is not initialized"); + return false; + } else if (input->dims != 2 || output->dims != 2) { + nn_error_set(error, NN_ERROR_INVALID_ARGUMENT, "only 2-dimensional tensors are allowed"); + return false; + } + + // Check if input and output tensors have the same shape + bool inPlace = (input == output); + NNTensorUnit *dataSrc = input->data; + if (inPlace) { + NN_DEBUG_PRINT(5, "function %s using in-place transpose\n", __func__); + + dataSrc = (NNTensorUnit *)malloc(input->sizes[0] * input->sizes[1] * sizeof(NNTensorUnit)); + if (!dataSrc) { + nn_error_set(error, NN_ERROR_MEMORY_ALLOCATION, "could not allocate memory for in-place transpose"); + return false; + } + memcpy(dataSrc, input->data, input->sizes[0] * input->sizes[1] * sizeof(NNTensorUnit)); + } + + // Perform matrix transpose + size_t m = input->sizes[0]; // number of rows in input + size_t n = input->sizes[1]; // number of columns in input + for (size_t i = 0; i < m; i++) { + for (size_t j = 0; j < n; j++) { + output->data[j * m + i] = dataSrc[i * n + j]; + } + } + output->sizes[0] = n; + output->sizes[1] = m; + + if (inPlace) { + free(dataSrc); + } + + return true; +} diff --git a/src/nn_neuron.c b/src/nn_neuron.c deleted file mode 100644 index f9e7755..0000000 --- a/src/nn_neuron.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "nn_neuron.h" -#include "nn_activation.h" -#include "nn_dot_product.h" -#include "nn_error.h" -#include -#include -#include - -// nn_neuron_init initializes a neuron with the given arguments. -bool nn_neuron_init(NNNeuron *neuron, const float weights[NN_NEURON_MAX_WEIGHTS], size_t input_size, float bias, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (neuron == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "neuron is NULL"); - return false; - } else if (weights == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "weights is NULL"); - return false; - } - neuron->input_size = input_size; - for (size_t i = 0; i < neuron->input_size; ++i) { - neuron->weights[i] = weights[i]; - } - neuron->bias = bias; - return true; -} - -// nn_neuron_set_weights sets the weights of the given neuron. -bool nn_neuron_set_weights(NNNeuron *neuron, const float weights[NN_NEURON_MAX_WEIGHTS], NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (neuron == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "neuron is NULL"); - return false; - } - for (size_t i = 0; i < neuron->input_size; ++i) { - neuron->weights[i] = weights[i]; - } - return true; -} - -// nn_neuron_set_bias sets the bias of the given neuron. -bool nn_neuron_set_bias(NNNeuron *neuron, float bias, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (neuron == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "neuron is NULL"); - return false; - } - neuron->bias = bias; - return true; -} - -// nn_neuron_set_dot_prod_func sets the dot product function of the given neuron. -bool nn_neuron_set_dot_prod_func(NNNeuron *neuron, NNDotProdFunc dot_prod_func, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (neuron == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "neuron is NULL"); - return false; - } - neuron->dot_prod_func = dot_prod_func; - return true; -} - -// nn_neuron_set_act_func sets the activation function of the given neuron. -bool nn_neuron_set_act_func(NNNeuron *neuron, NNActFuncScalar act_func, NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (neuron == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "neuron is NULL"); - return false; - } - neuron->act_func = act_func; - return true; -} - -// nn_neuron_compute computes the given neuron and returns the output. -float nn_neuron_compute(const NNNeuron *neuron, const float inputs[NN_NEURON_MAX_WEIGHTS], NNError *error) { - nn_error_set(error, NN_ERROR_NONE, NULL); - if (neuron == NULL) { - nn_error_set(error, NN_ERROR_INVALID_INSTANCE, "neuron is NULL"); - return NAN; - } - - // Initialize the result - float result = 0.0f; - - // Compute the output of the neuron: - // 1. Sum the weighted inputs (dot product) - // 2. Add the bias - // 3. Apply the activation function - - // Compute the dot product - if (neuron->dot_prod_func != NULL) { - // Sum the weighted inputs - result = neuron->dot_prod_func(neuron->weights, inputs, neuron->input_size); - } - // Add the bias - result += neuron->bias; - // Apply the activation function - if (neuron->act_func != NULL) { - result = neuron->act_func(result); - } - return result; -} diff --git a/src/nn_test.c b/src/nn_test.c index 6387c11..a0541ab 100644 --- a/src/nn_test.c +++ b/src/nn_test.c @@ -1,8 +1,8 @@ #define _POSIX_C_SOURCE 199309L + #include "nn_test.h" #include -// nn_timespec_diff_ns returns the difference between two timespec structs in nanoseconds. long long nn_timespec_diff_ns(struct timespec *start, struct timespec *end) { return (end->tv_sec - start->tv_sec) * 1000000000LL + (end->tv_nsec - start->tv_nsec); } diff --git a/tests/arch/arm/cmsis-dsp/dot_prod/include.txt b/tests/arch/arm/cmsis-dsp/dot_prod/include.txt new file mode 100644 index 0000000..eedf3ed --- /dev/null +++ b/tests/arch/arm/cmsis-dsp/dot_prod/include.txt @@ -0,0 +1,8 @@ +src/nn_app.c +src/nn_config.c +src/nn_error.c +src/nn_test.c +src/arch/arm/cmsis-dsp/nn_dot_prod.c +-Ilib/CMSIS_6/CMSIS/Core/Include +-Ilib/CMSIS-DSP/Include +lib/CMSIS-DSP/Source/BasicMathFunctions/arm_dot_prod_f32.c diff --git a/tests/arch/arm/cmsis-dsp/dot_prod/main.c b/tests/arch/arm/cmsis-dsp/dot_prod/main.c new file mode 100644 index 0000000..6ab6f2a --- /dev/null +++ b/tests/arch/arm/cmsis-dsp/dot_prod/main.c @@ -0,0 +1,70 @@ +#include "arch/arm/cmsis-dsp/nn_dot_prod.h" +#include "nn_app.h" +#include "nn_config.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include +#include +#include +#include + +typedef struct { + NNTensor *vec_a; + NNTensor *vec_b; + NNTensorUnit expected_output; + NNTensorUnit output_tolerance; +} TestCase; + +void run_test_cases(TestCase *test_cases, int n_cases, char *info) { + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + const NNTensorUnit output = nn_dot_prod_cmsis_dsp(tc.vec_a, tc.vec_b, &error); + assert(isnan(output) == false); + assert(error.code == NN_ERROR_NONE); + assert(fabs(output - tc.expected_output) < tc.output_tolerance); + printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); + } +} + +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + + const float default_output_tolerance = 0.000001f; + const int test_cases_size = 4; + TestCase test_cases[] = { + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.5f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2f}, NULL), + .expected_output = 0.1f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.6f, -1.1f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2f, 0.5f}, NULL), + .expected_output = -0.43f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){1.5f, 2.0f, -1.0f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4f, 0.4f, -0.2f}, NULL), + .expected_output = 1.6f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.36f, 0.17f, 0.96f, 0.12f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.77f, 0.09f, 0.12f, 0.81f}, NULL), + .expected_output = 0.504899f, + .output_tolerance = default_output_tolerance, + }, + + }; + run_test_cases(test_cases, test_cases_size, "nn_dot_prod_cmsis_dsp"); + + return 0; +} diff --git a/tests/arch/arm/cmsis-dsp/dot_prod_perf/include.txt b/tests/arch/arm/cmsis-dsp/dot_prod_perf/include.txt new file mode 100644 index 0000000..eedf3ed --- /dev/null +++ b/tests/arch/arm/cmsis-dsp/dot_prod_perf/include.txt @@ -0,0 +1,8 @@ +src/nn_app.c +src/nn_config.c +src/nn_error.c +src/nn_test.c +src/arch/arm/cmsis-dsp/nn_dot_prod.c +-Ilib/CMSIS_6/CMSIS/Core/Include +-Ilib/CMSIS-DSP/Include +lib/CMSIS-DSP/Source/BasicMathFunctions/arm_dot_prod_f32.c diff --git a/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c b/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c new file mode 100644 index 0000000..c9f33c9 --- /dev/null +++ b/tests/arch/arm/cmsis-dsp/dot_prod_perf/main.c @@ -0,0 +1,46 @@ +#define _POSIX_C_SOURCE 199309L + +#include "arch/arm/cmsis-dsp/nn_dot_prod.h" +#include "nn_app.h" +#include "nn_config.h" +#include "nn_dot_prod.h" +#include "nn_tensor.h" +#include "nn_test.h" +#include +#include +#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)); + + // Init vars + struct timespec start, end; + long long total_time = 0; + const int batch_size = 1024; + const int n_vectors = 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]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + vec_b[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + } + + // Benchmark + for (int i = 0; i < batch_size; i++) { + clock_gettime(CLOCK_MONOTONIC, &start); + nn_dot_prod_cmsis_dsp(vec_a[i], vec_b[i], NULL); + clock_gettime(CLOCK_MONOTONIC, &end); + total_time += nn_timespec_diff_ns(&start, &end); + } + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_prod_cmsis_dsp\n", total_time / batch_size, total_time / 1000000); + + return 0; +} diff --git a/tests/arch/arm/cmsis-dsp/dot_product_perf/main.c b/tests/arch/arm/cmsis-dsp/dot_product_perf/main.c deleted file mode 100644 index 2181fc1..0000000 --- a/tests/arch/arm/cmsis-dsp/dot_product_perf/main.c +++ /dev/null @@ -1,41 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include "arch/arm/cmsis-dsp/nn_dot_product.h" -#include "nn_app.h" -#include "nn_config.h" -#include "nn_dot_product.h" -#include "nn_test.h" -#include -#include -#include - -int main(int argc, char *argv[]) { - nn_init_app(argc, argv); - srand((unsigned int)time(NULL)); - - if (!nn_cmsis_dsp_available()) { - printf("ARM CMSIS-DSP not available\n"); - } - - // Init vars - const int n_runs = 1000; - const int n_vectors = 100000; - long long total_time = 0; - struct timespec start, end; - float *a = malloc(n_vectors * sizeof(float)); - float *b = malloc(n_vectors * sizeof(float)); - for (int i = 0; i < n_vectors; ++i) { - a[i] = (float)rand() / (float)RAND_MAX; - b[i] = (float)rand() / (float)RAND_MAX; - } - - // Benchmark - for (int i = 0; i < n_runs; ++i) { - clock_gettime(CLOCK_MONOTONIC, &start); - nn_dot_product_cmsis(a, b, n_vectors); - clock_gettime(CLOCK_MONOTONIC, &end); - total_time += nn_timespec_diff_ns(&start, &end); - } - printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_product_cmsis\n", total_time / n_runs, total_time / 1000000); - - return 0; -} diff --git a/tests/arch/arm/cmsis-dsp/neuron/main.c b/tests/arch/arm/cmsis-dsp/neuron/main.c deleted file mode 100644 index 7a32b67..0000000 --- a/tests/arch/arm/cmsis-dsp/neuron/main.c +++ /dev/null @@ -1,140 +0,0 @@ -#include "arch/arm/cmsis-dsp/nn_dot_product.h" -#include "nn_config.h" -#include "nn_neuron.h" -#include -#include -#include -#include - -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 10 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.0001f - -// TestCase defines a single test case. -typedef struct { - float inputs[NN_NEURON_MAX_WEIGHTS]; - float weights[NN_NEURON_MAX_WEIGHTS]; - size_t input_size; - float bias; - NNDotProdFunc dot_prod_func; - float output_tolerance; - float expected_output; -} TestCase; - -// run_test_cases runs the test cases. -void run_test_cases(TestCase *test_cases, int n_cases, char *info, NNDotProdFunc dot_prod_func) { - for (int i = 0; i < n_cases; ++i) { - TestCase tc = test_cases[i]; - NNNeuron neuron; - NNError error; - - nn_neuron_init(&neuron, tc.weights, tc.input_size, tc.bias, &error); - assert(error.code == NN_ERROR_NONE); - nn_neuron_set_dot_prod_func(&neuron, dot_prod_func, &error); - assert(error.code == NN_ERROR_NONE); - nn_neuron_set_act_func(&neuron, nn_act_func_identity, &error); - assert(error.code == NN_ERROR_NONE); - const float output = nn_neuron_compute(&neuron, tc.inputs, &error); - assert(error.code == NN_ERROR_NONE); - assert(isnan(output) == false); - assert(fabs(output - tc.expected_output) < tc.output_tolerance); - printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); - } -} - -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .inputs = {0.5f, 1.2f, -0.8f}, - .weights = {0.2f, 0.3f, -0.1f}, - .input_size = 3, - .bias = 0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 1.04f, - }, - - { - .inputs = {-0.6f, -1.1f, 0.9f}, - .weights = {-0.2f, 0.5f, 0.3f}, - .input_size = 3, - .bias = -0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.66f, - }, - - { - .inputs = {1.5f, 2.0f, -1.0f}, - .weights = {0.4f, 0.4f, -0.2f}, - .input_size = 3, - .bias = 2.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 3.6f, - }, - - { - .inputs = {0.1f, -0.2f, 0.3f}, - .weights = {0.3f, -0.2f, 0.1f}, - .input_size = 3, - .bias = 0.05f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.15f, - }, - - { - .inputs = {-2.5f, 3.0f, -1.5f}, - .weights = {0.5f, -0.5f, 0.75f}, - .input_size = 3, - .bias = 1.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -2.875f, - }, - - { - .inputs = {0.0f, 0.0f, 0.0f}, - .weights = {0.25f, -0.75f, 0.5f}, - .input_size = 3, - .bias = 0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.5f, - }, - - { - .inputs = {1.2f, -1.2f, 0.8f}, - .weights = {0.0f, 0.0f, 0.0f}, - .input_size = 3, - .bias = 0.25f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.25f, - }, - - { - .inputs = {1.0f, -1.0f, 1.0f}, - .weights = {-1.0f, 1.0f, -1.0f}, - .input_size = 3, - .bias = -0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -3.5f, - }, - - { - .inputs = {0.123f, 0.456f, -0.789f}, - .weights = {0.321f, -0.654f, 0.987f}, - .input_size = 3, - .bias = 0.1f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.937484, - }, - - { - .inputs = {0.001f, -0.002f, 0.003f}, - .weights = {0.004f, 0.005f, -0.006f}, - .input_size = 3, - .bias = 0.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.000012f, - }, - }; - run_test_cases(test_cases, N_TEST_CASES, "NNNeuron", nn_dot_product_cmsis); - return 0; -} diff --git a/tests/arch/arm/cmsis-dsp/neuron_perf/main.c b/tests/arch/arm/cmsis-dsp/neuron_perf/main.c deleted file mode 100644 index c074595..0000000 --- a/tests/arch/arm/cmsis-dsp/neuron_perf/main.c +++ /dev/null @@ -1,60 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include "arch/arm/cmsis-dsp/nn_dot_product.h" -#include "nn_activation.h" -#include "nn_app.h" -#include "nn_config.h" -#include "nn_neuron.h" -#include "nn_test.h" -#include -#include -#include - -int main(int argc, char *argv[]) { - nn_init_app(argc, argv); - srand((unsigned int)time(NULL)); - - if (!nn_cmsis_dsp_available()) { - printf("ARM CMSIS-DSP not available\n"); - } - - // Init vars - NNNeuron neuron; - NNError error; - size_t input_size = 3; - float weights[NN_NEURON_MAX_WEIGHTS] = {0.2f, 0.8f, -0.5f}; - float bias = 2.0f; - const int n_runs = 1000; - const int n_inputs = n_runs * input_size; - long long total_time = 0; - struct timespec start, end; - float *inputs = malloc(n_inputs * sizeof(float)); - for (int i = 0; i < n_inputs; ++i) { - inputs[i] = (float)rand() / (float)RAND_MAX; - } - - if (!nn_neuron_init(&neuron, weights, input_size, bias, &error)) { - printf("error: %s\n", error.message); - return 1; - } else if (!nn_neuron_set_act_func(&neuron, nn_act_func_identity, &error)) { - printf("error: %s\n", error.message); - return 1; - } else if (!nn_neuron_set_dot_prod_func(&neuron, nn_dot_product_cmsis, &error)) { - printf("error: %s\n", error.message); - return 1; - } - - // Benchmark - for (int i = 0; i < n_runs; ++i) { - clock_gettime(CLOCK_MONOTONIC, &start); - nn_neuron_compute(&neuron, inputs + i * input_size, &error); - clock_gettime(CLOCK_MONOTONIC, &end); - total_time += nn_timespec_diff_ns(&start, &end); - } - if (error.code != NN_ERROR_NONE) { - printf("error: %s\n", error.message); - return 1; - } - printf("avg_time_ns=%lld total_time_ms=%lld info=nn_neuron_compute\n", total_time / n_runs, total_time / 1000000); - - return 0; -} diff --git a/tests/arch/arm/neon/dot_prod/include.txt b/tests/arch/arm/neon/dot_prod/include.txt new file mode 100644 index 0000000..bf18d98 --- /dev/null +++ b/tests/arch/arm/neon/dot_prod/include.txt @@ -0,0 +1,5 @@ +src/nn_app.c +src/nn_config.c +src/nn_error.c +src/nn_test.c +src/arch/arm/neon/nn_dot_prod.c diff --git a/tests/arch/arm/neon/dot_prod/main.c b/tests/arch/arm/neon/dot_prod/main.c new file mode 100644 index 0000000..bc5f65d --- /dev/null +++ b/tests/arch/arm/neon/dot_prod/main.c @@ -0,0 +1,70 @@ +#include "arch/arm/neon/nn_dot_prod.h" +#include "nn_app.h" +#include "nn_config.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include +#include +#include +#include + +typedef struct { + NNTensor *vec_a; + NNTensor *vec_b; + NNTensorUnit expected_output; + NNTensorUnit output_tolerance; +} TestCase; + +void run_test_cases(TestCase *test_cases, int n_cases, char *info) { + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + const NNTensorUnit output = nn_dot_prod_neon(tc.vec_a, tc.vec_b, &error); + assert(isnan(output) == false); + assert(error.code == NN_ERROR_NONE); + assert(fabs(output - tc.expected_output) < tc.output_tolerance); + printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); + } +} + +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + + const float default_output_tolerance = 0.000001f; + const int test_cases_size = 4; + TestCase test_cases[] = { + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.5f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2f}, NULL), + .expected_output = 0.1f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.6f, -1.1f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2f, 0.5f}, NULL), + .expected_output = -0.43f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){1.5f, 2.0f, -1.0f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4f, 0.4f, -0.2f}, NULL), + .expected_output = 1.6f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.36f, 0.17f, 0.96f, 0.12f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.77f, 0.09f, 0.12f, 0.81f}, NULL), + .expected_output = 0.504899f, + .output_tolerance = default_output_tolerance, + }, + + }; + run_test_cases(test_cases, test_cases_size, "nn_dot_prod_neon"); + + return 0; +} diff --git a/tests/arch/arm/neon/dot_prod_perf/include.txt b/tests/arch/arm/neon/dot_prod_perf/include.txt new file mode 100644 index 0000000..bf18d98 --- /dev/null +++ b/tests/arch/arm/neon/dot_prod_perf/include.txt @@ -0,0 +1,5 @@ +src/nn_app.c +src/nn_config.c +src/nn_error.c +src/nn_test.c +src/arch/arm/neon/nn_dot_prod.c diff --git a/tests/arch/arm/neon/dot_prod_perf/main.c b/tests/arch/arm/neon/dot_prod_perf/main.c new file mode 100644 index 0000000..1b64740 --- /dev/null +++ b/tests/arch/arm/neon/dot_prod_perf/main.c @@ -0,0 +1,46 @@ +#define _POSIX_C_SOURCE 199309L + +#include "arch/arm/neon/nn_dot_prod.h" +#include "nn_app.h" +#include "nn_config.h" +#include "nn_dot_prod.h" +#include "nn_tensor.h" +#include "nn_test.h" +#include +#include +#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)); + + // Init vars + struct timespec start, end; + long long total_time = 0; + const int batch_size = 1024; + const int n_vectors = 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]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + vec_b[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + } + + // Benchmark + for (int i = 0; i < batch_size; i++) { + clock_gettime(CLOCK_MONOTONIC, &start); + nn_dot_prod_neon(vec_a[i], vec_b[i], NULL); + clock_gettime(CLOCK_MONOTONIC, &end); + total_time += nn_timespec_diff_ns(&start, &end); + } + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_prod_neon\n", total_time / batch_size, total_time / 1000000); + + return 0; +} diff --git a/tests/arch/arm/neon/dot_product_perf/main.c b/tests/arch/arm/neon/dot_product_perf/main.c deleted file mode 100644 index 1265895..0000000 --- a/tests/arch/arm/neon/dot_product_perf/main.c +++ /dev/null @@ -1,41 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include "arch/arm/neon/nn_dot_product.h" -#include "nn_app.h" -#include "nn_config.h" -#include "nn_test.h" -#include -#include -#include - -int main(int argc, char *argv[]) { - nn_init_app(argc, argv); - srand((unsigned int)time(NULL)); - - if (!nn_neon_available()) { - printf("ARM NEON not available\n"); - return 1; - } - - // Init vars - const int n_runs = 1000; - const int n_vectors = 100000; - long long total_time = 0; - struct timespec start, end; - float *a = malloc(n_vectors * sizeof(float)); - float *b = malloc(n_vectors * sizeof(float)); - for (int i = 0; i < n_vectors; ++i) { - a[i] = (float)rand() / (float)RAND_MAX; - b[i] = (float)rand() / (float)RAND_MAX; - } - - // Benchmark - for (int i = 0; i < n_runs; ++i) { - clock_gettime(CLOCK_MONOTONIC, &start); - nn_dot_product_neon(a, b, n_vectors); - clock_gettime(CLOCK_MONOTONIC, &end); - total_time += nn_timespec_diff_ns(&start, &end); - } - printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_product_neon\n", total_time / n_runs, total_time / 1000000); - - return 0; -} diff --git a/tests/arch/arm/neon/neuron/main.c b/tests/arch/arm/neon/neuron/main.c deleted file mode 100644 index ac4b880..0000000 --- a/tests/arch/arm/neon/neuron/main.c +++ /dev/null @@ -1,140 +0,0 @@ -#include "arch/arm/neon/nn_dot_product.h" -#include "nn_config.h" -#include "nn_neuron.h" -#include -#include -#include -#include - -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 10 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.0001f - -// TestCase defines a single test case. -typedef struct { - float inputs[NN_NEURON_MAX_WEIGHTS]; - float weights[NN_NEURON_MAX_WEIGHTS]; - size_t input_size; - float bias; - NNDotProdFunc dot_prod_func; - float output_tolerance; - float expected_output; -} TestCase; - -// run_test_cases runs the test cases. -void run_test_cases(TestCase *test_cases, int n_cases, char *info, NNDotProdFunc dot_prod_func) { - for (int i = 0; i < n_cases; ++i) { - TestCase tc = test_cases[i]; - NNNeuron neuron; - NNError error; - - nn_neuron_init(&neuron, tc.weights, tc.input_size, tc.bias, &error); - assert(error.code == NN_ERROR_NONE); - nn_neuron_set_dot_prod_func(&neuron, dot_prod_func, &error); - assert(error.code == NN_ERROR_NONE); - nn_neuron_set_act_func(&neuron, nn_act_func_identity, &error); - assert(error.code == NN_ERROR_NONE); - const float output = nn_neuron_compute(&neuron, tc.inputs, &error); - assert(error.code == NN_ERROR_NONE); - assert(isnan(output) == false); - assert(fabs(output - tc.expected_output) < tc.output_tolerance); - printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); - } -} - -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .inputs = {0.5f, 1.2f, -0.8f}, - .weights = {0.2f, 0.3f, -0.1f}, - .input_size = 3, - .bias = 0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 1.04f, - }, - - { - .inputs = {-0.6f, -1.1f, 0.9f}, - .weights = {-0.2f, 0.5f, 0.3f}, - .input_size = 3, - .bias = -0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.66f, - }, - - { - .inputs = {1.5f, 2.0f, -1.0f}, - .weights = {0.4f, 0.4f, -0.2f}, - .input_size = 3, - .bias = 2.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 3.6f, - }, - - { - .inputs = {0.1f, -0.2f, 0.3f}, - .weights = {0.3f, -0.2f, 0.1f}, - .input_size = 3, - .bias = 0.05f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.15f, - }, - - { - .inputs = {-2.5f, 3.0f, -1.5f}, - .weights = {0.5f, -0.5f, 0.75f}, - .input_size = 3, - .bias = 1.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -2.875f, - }, - - { - .inputs = {0.0f, 0.0f, 0.0f}, - .weights = {0.25f, -0.75f, 0.5f}, - .input_size = 3, - .bias = 0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.5f, - }, - - { - .inputs = {1.2f, -1.2f, 0.8f}, - .weights = {0.0f, 0.0f, 0.0f}, - .input_size = 3, - .bias = 0.25f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.25f, - }, - - { - .inputs = {1.0f, -1.0f, 1.0f}, - .weights = {-1.0f, 1.0f, -1.0f}, - .input_size = 3, - .bias = -0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -3.5f, - }, - - { - .inputs = {0.123f, 0.456f, -0.789f}, - .weights = {0.321f, -0.654f, 0.987f}, - .input_size = 3, - .bias = 0.1f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.937484, - }, - - { - .inputs = {0.001f, -0.002f, 0.003f}, - .weights = {0.004f, 0.005f, -0.006f}, - .input_size = 3, - .bias = 0.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.000012f, - }, - }; - run_test_cases(test_cases, N_TEST_CASES, "NNNeuron", nn_dot_product_neon); - return 0; -} diff --git a/tests/arch/arm/neon/neuron_perf/main.c b/tests/arch/arm/neon/neuron_perf/main.c deleted file mode 100644 index 2d74eb3..0000000 --- a/tests/arch/arm/neon/neuron_perf/main.c +++ /dev/null @@ -1,61 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include "arch/arm/neon/nn_dot_product.h" -#include "nn_activation.h" -#include "nn_app.h" -#include "nn_config.h" -#include "nn_neuron.h" -#include "nn_test.h" -#include -#include -#include - -int main(int argc, char *argv[]) { - nn_init_app(argc, argv); - srand((unsigned int)time(NULL)); - - if (!nn_neon_available()) { - printf("ARM NEON not available\n"); - return 1; - } - - // Init vars - NNNeuron neuron; - NNError error; - size_t input_size = 3; - float weights[NN_NEURON_MAX_WEIGHTS] = {0.2f, 0.8f, -0.5f}; - float bias = 2.0f; - const int n_runs = 1000; - const int n_inputs = n_runs * input_size; - long long total_time = 0; - struct timespec start, end; - float *inputs = malloc(n_inputs * sizeof(float)); - for (int i = 0; i < n_inputs; ++i) { - inputs[i] = (float)rand() / (float)RAND_MAX; - } - - if (!nn_neuron_init(&neuron, weights, input_size, bias, &error)) { - printf("error: %s\n", error.message); - return 1; - } else if (!nn_neuron_set_act_func(&neuron, nn_act_func_identity, &error)) { - printf("error: %s\n", error.message); - return 1; - } else if (!nn_neuron_set_dot_prod_func(&neuron, nn_dot_product_neon, &error)) { - printf("error: %s\n", error.message); - return 1; - } - - // Benchmark - for (int i = 0; i < n_runs; ++i) { - clock_gettime(CLOCK_MONOTONIC, &start); - nn_neuron_compute(&neuron, inputs + i * input_size, &error); - clock_gettime(CLOCK_MONOTONIC, &end); - total_time += nn_timespec_diff_ns(&start, &end); - } - if (error.code != NN_ERROR_NONE) { - printf("error: %s\n", error.message); - return 1; - } - printf("avg_time_ns=%lld total_time_ms=%lld info=nn_neuron_compute\n", total_time / n_runs, total_time / 1000000); - - return 0; -} diff --git a/tests/arch/generic/dot_prod/include.txt b/tests/arch/generic/dot_prod/include.txt new file mode 100644 index 0000000..c1ad746 --- /dev/null +++ b/tests/arch/generic/dot_prod/include.txt @@ -0,0 +1,5 @@ +src/nn_app.c +src/nn_config.c +src/nn_dot_prod.c +src/nn_error.c +src/nn_test.c diff --git a/tests/arch/generic/dot_prod/main.c b/tests/arch/generic/dot_prod/main.c new file mode 100644 index 0000000..9eef7b3 --- /dev/null +++ b/tests/arch/generic/dot_prod/main.c @@ -0,0 +1,70 @@ +#include "nn_app.h" +#include "nn_config.h" +#include "nn_dot_prod.h" +#include "nn_error.h" +#include "nn_tensor.h" +#include +#include +#include +#include + +typedef struct { + NNTensor *vec_a; + NNTensor *vec_b; + NNTensorUnit expected_output; + NNTensorUnit output_tolerance; +} TestCase; + +void run_test_cases(TestCase *test_cases, int n_cases, char *info) { + for (int i = 0; i < n_cases; i++) { + TestCase tc = test_cases[i]; + + NNError error = {0}; + const NNTensorUnit output = nn_dot_prod(tc.vec_a, tc.vec_b, &error); + assert(isnan(output) == false); + assert(error.code == NN_ERROR_NONE); + assert(fabs(output - tc.expected_output) < tc.output_tolerance); + printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); + } +} + +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + + const float default_output_tolerance = 0.000001f; + const int test_cases_size = 4; + TestCase test_cases[] = { + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.5f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2f}, NULL), + .expected_output = 0.1f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.6f, -1.1f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2f, 0.5f}, NULL), + .expected_output = -0.43f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){1.5f, 2.0f, -1.0f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4f, 0.4f, -0.2f}, NULL), + .expected_output = 1.6f, + .output_tolerance = default_output_tolerance, + }, + + { + .vec_a = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.36f, 0.17f, 0.96f, 0.12f}, NULL), + .vec_b = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.77f, 0.09f, 0.12f, 0.81f}, NULL), + .expected_output = 0.504899f, + .output_tolerance = default_output_tolerance, + }, + + }; + run_test_cases(test_cases, test_cases_size, "nn_dot_prod"); + + return 0; +} diff --git a/tests/arch/generic/dot_prod_perf/include.txt b/tests/arch/generic/dot_prod_perf/include.txt new file mode 100644 index 0000000..c1ad746 --- /dev/null +++ b/tests/arch/generic/dot_prod_perf/include.txt @@ -0,0 +1,5 @@ +src/nn_app.c +src/nn_config.c +src/nn_dot_prod.c +src/nn_error.c +src/nn_test.c diff --git a/tests/arch/generic/dot_prod_perf/main.c b/tests/arch/generic/dot_prod_perf/main.c new file mode 100644 index 0000000..7481145 --- /dev/null +++ b/tests/arch/generic/dot_prod_perf/main.c @@ -0,0 +1,45 @@ +#define _POSIX_C_SOURCE 199309L + +#include "nn_app.h" +#include "nn_config.h" +#include "nn_dot_prod.h" +#include "nn_tensor.h" +#include "nn_test.h" +#include +#include +#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)); + + // Init vars + struct timespec start, end; + long long total_time = 0; + const int batch_size = 1024; + const int n_vectors = 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]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + vec_b[i]->data[j] = (NNTensorUnit)rand() / (NNTensorUnit)RAND_MAX; + } + } + + // Benchmark + for (int i = 0; i < batch_size; i++) { + clock_gettime(CLOCK_MONOTONIC, &start); + nn_dot_prod(vec_a[i], vec_b[i], NULL); + clock_gettime(CLOCK_MONOTONIC, &end); + total_time += nn_timespec_diff_ns(&start, &end); + } + printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_prod\n", total_time / batch_size, total_time / 1000000); + + return 0; +} diff --git a/tests/arch/generic/dot_product/main.c b/tests/arch/generic/dot_product/main.c deleted file mode 100644 index 632a4ec..0000000 --- a/tests/arch/generic/dot_product/main.c +++ /dev/null @@ -1,73 +0,0 @@ -#include "nn_config.h" -#include "nn_neuron.h" -#include -#include -#include -#include - -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 4 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.0001f - -// TestCase defines a single test case. -typedef struct { - float a[4]; - float b[4]; - size_t vector_size; - float bias; - NNDotProdFunc dot_prod_func; - float output_tolerance; - float expected_output; -} TestCase; - -// run_test_cases runs the test cases. -void run_test_cases(TestCase *test_cases, int n_cases, char *info, NNDotProdFunc dot_prod_func) { - for (int i = 0; i < n_cases; ++i) { - TestCase tc = test_cases[i]; - - const float output = dot_prod_func(tc.a, tc.b, tc.vector_size); - assert(isnan(output) == false); - assert(fabs(output - tc.expected_output) < tc.output_tolerance); - printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); - } -} - -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .a = {0.5f}, - .b = {0.2f}, - .vector_size = 1, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.1f, - }, - - { - .a = {-0.6f, -1.1f}, - .b = {-0.2f, 0.5f}, - .vector_size = 2, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.43f, - }, - - { - .a = {1.5f, 2.0f, -1.0f}, - .b = {0.4f, 0.4f, -0.2f}, - .vector_size = 3, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 1.6f, - }, - - { - .a = {0.36f, 0.17f, 0.96f, 0.12f}, - .b = {0.77f, 0.09f, 0.12f, 0.81f}, - .vector_size = 4, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.5048, - }, - - }; - run_test_cases(test_cases, N_TEST_CASES, "nn_dot_prod", nn_dot_prod); - return 0; -} diff --git a/tests/arch/generic/dot_product_perf/main.c b/tests/arch/generic/dot_product_perf/main.c deleted file mode 100644 index e8e7eb4..0000000 --- a/tests/arch/generic/dot_product_perf/main.c +++ /dev/null @@ -1,36 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include "nn_app.h" -#include "nn_config.h" -#include "nn_dot_product.h" -#include "nn_test.h" -#include -#include -#include - -int main(int argc, char *argv[]) { - nn_init_app(argc, argv); - srand((unsigned int)time(NULL)); - - // Init vars - const int n_runs = 1000; - const int n_vectors = 100000; - long long total_time = 0; - struct timespec start, end; - float *a = malloc(n_vectors * sizeof(float)); - float *b = malloc(n_vectors * sizeof(float)); - for (int i = 0; i < n_vectors; ++i) { - a[i] = (float)rand() / (float)RAND_MAX; - b[i] = (float)rand() / (float)RAND_MAX; - } - - // Benchmark - for (int i = 0; i < n_runs; ++i) { - clock_gettime(CLOCK_MONOTONIC, &start); - nn_dot_prod(a, b, n_vectors); - clock_gettime(CLOCK_MONOTONIC, &end); - total_time += nn_timespec_diff_ns(&start, &end); - } - printf("avg_time_ns=%lld total_time_ms=%lld info=nn_dot_prod\n", total_time / n_runs, total_time / 1000000); - - return 0; -} diff --git a/tests/arch/generic/layer/include.txt b/tests/arch/generic/layer/include.txt new file mode 100644 index 0000000..c0506a0 --- /dev/null +++ b/tests/arch/generic/layer/include.txt @@ -0,0 +1,8 @@ +src/nn_activation.c +src/nn_app.c +src/nn_config.c +src/nn_mat_mul.c +src/nn_mat_transpose.c +src/nn_error.c +src/nn_layer.c +src/nn_test.c diff --git a/tests/arch/generic/layer/main.c b/tests/arch/generic/layer/main.c index 8464af7..f3d4945 100644 --- a/tests/arch/generic/layer/main.c +++ b/tests/arch/generic/layer/main.c @@ -1,287 +1,3690 @@ #include "nn_activation.h" +#include "nn_app.h" #include "nn_config.h" -#include "nn_dot_product.h" +#include "nn_error.h" #include "nn_layer.h" +#include "nn_mat_mul.h" +#include "nn_mat_transpose.h" +#include "nn_tensor.h" #include #include #include #include -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 9 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.0001f - // TestCase defines a single test case. typedef struct { - size_t input_size; - size_t output_size; - float weights[NN_LAYER_MAX_OUTPUT_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - float biases[NN_LAYER_MAX_BIASES]; - NNDotProdFunc dot_prod_func; - NNActFuncScalar act_func_scalar; - NNActFuncVector act_func_vector; size_t batch_size; - float inputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - float output_tolerance; - float expected_outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE]; + size_t inputs_size; + size_t output_size; + NNMatMulFunc mat_mul_func; + NNMatTransposeFunc mat_transpose_func; + NNActFuncType act_func_type; + NNActFunc act_func; + NNTensor *weights; + NNTensor *biases; + NNTensor *inputs; + NNTensor *expected_outputs; + NNTensorUnit output_tolerance; } TestCase; // run_test_cases runs the test cases. void run_test_cases(TestCase *test_cases, int n_cases, char *info) { - for (int i = 0; i < n_cases; ++i) { + for (int i = 0; i < n_cases; i++) { TestCase tc = test_cases[i]; - NNLayer layer; - NNError error; + NNError error = {0}; + + // Init the layer + NNLayer *layer = nn_layer_init(tc.inputs_size, tc.output_size, &error); + assert(layer != NULL); + assert(error.code == NN_ERROR_NONE); + + // Set weights + const bool sw = nn_layer_set_weights(layer, tc.weights, &error); + assert(sw == true); + assert(error.code == NN_ERROR_NONE); - nn_layer_init(&layer, tc.input_size, tc.output_size, &error); + // Set biases + const bool sb = nn_layer_set_biases(layer, tc.biases, &error); + assert(sb == true); assert(error.code == NN_ERROR_NONE); - nn_layer_set_dot_prod_func(&layer, tc.dot_prod_func, &error); + + // Set matrix multiplication function + const bool smf = nn_layer_set_mat_mul_func(layer, tc.mat_mul_func, &error); + assert(smf == true); assert(error.code == NN_ERROR_NONE); - nn_layer_set_weights(&layer, tc.weights, &error); + + // Set matrix transpose function + if (tc.mat_transpose_func) { + const bool stf = nn_layer_set_mat_transpose_func(layer, tc.mat_transpose_func, &error); + assert(stf == true); + assert(error.code == NN_ERROR_NONE); + } + + // Set activation function + const bool saf = nn_layer_set_act_func(layer, tc.act_func_type, tc.act_func, &error); + assert(saf == true); assert(error.code == NN_ERROR_NONE); - nn_layer_set_biases(&layer, tc.biases, &error); + + // Init outputs tensor + NNTensor *outputs = nn_tensor_init_NNTensor(2, (const size_t[]){tc.batch_size, tc.output_size}, true, NULL, &error); + assert(outputs != NULL); assert(error.code == NN_ERROR_NONE); - float outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE]; - const bool lfr = nn_layer_forward(&layer, tc.inputs, outputs, tc.batch_size, &error); + + // Compute + const bool lfr = nn_layer_forward(layer, tc.inputs, outputs, &error); assert(lfr == true); assert(error.code == NN_ERROR_NONE); - for (size_t i = 0; i < tc.batch_size; ++i) { - if (tc.act_func_scalar != NULL) { - const bool laf = nn_act_func_forward_scalar(tc.act_func_scalar, outputs[i], outputs[i], tc.output_size, &error); - assert(laf == true); - assert(error.code == NN_ERROR_NONE); - } else if (tc.act_func_vector != NULL) { - const bool laf = nn_act_func_forward_vector(tc.act_func_vector, outputs[i], outputs[i], tc.output_size, &error); - assert(laf == true); - assert(error.code == NN_ERROR_NONE); - } - } - for (size_t i = 0; i < tc.batch_size; ++i) { - for (size_t j = 0; j < tc.output_size; ++j) { - assert(fabs(outputs[i][j] - tc.expected_outputs[i][j]) <= tc.output_tolerance); + + // Check outputs + for (int k = 0; k < tc.batch_size; k++) { + for (int l = 0; l < tc.output_size; l++) { + // printf("expected=%f, got=%f\n", tc.expected_outputs->data[k * tc.output_size + l], outputs->data[k * tc.output_size + l]); + assert(fabs(outputs->data[k * tc.output_size + l] - tc.expected_outputs->data[k * tc.output_size + l]) < tc.output_tolerance); } } printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); + + // Cleanup + nn_layer_destroy(layer); } } -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.1f, 0.2f, -0.1f, 0.5f}, - {0.3f, -0.2f, 0.4f, 0.1f}, - {-0.3f, 0.4f, 0.2f, -0.5f}, - }, - .biases = {0.5f, -0.1f, 0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_identity, - .batch_size = 2, - .inputs = { - {1.5f, -2.0f, 1.0f, -1.5f}, - {-1.0f, 2.0f, -0.5f, 1.0f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {-0.6f, 1.0f, -0.1f}, - {1.35f, -0.9f, 0.7f}, - }, - }, +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + const int n_test_cases = 256; + const float default_output_tolerance = 0.000001f; + + // Use scripts/test/layer_gen_tc.py to generate test cases + TestCase test_cases[] = { { - .input_size = 4, - .output_size = 3, - .weights = { - {0.1f, 0.2f, -0.1f, 0.5f}, - {0.3f, -0.2f, 0.4f, 0.1f}, - {-0.3f, 0.4f, 0.2f, -0.5f}, - }, - .biases = {0.5f, -0.1f, 0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_relu, - .batch_size = 2, - .inputs = { - {1.5f, -2.0f, 1.0f, -1.5f}, - {-1.0f, 2.0f, -0.5f, 1.0f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {0.0f, 1.0f, 0.0f}, - {1.35f, 0.0f, 0.7f}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.08801451889539791}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.1991087476815825}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-1.247392159845976}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.08932012685884762}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.1f, 0.2f, -0.1f, 0.5f}, - {0.3f, -0.2f, 0.4f, 0.1f}, - {-0.3f, 0.4f, 0.2f, -0.5f}, - }, - .biases = {0.5f, -0.1f, 0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_vector = nn_act_func_softmax, - .batch_size = 2, - .inputs = { - {1.5f, -2.0f, 1.0f, -1.5f}, - {-1.0f, 2.0f, -0.5f, 1.0f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {0.13154859, 0.65156444, 0.21688696}, - {0.61446009, 0.06476362, 0.32077629}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.4561914362531352}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2949810476057112}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-1.575748502094937}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.6044070042139293}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {-0.5f, 0.8f, -0.2f, 0.4f}, - {0.2f, -0.3f, 0.5f, -0.1f}, - {0.4f, 0.1f, -0.4f, 0.6f}, - }, - .biases = {1.0f, 0.5f, -0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_identity, - .batch_size = 2, - .inputs = { - {0.5f, 0.1f, -0.2f, 0.4f}, - {1.2f, -1.2f, 0.5f, -0.3f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {1.03f, 0.43f, 0.33f}, - {-0.78f, 1.38f, -0.22f}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.22724014368445478}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.17940052352514158}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.10461718636712591}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.1556272990632125}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {-0.5f, 0.8f, -0.2f, 0.4f}, - {0.2f, -0.3f, 0.5f, -0.1f}, - {0.4f, 0.1f, -0.4f, 0.6f}, - }, - .biases = {1.0f, 0.5f, -0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_relu, - .batch_size = 2, - .inputs = { - {0.5f, 0.1f, -0.2f, 0.4f}, - {1.2f, -1.2f, 0.5f, -0.3f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {1.03f, 0.43f, 0.33f}, - {0.0f, 1.38f, 0.0f}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.05170417551969542}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.48089305212753397}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.010393348834317}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.0}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {-0.5f, 0.8f, -0.2f, 0.4f}, - {0.2f, -0.3f, 0.5f, -0.1f}, - {0.4f, 0.1f, -0.4f, 0.6f}, - }, - .biases = {1.0f, 0.5f, -0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_vector = nn_act_func_softmax, - .batch_size = 2, - .inputs = { - {0.5f, 0.1f, -0.2f, 0.4f}, - {1.2f, -1.2f, 0.5f, -0.3f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {0.48890266, 0.26831547, 0.24278187}, - {0.0875518, 0.75917368, 0.15327452}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.10244853900812656, 0.46177757530818964}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.1643686473564756, 0.10662961931867632}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.2033947402731342}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.14353115337355565, 0.01270648932490942}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.6f, -0.1f, 0.2f, 0.3f}, - {-0.4f, 0.2f, -0.5f, 0.1f}, - {0.1f, 0.4f, 0.2f, -0.2f}, - }, - .biases = {0.2f, -0.3f, 0.4f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_identity, - .batch_size = 3, - .inputs = { - {2.0f, -1.5f, 0.5f, 0.6f}, - {-1.2f, 1.3f, -0.4f, 0.5f}, - {0.5f, 0.6f, -1.0f, 0.2f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {1.83f, -1.59f, -0.02f}, - {-0.58f, 0.69f, 0.62f}, - {0.3f, 0.14f, 0.45f}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2746458368073045, 0.1701742968926956}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.23576659245191334, -0.2420043619218064}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-1.6178313845585381}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.6637604015541327, 0.37347966335822874}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.6f, -0.1f, 0.2f, 0.3f}, - {-0.4f, 0.2f, -0.5f, 0.1f}, - {0.1f, 0.4f, 0.2f, -0.2f}, - }, - .biases = {0.2f, -0.3f, 0.4f}, - .dot_prod_func = nn_dot_prod, - .act_func_vector = nn_act_func_softmax, - .batch_size = 3, - .inputs = { - {2.0f, -1.5f, 0.5f, 0.6f}, - {-1.2f, 1.3f, -0.4f, 0.5f}, - {0.5f, 0.6f, -1.0f, 0.2f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {0.84037173, 0.02749061, 0.13213767}, - {0.12688794, 0.45182925, 0.4212828}, - {0.33178742, 0.28273059, 0.38548199}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4609097422366777, -0.24823271323198892}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2178348805563568, 0.26825393466278513}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.1916935884599336}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.3314283041258126, 0.0}, NULL), + .output_tolerance = default_output_tolerance, }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.6f, -0.1f, 0.2f, 0.3f}, - {-0.4f, 0.2f, -0.5f, 0.1f}, - {0.1f, 0.4f, 0.2f, -0.2f}, - }, - .biases = {0.2f, -0.3f, 0.4f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_relu, - .batch_size = 3, - .inputs = { - {2.0f, -1.5f, 0.5f, 0.6f}, - {-1.2f, 1.3f, -0.4f, 0.5f}, - {0.5f, 0.6f, -1.0f, 0.2f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {1.83f, 0.0f, 0.0f}, - {0.0f, 0.69f, 0.62f}, - {0.3f, 0.14f, 0.45f}, - }, + .batch_size = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.04403719840041609, -0.11729236935335807}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.11834904979800276, -0.21417261152281708}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.9610726125626292}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.562391362021427, 0.43760863797857297}, NULL), + .output_tolerance = default_output_tolerance, }, - }; + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.26101316756427095, -0.06227829535013629, 0.38353870277658575}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.21071885966728232, 0.28450685708742096, 0.2589536567735904}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.32885846026226595}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.12488247127391935, 0.3049876014040254, 0.13282370952749553}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.274231232403917, -0.07990186106940145, -0.43563630911872864}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.0964326869209966, 0.3373237223108303, 0.3924863863290551}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-1.1978902244670926}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.6046627339755668, 0.6065987331507472, 0.7138855730128303}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.0023952343652897667, 0.39538184446127533, -0.24407906861172934}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.36723234296629026, -0.4835120651833691, 0.05249695437105939}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.11162154594376039}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.36749970272904153, 0.0, 0.025252471400105}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.42335038687001847, -0.2540515564737893, -0.43598162384121486}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.40210470458619796, 0.3740398003743294, -0.3363327094471328}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.9989652267455837}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.7480590094305726, 0.18778806835876222, 0.0641529222106652}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.1531960296532764, -0.1871218406558416, 0.347104020990443, 0.38023110263249615}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.17655865154664596, -0.4463248457283463, 0.059213773519614876, 0.1945129418277548}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.2967892106618497}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.022104306823955644, -0.6889824297700275, 0.5093345229173656, 0.6875925332796342}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.18857134113802954, 0.0052305408491463146, 0.3490037878830786, -0.20648436730242037}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.17711955065481155, -0.07909359780279657, 0.18171271362934172, -0.27877201051351197}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.19599079373146822}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.5349830739359893, 0.48049279152955304, 0.5622046197898823, 0.4208607219927736}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.3488467194750853, 0.2365669013092747, -0.0003774137190417637, -0.12033500693673649}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2875208106001731, -0.3311306924350146, 0.0863586139898459, -0.06878932928413273}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-1.752359259216722}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.0, 0.0, 0.08701997841496416, 0.14208083432936594}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.21054522530589515, 0.23414539834613501, -0.21134454505552536, -0.10960188586949926}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.13561732371232704, 0.33114885673920824, -0.1805789994267164, -0.34077521237535535}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.8466568637868237}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2394225739948768, 0.42422415565318045, 0.17440095895137236, 0.1619523114005703}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.3727086430908736, 0.09315636542505157}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.1947128788862139}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-1.307066718826789, 0.1269303692187349}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.28061781245848183}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.37095862065672913, 0.34109026805366327}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4720555400219495}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){1.129028838853439, -1.2118779745105188}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.617161789851582}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.11062606560895016, -0.02114449408827901}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.11663699608232281}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-1.4402670268333813, -0.3550567351219214}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.2776303394377082, 0.43972551960895245}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3954205918165643}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){1.7539287892385174, 1.1895486868371492}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.16919728132700362, -0.1882142494911464, -0.20984618000594024, -0.3261104093035674}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3811495560306797, 0.32005648720313784}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.9466355104108355, 1.3878729220093184}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.04023605914350237, -0.33119116517234637}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.10911562376633555, -0.15576699437209196, -0.2703310085569506, 0.44462578845283707}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2082742890575373, -0.0899554140192873}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.6493428985827201, 1.797314382473068}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.36375804141969736, 0.7077982135888166}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.2690710674250778, -0.33052796092697356, -0.00910236758463745, 0.40475344775132394}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3839996873001077, -0.3050884072248202}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.08087186633845045, -1.3004027043996294}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.792058862168894, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3995458788323055, -0.12180066579335713, 0.20288128308999764, 0.011745452093031683}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.13485106131081048, 0.4339949409407413}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-1.1580391102265888, -0.6551839694821271}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.39188587744859876, 0.6081141225514013}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.15946718212300937, -0.08539663715100776, -0.24468655991286703, 0.375602249302185, -0.09820869079535499, 0.06136792889177389}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.32831690256441426, -0.4912220648260507, -0.09121128416186652}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-1.5861244593284551, 0.1001873040496215}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.5898073594409681, -0.06548815052675505, 0.07070820977804707}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.04013902978854178, -0.08847579381675741, 0.2579761599060061, -0.48221657243706784, 0.11286757765848654, 0.15114242636134823}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.22206680116695998, 0.07358543821308705, 0.49685710686469453}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4402062043242032, 0.009449421849701878}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.5507153222536395, 0.5455214668880203, 0.633664562441054}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.14617566472927856, -0.356605767477174, 0.26336742228333043, 0.3665747519208514, -0.0331849036305526, 0.44208678482162345}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.19419746450443587, 0.221186357455198, 0.10348358079419628}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){1.5043924812888068, 1.5258351982185698}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.0, 1.1767269866137298, 0.7281120382282114}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.413824916860111, -0.4588230950889738, 0.3007797288750268, 0.4911918671375408, -0.3735972375742086, -0.35697408634804717}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4331686153644586, -0.1594725287441343, 0.29631638750032163}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.26594198568957816, 0.9647051634585742}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.16539494912969574, 0.5276605657580989, 0.30694448511220535}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.24276572368975957, 0.10957542847800861, 0.43943928412379873, 0.23966715801340654, -0.1353681997441144, -0.15128272431063716, -0.36646910456201365, 0.3434558264524068}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.07237968602353728, 0.2814583605977611, -0.31027546301457765, -0.4962320179911416}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){1.521042711144318, 1.5218562716508117}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.27487866750943923, 1.3146032482361711, -0.7464068393406549, -0.5309567748231694}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.08212736560627454, -0.3998709158466325, 0.012248208883173906, -0.011391129068417105, -0.009422638288266172, 0.254958476683133, 0.42300343926874573, -0.16695592228169842}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.11641615854086562, 0.4964066783874884, 0.2844932456463556, 0.3667834717623596}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){1.786022313160232, -0.25607233553052255}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.5903695646057233, 0.6274281379475714, 0.5504221234997813, 0.7622454623417562}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.40410367305207506, 0.25032907365706436, 0.3038151769616758, -0.16232113105946377, -0.3400208733010627, 0.36488287469157965, -0.20786410872525685, -0.34775239022227833}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3888791283998829, -0.2960177019309589, 0.21134431832017253, 0.4338274409109468}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-1.8389836307419203, -0.6851235828943874}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.182754559619007, 0.0, 0.5866472759859004, 1.0543394978246274}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3725961589973664, -0.0655272848886409, 0.2127224975547477, -0.010179359962674162, -0.19201437592339765, 0.20949757553739168, 0.10274784532378267, -0.048272700625361376}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.09671520603376171, -0.04329517041002984, 0.11051767951781355, 0.05620126774051626}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){1.7688925670361368, 0.992563410931715}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3153816549182553, 0.264896858688669, 0.1877780403620437, 0.23194344603103198}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3644826938312581, -0.3099223017380015, -0.4721022597175788}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4009907104470427}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){1.3708321834966117, -0.5862812996068065, -0.08824713780185389}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.32201721959434004}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.007215725147337149, -0.32496501073422945, 0.16929804612891974}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.18443664918573155}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.6611498144735188, -1.0127183105811115, 1.6538520917226194}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.6057365871698931}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.24276182727940643, -0.12498243265631892, -0.09826376158077677}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.27950192251264283}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.7091636843442699, -0.24669767169333534, 1.7345344780815708}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.11199589955884592, -0.2095740788057301, -0.21988173967465474}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.16021449883005734}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-1.5522452245784915, -1.3454086768871347, -0.7938129662193565}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.208500226482341, -0.47644164788457355, -0.3809399424670077, 0.20640646224539738, -0.2612162357119583, -0.12132692707995107}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3202406067306497, -0.23591933558275602}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4559180329207715, -1.4573521867382158, 1.0898440833746323}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.13612148487301282, 0.10664171136053852}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.3899367920091773, 0.162935961562217, 0.20020134434967773, 0.013702484908657553, -0.21896410225586405, -0.08479425899214144}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.41848506530181706, 0.11766889244837753}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){1.4561869764133513, -1.8454473436554482, 1.0135850171831544}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.25273571157973335, 0.6120085151460839}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.46851590995197434, 0.29217583058627306, -0.37068715309198086, -0.3241463293975314, -0.2920873513377654, 0.0011293886316566804}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3573957287129933, -0.04813737716690547}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-1.7282688787449083, 1.1884252912296152, -0.012345088677864435}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.0, 0.16493669810936346}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.4297970620913606, 0.11644999483480167, 0.06964566738299416, -0.02755005564929458, -0.1540443934129495, -0.2031613392391287}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.28367333668609085, 0.00458531670393969}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){1.3156553768053398, -1.6100424122917962, 1.2410642320138257}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.28609754639546525, 0.7139024536045346}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.39961589774083894, -0.035469012843079795, -0.4052010114853224, 0.3872367330521955, 0.31291598638037843, 0.39272321505232, -0.27738331533754135, -0.48745550737323107, -0.13818969150489424}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2707297976359083, 0.3908959491470523, -0.2667092723191973}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.7926934517338147, -1.74260770760511, -1.4686781048601745}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.6108753210852003, -0.4242178252086163, 0.5658106884862901}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.3236951088189599, -0.06561693034228244, -0.32127867378141295, -0.019245058840784424, 0.10860467160331555, 0.35292409583183326, -0.49996654062422297, 0.13817591660421114, -0.44540925303778567}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.39162820837061285, 0.024735291907909684, -0.294627487336794}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.9721039935971136, -1.1163880823822483, -0.0486017335295581}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.5029764046291811, 0.47627927172024714, 0.5146911947329305}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.3620980992522711, 0.2911778185690218, -0.445046737283293, 0.2195777990836434, -0.3172227463151698, 0.008299642687703668, 0.12467155089889204, 0.39690436320598477, -0.1982705369893768}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.24345755362439625, 0.13171559218800166, 0.49655152821050685}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){1.562773669077389, -1.7142770823773903, -0.06089849829533511}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.0, 1.0181682431507282, 0.023055269457587957}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.12167001662065546, 0.385939721047015, -0.27123232256055185, 0.4990280858090611, -0.12689016347208948, -0.0020366147520587408, -0.002376591897432112, -0.4912413070420558, -0.12466914765705805}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.22780122385444945, 0.24163254706948922, -0.27340575833476277}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.10343216124231924, 0.8471284811708601, -0.08765118742964795}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.5071348053769364, 0.3468110826831197, 0.14605411193994378}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.4367038326225865, 0.1995780845231392, -0.21785843703338237, -0.07841856957784621, 0.11299842938346649, 0.01063141135248813, 0.18084595229111156, 0.4814407241301999, -0.18113689854963766, -0.38658214973047267, -0.24342040340882387, 0.08999180686697339}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.004235137655706378, 0.4531971501547376, 0.009708143361784827, -0.33097796521697487}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.9259697522671968, 1.8021099774460887, -0.22980634976093617}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.8183365869413705, 0.7270028047918438, 0.7514858036868713, -0.43236561414161245}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.2031009437067819, 0.11021993806874641, -0.21921115528913315, 0.22471757829338235, -0.200050207603102, 0.3115736314977754, -0.07883046478679268, -0.4209526717143758, -0.08733369531765955, -0.3158283809467374, 0.36690223427722657, -0.043306615382742275}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3502533983425483, -0.14025706330345222, -0.10780517556323854, 0.13741381088536186}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){1.911099820287844, -0.4723955260760029, 0.6745109588816991}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.4595796603823065, 0.6442510771170646, 0.47040726685504375, 0.3387881029882227}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3265036588796153, 0.44195454796776157, -0.38776575700563976, -0.0019379331081529338, -0.31952060890183775, -0.4355722071856799, 0.242180278682671, 0.2619891026977782, 0.18419870960634, 0.03023840826150359, 0.48260485685213794, -0.18885110845905773}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.10089462263108184, 0.27267190339992964, -0.19972850662509845, 0.391264524167909}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-1.5028582730624511, 0.10910114183535446, 0.9838482785008873}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0, 0.21267238513529613}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.005848916045059438, -0.2044770014360794, -0.09245698243496103, -0.09442238309366546, -0.4697586758838419, -0.4412632158098151, 0.062458444470072094, 0.2088214569816712, -0.0614917647398151, 0.021510314506775652, 0.45548379040151965, -0.20029732876710404}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.04265565918697323, -0.05236667177742116, 0.15845335564830487, 0.2140413937142026}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.2272148458512282, 0.8816297088316705, 1.3512671369907343}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.18891532404692918, 0.09430200789902912, 0.34141745706616783, 0.3753652109878739}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.05950099804998732, -0.25971386357944704, 0.12866650455324713, -0.042280636574971386}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.41350738717897684}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.25373637367866886, 1.2553221550655391, 0.048887418676432315, -1.2907225776025548}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.1634431332259449}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.06501568493841559, 0.008920614989422204, -0.13656541566244884, -0.4840383578679126}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.238844218268505}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){1.9273940859887442, 1.592268151082851, 0.5381513479309539, -0.2267820558767819}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.6021993239330515}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.05727095610605837, 0.3652123810894796, -0.16601731383596308, 0.2830318118479025}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.014631096587904291}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.24889289675900095, -0.7857279232368848, 0.13491126466709247, 1.745670443839026}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.15583966635571495}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.07101665704553017, -0.3997012950050115, -0.3880990540522423, 0.042150381593127006}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3432678103751594}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.49770440729434595, 1.6823267962296073, -0.2037218701997685, 0.46136155687739544}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.49393622930577363, 0.31896225375655873, -0.2191557605828982, 0.43511400350743257, -0.3423022942257802, 0.3194171121972752, 0.24087896202982761, 0.2725525463811289}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.12780625922573086, -0.21051859555759256}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2971450688026409, -1.4512065991547005, 1.3791869009899815, 0.4409263466424904}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.8478606279325959, -0.3233795477306965}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.17406178994859334, 0.30602233590342365, 0.3830658866365476, 0.26668849909705217, -0.15212072359258144, 0.15123651876921684, -0.25840402125389295, -0.10339056047326567}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.006187830475332445, 0.044894883276825115}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.7634294905161485, -0.22836203507634467, -0.4818021725411539, -1.2378920265692765}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.32931750442944546, 0.59362649362645}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.45819974719521117, -0.31161795687632765, 0.12488781748555255, 0.11667932872506881, -0.03826768208981135, 0.32980412145101135, -0.44783318352835855, -0.3553951404239626}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.23846544944782022, 0.47334417668475604}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-1.6331724222846762, 1.308552414198569, 1.5933968270996774, 1.7561807403501533}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5059911538198982, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.15285880409249952, -0.08537441142529256, 0.4689464275009322, 0.26506361283859436, -0.0037574479822077844, 0.4488540286659094, 0.37218291187101693, -0.13457532613318113}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2491359415833586, -0.28251476264638764}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){1.0518737210935143, -0.26902094072596494, 1.7278617391790654, 0.09310639290813283}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.6332630109451743, 0.3667369890548256}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.32715396810631914, 0.4390223260016536, -0.0719601955371405, 0.21971986172564995, -0.1896730728429108, -0.10813067958920908, 0.12489736444883481, -0.18198505968990597, 0.2358288302738587, 0.07060396050700912, -0.23607003524299952, -0.092739502305076}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2089326970411688, -0.24878693059723977, -0.2868264796760508}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.995131180402669, -1.6928046247063167, 1.4343469047115294, 0.4414142960879719}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.2149136079396557, 0.22182211383504413, -1.0205686792637856}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.34231488150149403, -0.010608428892375454, 0.4276456826835572, 0.4884265410968094, 0.18368621951325514, -0.49655184836930477, 0.2238858681203788, -0.15001210768167095, -0.1790254881376453, 0.0790189613628578, 0.32190601285095977, -0.2994007613578913}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.09858688641115254, 0.2513841446630032, 0.02596249454009869}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.6991035974868818, -1.521253729355891, -1.3264626038306795, 0.0050074270657636255}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.39940486472455755, 0.6412106063018027, 0.4018930566996424}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.481091981221374, -0.40038679440185854, 0.17037192543258428, 0.1834433467827178, -0.29802358278784224, -0.45316760764341046, 0.025124381286315445, -0.11866145879579004, 0.45554840508444006, -0.2632823757321313, 0.01397957576932729, -0.1274184238759255}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11786977905027729, 0.313060634317907, 0.3031611987258873}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.26289509980377046, -1.258768923173244, -0.21195183932080397, -1.759832281062622}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.13644734229585007, 1.1653419822304667, 0.7360834866383339}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.007891355193696437, 0.019371867522053443, -0.002333670610448091, -0.22987527330151747, -0.010422617755023289, -0.34508211616595597, 0.06278275226852026, -0.05135979012543146, 0.06147144866431575, 0.3623282046977544, 0.23243943227997133, 0.049807813266369405}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4614010839175484, 0.027180503887746954, -0.2502193767361247}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.9397993844925674, 0.06519926414518817, -0.8740793014905752, -1.9320573123016462}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.6000680160942675, 0.24964247013554988, 0.1502895137701826}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.09467157118131742, 0.2886887294700855, -0.1526945195862115, 0.107624183177779, 0.2663539810205722, -0.08940657215495662, 0.1248651696581683, 0.19205416519682894, -0.06729173493421137, -0.46236982737291743, -0.14342925341350987, -0.03565939364687931, 0.3578735292732246, 0.3347243358016786, -0.3763118832528405, 0.2954292815268289}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.35064567049926076, -0.1861525341461231, -0.2722152898181135, -0.28936694480704617}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.6432327396344726, -0.9231704432508536, 0.5277479000745222, 0.7820892201956435}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.5526712173180355, 0.28381339499777913, 0.007763306978900153, -0.335724337326354}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.30879221659440237, 0.005560866586946656, -0.062125071639239304, -0.4627318182562983, 0.36663147014481123, 0.42046520274795396, -0.25293282459599487, -0.40349862434362915, 0.25600654486724106, -0.3736426900780452, -0.27168805798587314, 0.30028766453548383, 0.064194852857829, 0.13261277942863225, 0.2954022388772828, 0.26202310512859717}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.16266735264476218, -0.32565286789778713, -0.4252304024063709, -0.2381210148941214}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.10552566494390758, 1.8847691873701908, 0.40324241173208364, 0.37973733399520704}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.5012414464219954, 0.5431229060270831, 0.24012367198089948, 0.5556850274349069}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.06906891349437361, 0.2671478331760079, 0.020372180267489437, 0.3214699254343266, -0.1679171589397216, 0.3757314288483625, 0.08462589036865575, 0.15074510567317345, 0.2934638841097218, -0.11745102126603191, -0.3170114968826496, -0.31998263564326634, -0.2566594663583388, 0.19866414050072922, 0.02476672231778787, -0.45051849093440755}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.22091380247820702, -0.0029200384429212134, 0.3554689809268049, -0.005185537946792995}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.4159035903366126, -1.485897786457853, -0.6167885148442793, 0.5251468609479555}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.008939033027609206, 0.0, 0.4354276840927517, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.33319554214732583, 0.23446808013523068, -0.13943254379152248, -0.12752196195776488, -0.24321875803082615, 0.029076977547141336, 0.27420344297112886, -0.07974667811037983, 0.10157590083985468, 0.37182124732727184, -0.40144768987041246, 0.4222632143479724, -0.496002231079703, 0.38291580608706843, 0.2905128175391981, 0.4616427355464351}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2722317247055963, -0.4323779642937754, -0.1293719934995886, -0.4775045160442267}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.8829698290963575, 0.9643361709684357, 0.12387703081618584, 0.6101035887826289}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3266243807293024, 0.13256540599284217, 0.2301519909926662, 0.31065822228518924}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.46742812886986096}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.37720332787535704}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.3599073961968307, -0.6655507842575066}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2584556417652122, 0.0661061701220022}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.053124955719346056}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.39794337884978526}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.3605019623944163, -1.5917958862177382}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.6154358226533674, 0.5777098931526707}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.2296284396683853}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.0645804830826292}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4060675189632268, 0.5251877920197372}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.4641733877510248}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2922591693022063}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.2548273557375893, 0.4036558863256814}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.3205148986079698, 0.2521648426506594}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3598686924295672, -0.25252248957004775}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.4404803857216755, 0.7073355005982211}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.8215641172059192, 0.11071602023681976, 0.5865802586856236, -0.07415734436047192}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2084156927207248, 0.10199816712787835}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.41932560408288255, 0.42601772432381313}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.0906827736108502, -0.605776656188044}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.6562531232211857, 0.5780491546091295, 0.6331092702645525, 0.5900639177732921}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.24807366834018063, 0.18622748259751953}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.11189045846120527, -0.39989984925192823}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.8100223382481495, -1.2342008499556987}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.08905475442550378, 0.0, 0.19428227385587377, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.09780359662061044, 0.1820912318393202}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3393693029921311, 0.3335258281893474}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.2337118960302824, 1.6791754285543101}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.41882821133566467, 0.5811717886643354, 0.24179057960608114, 0.7582094203939188}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.08631725799504608, 0.0994268135137073, -0.192456325583781}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.22061466211693848, -0.33997909548380145, -0.29679325405967916}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.3438415524960545, -0.7432875995760968}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2502941221131576, -0.30579202556551266, -0.36296773583609254, 0.15645611461981002, -0.41388181303390514, -0.15374285379327482}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.41975206490890227, 0.09091814110731, -0.3015432180287423}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3244074227051963, -0.09561094316355001, -0.2784739043939253}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.45849542243411, -0.08375546088742558}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.42854278307938504, 0.4431926801602905, 0.5402441299976934, 0.5718127297541752, 0.4742164323315009, 0.4370315955205919}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.12484606852072555, -0.07012490380924619, 0.013714551797112784}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.28683394233225334, 0.036206722062279484, 0.08516861716839785}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.1104049047246245, -1.556594798215976}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.14820425551125316, 0.11407375919540895, 0.0699399115867839, 0.09249920149517665, 0.1453627825571478, 0.06382061718114852}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3644356878022439, -0.46937193807584743, -0.3201063779935397}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3828169571136122, -0.026165988078360347, 0.1961733014042586}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.7407179371896313, 1.155557578093004}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.40821058460964665, 0.22590980387083384, 0.3658796115195195, 0.40620480727215447, 0.23903611741510217, 0.3547590753127434}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.382735460423549, 0.02326151442497837, 0.13563070982980896, 0.42742108363375186}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4009208924963149, -0.318070524398261, -0.1634238668530249, 0.09493596089678924}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.5245792157264453, -1.6437446819163992}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.9844314205795491, -0.3535345458169039, -0.37020362807377616, -0.5567013395745035, 1.0300402701483482, -0.3563065150276408, -0.3863661248403197, -0.6076351722651349}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.11631599554361804, -0.3325476026493315, -0.4511169549522238, -0.2571858278479461}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.07923956254818865, -0.050076923963506714, 0.16667970126778076, -0.19133006271565778}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.9846073179049455, 0.023753956045057922}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.4517097077764583, 0.4067286259441757, 0.43106842059762107, 0.39065563827932764, 0.47951084827748575, 0.48550999720183075, 0.5389121269329205, 0.4507999128922799}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.1459286992505915, -0.23549733033162035, -0.3375900529124435, 0.42026472340444765}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.45567703170600504, 0.1501427327613113, -0.08639115347287929, -0.2540418723015515}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-1.9864771941301562, -0.39749172710393044}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.0, 0.617952808743611, 0.5842237876028824, 0.0, 0.0, 0.2437509733231919, 0.047798099712395126, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.29227838756055413, 0.4276238613760497, 0.3978206337918344, 0.2179543276717888}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.47789069062353295, 0.15879113828439373, -0.13840231406722636, 0.21733778103781332}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.1789617388747624, 1.092450105700078}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.1878718542173036, 0.31906593008111717, 0.22885015432098846, 0.26421206138059067, 0.19650574167241078, 0.3135783929889095, 0.2254948667258703, 0.2644209986128095}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3992347387418028, 0.11357939120748128}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2246681517287603}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.6545971259143184, 1.7380597038682994, 1.95262556222408, -1.0064204135462789}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2384967365109638, -0.669196422335704}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.15414063893352603, -0.2769463058610916}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.46544724089122913}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-1.212433973356951, 1.420781091280488, -0.3926770411392937, 1.5052470450505995}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.564354193322935, 0.5272485070851866}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.21241600872422017, -0.2859992886319336}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.15699409785799368}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.943678418146594, -0.22607137773317243, -0.7123252993697076, 1.9053392244913963}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.057960737582820276, -0.31654780602345867}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.22741344055332302}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.355934789006894, 0.1160393325725182, -1.1956859358375813, 1.6634604965876187}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.2865824245033146, 0.11742951589695738, -0.043453959334418424, -0.13057968835026945}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.20332305061154643, -0.1755490467405132}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-1.6439461124950476, -1.5836245880569, 1.2730501963290903, -1.5702716720881735}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.48848484454513563, 0.10267612595211573, -0.34590700344688496, -0.02582253263594067}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.3708262922412441, 0.4819462429190061, -0.10222313751337375, 0.40498411857278604}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.05994169157945117, -0.16262405179710682}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.3107843890465265, -1.4353136674408078, -0.48887312834491636, 1.1011253373683134}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.22482629882933106, 0.29361401361272554, 0.6574674432142774, 0.5825592715138762}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.23381964773238495, 0.4759002925028487, -0.3730794908210864, -0.2663590121947961}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.05654806765681275, 0.31742937044823427}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-1.622109287569546, -0.3470636684706947, 1.8672200641954646, -1.3746381191162769}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.0, 1.015048613413392, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3288372593051838, -0.15812277386960805, 0.1176108802998308, 0.3456454253400848}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.12352032906923127, 0.04687675588212903}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.11844602775458313, 1.7701111924834003, -0.6251419752324723, -1.4096943182717179}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.2521568897154841, 0.7478431102845159, 0.6005399980774965, 0.3994600019225035}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.06889694762458098, 0.37922916890804137, 0.32356293448406115, 0.07594932890383632, -0.3133975439569051, -0.32056777451255225}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.01112404602097139, -0.0037321359253911224, 0.021936542504760403}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.05344484858227, 1.6099394037877675, 1.0768820766432543, 1.7342156062460434}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.6719910706279286, 0.459397387892529, -0.8243051775072867, 0.7207349850754111, 0.47641950035553654, -0.8714892928656779}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.028726080561431222, 0.032930325808731564, 0.4516713143463129, 0.42295217218000947, 0.44800154092436484, -0.45013972262536794}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.21103951594696224, -0.40401604235551447, 0.3751614340882886}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-1.302497239604314, -1.2927332133516405, -0.6057585535748267, -1.5961741684654034}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.532716624849705, 0.17666890959371534, 0.5923168021983248, 0.5352105992519898, 0.20542520248825666, 0.6947205445646147}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.44102932078876533, -0.26685860701641384, 0.04583380569594264, 0.23557871514864792, 0.37487201383308133, -0.14963213240546203}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2989810811653957, 0.41529315273336165, 0.07773541158175079}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.8018701681172895, 0.6655848922371899, 0.07828804101991649, 0.030681430884858862}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.9160416003661158, 0.6546773536437535, 0.6536132234473215, 0.32532079881508863, 0.42610928366056156, 0.10249247924938153}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.09639019770105428, 0.4390483782476582, -0.06782986426300186, 0.14769494577771414, -0.37167288548203936, 0.09981550988129007}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.08940484927836134, -0.49173839134170205, 0.31090551213790873}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.3031203582065873, -0.37715075388952624, -1.5552658803669974, 1.2359763637783714}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4396325958940841, 0.22155742010707286, 0.33880998399884305, 0.3122168180641002, 0.15725277441068788, 0.530530407525212}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.027152259809546164, -0.1920412719760759, -0.4075944935961098, 0.22637110691593199, 0.276120913908242, -0.005794733681643627, -0.08323568596241604, 0.16796426232810657}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.260701494305699, -0.22914018775286993, -0.3748674457781359, -0.1180080024998047}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.16346102952189945, -0.10631150333758965, 0.7262804846297164, -1.1498748845973639}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.23584696163674493, -0.18658022489061954, -0.4193864077889684, -0.12225874481451694, -0.05959821526754691, -0.7854665645353911, -0.16766299588500527, -0.371598343600088}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.08430425560198818, 0.039839868290637015, -0.32724509607318697, 0.3725767566131185, -0.28561807737035416, 0.10460385472998657, 0.32439673278930814, 0.17153231202415642}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4759878852107021, 0.15040998466512168, 0.07984101877154892, 0.42246872223182297}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.4864073082066271, -0.8914923915301092, -0.08789847198702239, 1.5150756363272815}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.40463376502950765, 0.3389092250157276, 0.39222780663889434, 0.6795565522180489, 0.39579008738289206, 0.6777948693547498, 0.5654790684251333, 0.6578750890352756}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.4307618240482741, -0.11918627697394568, 0.3484429837876606, -0.2968127066320476, -0.028294132076763567, -0.30239473757600466, 0.0691185454639216, -0.4200860648358796}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.04390917357117263, 0.23158381442550557, -0.08585133288967572, 0.39502126380039515}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3163771706624523, -0.9768918017125476, 0.6452613219502035, -0.8648459401508739}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.02405806330187109, 0.6317771195263873, 0.2006039896765443, 0.8272674264064312, 0.0, 0.7131178590845235, 0.15741641915863472, 0.8029305155049877}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.22794932272395396, -0.18234478148897604, -0.4304444030293515, -0.03459801483285152, 0.44148053624800987, 0.06803548252769587, 0.49362253218153684, 0.33883744368003965}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.07821867577352226, 0.31494742394945363, 0.4616248958377064, 0.3028335510504848}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.042342265777231, -1.4708691675830798, 0.19887607954842945, -1.642907120616838}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.17260618112217832, 0.16663292596743087, 0.41172456198957536, 0.2490363309208156, 0.2419432238405464, 0.27011925412723026, 0.31429395967707513, 0.1736435623551482}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4401029484213764, -0.06678741838129842, -0.21268796324455286}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2823732421328984}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-1.562503892251931, 1.9543365126737036, -0.8073060650874657, -1.6678485884625704, 1.9131291571166047, -1.0974853334244732}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.36411013539841186, -0.34600287634689697}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.05378496745622674, 0.15842406379398477, 0.19526218170622756}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.33541371147573185}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4629684251277597, 0.4231148590404086, -0.5816340703310061, 1.8706589021967903, -0.36650874390061494, 0.5953234680311779}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.5656127913478632, 0.5727257098035203}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.05610650350357893, 0.3729233684399318, -0.09444397677256411}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3892840855245886}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.5262805293682749, -0.1885456657958673, 0.6839764807286031, -0.26021682267840074, -1.6317537443044108, -1.246022907214444}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.22484578150746531, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.40395982391513086, 0.3455554040905744, -0.45508122990871613}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.33383786573738605}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){1.6476390751881524, -0.2601716440460051, -0.19043051819280832, 1.5070756985146492, 0.8175612513993591, -1.8734424796794156}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.35520999893124083, 0.21305980075298148, 0.09664687331470789, 0.38540598726574027, -0.29598456979392496, 0.4704018769420285}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.23707652905291587, 0.457332561864212}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.3720485415345598, -1.607724294714767, 0.6700781691681725, 1.8855855824195036, -0.2925572508538328, 0.1362700808780546}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.09145143312266843, 1.1050104385962844, -0.48186443599563045, 1.3347426686807906}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.21682694147103465, 0.15773899158051963, -0.2880020407668292, 0.3698180246868419, -0.08298314522066752, 0.42785727960877484}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4262498047423222, 0.45143692682944225}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.5066610395549866, 1.826224801802466, -0.4713159257391406, -1.0228936893027671, 1.9714560943322779, -1.8220123711556804}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.6770393373492393, 0.5709204338117007, 0.815139758375338, 0.2952529535003604}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.31364371650766387, 0.14788083223998194, 0.10884967724568428, -0.12324620630800809, 0.121215426664253, 0.4178919419081817}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.06890305383605133, 0.3936153917845293}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-1.1527667598085167, -0.45542177821597374, -1.1480683258392657, -1.4270715758581334, 1.4505996565642763, -0.5186758326422938}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.23814608634250414, 0.000716874402015899, 0.6745532740921518, 0.5285811550047614}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3376532455707598, 0.3618957995826806, 0.3390613632292768, 0.25671566127004886, 0.0787617175577301, 0.4077116306184698}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4980344313529498, 0.3480173330931864}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-1.0573389861036384, 1.8958797971570718, 1.268548023712333, 0.30762979908411614, 1.5925435125219543, -1.9435161725508552}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.625776639062024, 0.3742233609379761, 0.681189176235686, 0.318810823764314}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4121984496022123, -0.39224103878699235, 0.44655083616858016, -0.053700775637103404, 0.29547060364356525, -0.12154358382466524, 0.19466029362945692, -0.06631875299055268, -0.29923845582525765}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1841736909869206, -0.47578071837170577, 0.34021448727938053}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2877250877105575, 1.1941866891786423, 0.10907822549313329, 1.3364001456735113, 0.4983200029222221, -0.6214155134301032}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.48527391058825453, -0.15164247528096259, 0.28438576551271016, -0.1062667956170182, -0.32477846213828, 0.7532619895232686}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4840382729440562, -0.23755967221522645, -0.36092890647424436, -0.3629753583036567, 0.10183457340378599, 0.2589442440204891, -0.3725682842323832, 0.19977273151555763, -0.19290045841773373}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.23568871262244406, 0.15004552895997392, -0.23282277349038205}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){1.6801085779980105, 0.7826439423108518, 0.2167262594756192, -1.9321675545972816, 0.7456255586481193, -0.2000580844712001}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.21197307815007194, 0.4197079851482114, 0.3220790621289072, 0.6444268943149242, 0.7058891155143082, 0.6625298447293616}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.39308304205406985, -0.1366068322431443, -0.17960743128293288, 0.33847087952364774, 0.1976076648385785, -0.27490729320621965, 0.2365077180888292, -0.29200477732722163, 0.33018720276290026}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.31015738152599326, 0.04157853759422825, 0.22884334123000238}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){1.8917221042928127, -1.9845795709273486, 1.689122973222962, 1.103677883380485, 0.023553453451710116, 1.5976166182811626}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.0, 0.0, 1.8134837247223303, 0.0, 0.0, 1.0105065202807575}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.04573125590536453, 0.3227709376892943, -0.17177252951380706, -0.1201953598904757, 0.34931122790539826, -0.3554250275617481, -0.09207621985359038, 0.27262577590996806, -0.420569829858639}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.13238718906096192, -0.4360063502504449, 0.3893497009123609}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.10032030275545001, 0.6197181616799523, -1.4034893966797446, -0.13476367568911796, -0.5890941665724476, 0.6899071178040197}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.28092740079130524, 0.21284205787885366, 0.5062305413298411, 0.3780529612700401, 0.1899315493294791, 0.4320154894004807}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4952473217087575, 0.028797615974001767, 0.20082883458774525, -0.45154996855277996, 0.18465685241850405, 0.13969514820438733, 0.18522437206871167, 0.276126912553892, 0.019306807610944166, 0.29995084678173733, 0.31582023876382803, -0.10953186575986129}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.15607094715063252, -0.11665710887465486, 0.1932522165040077, 0.06299044940496024}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.10921291522994059, -1.774761450325327, 0.029619330955022782, -1.3459413110448066, -1.2617529967085503, 1.899067607914993}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.1471440263619641, -0.4895563836955894, -0.27600643492441973, -0.468000889764962, -0.4775927203751003, 0.5234018418375354, -0.36778794411616755, -0.9472213375419669}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4731603274269002, 0.46313154267112877, 0.23307671588202838, -0.2758457344752032, 0.21617846087746317, -0.45287523013032527, -0.375155917832806, -0.24072465370070983, -0.04589365520237976, 0.17447590146528402, -0.07198227792204015, -0.3651185489836013}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.10928251332814654, 0.04234631290340085, -0.320119871341086, 0.08964017751798281}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-1.0536475072050444, -1.5478791985445217, 0.2183719255584755, 0.7504881377950601, -1.2049995244301797, 0.4816145297948502}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.258220921796404, 0.47489041664277304, 0.6077234914118094, 0.48437816338680645, 0.5046407593801423, 0.3445057224088479, 0.4173406548711413, 0.532821356777003}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.0592415831896822, 0.2968517589350036, 0.13179397204768994, 0.40657404387900353, -0.4331852372423457, 0.34591262194515504, -0.23683035319195544, -0.21940459507462862, 0.456180804290664, -0.06612290343563998, 0.034063463635502056, 0.3043705501430124}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.49654991151176464, 0.12253788667874266, -0.3583238806892223, -0.23010116096423583}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.0330916247403783, 1.9674323286915119, 1.798223835174066, 0.3248469721687677, 0.7818750273288826, 1.345930833085454}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){1.3195411209777896, 0.0, 0.038164722496790204, 0.38643089091890326, 0.8867920103098333, 0.38148997801733736, 0.007183332345179316, 0.18471409374527592}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.18389137901973485, 0.16539808065647177, -0.2194991075868301, -0.31439347142980434, 0.23126450148230926, 0.4984795829189973, -0.35712727480847384, -0.19274938013820053, 0.3231020418082896, 0.23199942475283997, 0.3677166599741851, -0.2354309158148632}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.1208166020046737, 0.23359193877713524, -0.17803547306125012, -0.3918286004957585}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){1.400697609970007, 1.8778020725691253, -1.2106699091438125, -1.0879784098625631, -1.0345764922142613, -1.7225350648977655}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.37457895932758184, 0.12605441354612307, 0.04387476322681815, 0.4554918638994768, 0.3090309454298358, 0.20542598486370825, 0.29908284247361655, 0.1864602272328393}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2327093197464033, -0.09257587141189627, 0.31355841762075776, 0.15898277278913997}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4931270562202532}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-1.6013250055800081, -1.5750232680022385, -1.8521379876556998, -1.2437641789548781, 0.9158672207787402, -1.2675935310412783, -1.9356739167199732, -0.5738196183211683}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.5121975794825264, 0.12543218551993718}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.10640018715020394, -0.04969085182402089, -0.06308792988144885, 0.2652028725987946}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.40906563784193206}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.46759565881476295, -1.9339133064297278, -1.4225998658591759, -0.3415953693317251, -1.9851427895382967, 0.5978609515377546, 0.03714287302263086, 1.5865285461673326}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.635079927378257, 0.7328215910546905}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.30329719821739753, 0.057438835135485755, 0.4886564804999236, 0.15510539024484848}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.14755703499390227}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.9250275573760112, 1.2400592761508116, 0.7350700836751138, -1.1630820783240203, -0.12374869551695955, 1.4289334040405386, -0.024815031260219556, 0.06546991923579659}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.6781393221052144, 0.2651946493747793}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.46817064740388137, -0.4048948228818021, -0.49164677117752975, 0.030849603921765056}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.21146862124840782}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-1.125136580360035, 1.3558989771142183, -1.5369105721733023, 1.6965648792528394, -1.517602366664545, -0.3761443990283664, -1.2681794196210276, -1.4193629189902546}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.33228316446019823, -0.26148161678137427, -0.2321831150776409, -0.4769950994763301, 0.0571892046786896, -0.33125364919087785, 0.4323090502268133, -0.3925794441906525}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.15687237816563293, -0.07276059593911299}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.5909731690969293, -0.8519042232150036, -1.9109994450337533, -0.20807701122291844, 1.850968006469901, -1.8297783971526176, -0.29661616021548376, -0.012927443304469488}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){1.1189536252599654, -0.5688170964168848, 0.09531587646651725, 0.5160607615066349}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.056865639687060154, -0.17656268591529278, -0.44768724775965285, -0.07047676487917753, 0.434104674078568, -0.1901106754570545, -0.07192867686457916, 0.48311413675197856}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.09875261733895568, -0.04479659689274984}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.5820896303832073, -0.8649564188929193, -0.269494539704652, -0.7698339545140716, -0.281890961996047, -0.5474766689185127, -1.8231777376805214, 1.404435639922879}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5970709411830211, 0.380935297255391, 0.710254417011327, 0.6784277739917199}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.41327476180635525, -0.4368448660660723, -0.3221332953068956, 0.34525827253158603, -0.3347505542657103, -0.17860283659637433, 0.45670975741257847, -0.20499472527951312}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3703270084180801, -0.34604838580196406}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.5253570502462241, 1.8639993558552979, -1.5007976233991633, -1.7887622584533647, -1.6145826443270863, -0.8067765033195267, -0.9211639968314667, 0.32936234768223605}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.1240754262984134, 0.3461058019487768, 0.15916637322751293, -0.1829180032069605, 0.23485781015265317, 0.43813808016964007, -0.3371653853739073, -0.022834026741689217}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2655706183233837, 0.2631521422936436}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.13037868011206744, -0.34792304187019285, 1.1405496659825398, -0.9614120606522212, -0.8892378033445341, -0.7843988201205012, 0.9998947077345677, 0.28821107879360675}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5671155688500386, 0.4328844311499614, 0.5775650913343379, 0.4224349086656621}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2347668096392317, 0.3933050574299275, -0.4515238433395794, 0.05182095420042343, 0.34169810543946055, 0.3672993282696111, 0.24544978666245043, -0.031625922401916085, 0.0005086793781924337, 0.4569166526888777, -0.08854728588139416, -0.3401537773355664}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.41051449861565337, 0.01225849210420149, 0.44248397156332764}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-1.8165602771511842, -0.5982891971955229, 1.8101003141736651, 1.6406553571842641, 0.11826834551638044, -1.0977481561571554, -1.8423698027404267, -0.950424627199232}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.9835468537937274, -0.43580643631885685, -0.5501629595565941, 0.7891520622819517, -0.7726828181924248, 0.42739209186214044}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.49793998318501753, -0.40343840949123433, -0.05394288631370181, 0.03490681786958705, -0.13227954444725287, 0.2583737990931223, 0.4085828408485851, 0.23886327825594722, -0.2339846552663285, 0.0073730632447099875, -0.22526046701659908, 0.32011336890526343}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.36040371246616776, 0.030207946585109502, -0.48339065837404127}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){1.8068259636240862, -1.1924035802844593, -0.3084587972851436, -1.6279450080547084, -0.3626065171629502, -1.3285849683236348, -1.9803180193985543, -1.0703090134015798}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.7271402323833396, 0.2627408516346783, 0.20317048978121138, 0.5161207103777679, 0.20917927221311888, 0.4243662078873462}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.46790660001561146, 0.4318933798692046, 0.2296363231890679, -0.362922169134107, -0.13962690177313808, 0.49598827429058934, -0.1495450630582511, 0.06979270112321512, -0.15585366335943762, -0.07764672247998217, -0.38940660417615425, -0.3548616418625381}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1920121460771611, -0.21521418610257081, -0.03413405674296843}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){1.1659860473982309, -0.683690429939201, -0.3898582631390375, 1.791581216024814, 1.5123507814641766, 0.1858324543361931, 1.0323246777053119, -0.8488779673899591}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.4313924619166244, 0.45165850842221733, -0.31422419917913724, 0.3910872654730889, 0.21745744475618056, -0.3641790171669441, 0.46765839755307936, -0.3351616377039722, -0.48856770858436716, -0.2967420139814514, -0.43364649071148975, -0.08007720670335794}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11692376161772666, -0.49480666838575704, -0.0782085669624456}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.9241987126247078, 1.0558506390827351, -0.14737572561891543, -0.4628024290486623, 0.5754482142776038, 1.4993290008220268, 0.8847856657803295, -0.4312913357611565}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.5078987790664792, 0.2644612297104502, 0.22763999122307052, 0.5210399266355143, 0.3300652212035703, 0.14889485216091533}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.262480425161038, 0.21070826527530506, 0.1415607548450004, -0.233880696318995, 0.357838215031945, -0.3413338878781734, 0.3399812656410216, 0.17047326660996542, 0.18563840887672722, 0.08496291674116752, -0.4861230899778858, -0.4562936239580707, 0.10244699648851929, -0.3173337764728258, 0.49549431540756905, 0.00728120778843433}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4109067981008435, 0.2514238601965554, 0.037784895128467055, 0.397998175722288}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.29904222253455703, -0.4824082353420738, 1.1000329142540681, -0.15164635902021528, 0.3991636740254738, -0.5001063167741688, 1.7163854673356829, -0.9919265890299003}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.578940771127406, 0.6572163358225585, -0.524271770621616, 1.0644025124467902, 0.6757229164737546, 0.9794050479158186, -0.3123703158634097, 1.4408287398807778}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.16111447495602893, -0.08025693622793373, 0.11495578562695996, 0.13730827498030174, -0.43143966459506256, 0.33294279038038577, -0.3657894395540555, 0.39799150988003695, -0.15016460021362033, 0.01589800581179468, 0.34096694233919955, 0.0686886045679973, 0.31789693316463685, 0.18942619965841279, -0.3039534656708819, 0.23966252879545913}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.41117497370339584, 0.24993732117463618, -0.4867411705741256, 0.16222573513811678}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.42469049296714934, -1.583276614330801, -1.80127868311606, 1.3471725599021473, 0.6958632090943739, 1.6733798711316838, 0.2270024524423806, -1.482615882194311}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.6100995409331343, 0.7504618620921083, 0.27492441187449823, 0.6451243262205201, 0.55268077471941, 0.458533079881386, 0.35684820545714213, 0.5685885657849131}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.12314184892098567, 0.1688697853725324, 0.30248151921568367, -0.04635618729069235, 0.48085341786943747, 0.06295795532868931, -0.4607098791243185, -0.49672924840570176, 0.21438758526146717, 0.17413995685600925, 0.23182225653138355, 0.4025902753149071, 0.16807044535843518, 0.10033894901082197, -0.3557110458844175, 0.027093936486366932}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4198419677412396, 0.24370862661254278, -0.43735987223165096, 0.37198817313471355}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.7058923909026862, 0.2934435552068684, 1.5253946914158596, 1.8359373207406562, 0.9260726130410557, -1.7985064609763275, -1.2106381142996918, -0.7254006579058871}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.9326172614517706, 0.0, 0.5551567615545883, 0.0, 0.0, 1.4938641812570055, 0.0, 0.7581567520318475}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.03634520705406874, -0.1541765201173012, -0.33356217099948426, 0.29443365130961063, -0.19273102137617604, 0.1828113651751161, 0.03719509085436146, 0.1605201339398249, -0.4119181468887786, -0.014292975266800623, 0.41909595793532106, -0.13410058667984992, -0.2071269704961074, -0.46027148593486333, 0.22507230325519145, -0.05154386468196015}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.48879686969852076, -0.10250148997421449, -0.0574194454767325, 0.05914460026159141}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-1.6654665664763146, -1.0404231347415656, 0.9364481751071105, -0.08878895087771266, -1.0666331830193587, 1.3651147470380942, 1.7229449333903246, -0.34829373097726757}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.0732372208268896, 0.1410239181025924, 0.3829566250559019, 0.40278223601461616, 0.04481807420900943, 0.2449798335379291, 0.5293177287889255, 0.18088436346413597}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.3785139549121177}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.48836682892022876}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-1.3816429657166265, -1.756444828093982, -0.6668652268687807}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-1.0113379721501365, -1.1532057073870166, -0.7407846233356976}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.14997121619145393}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.29896628728676244}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.6261027288658334, -1.9439940255219796, -1.2105873334408117}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4489116855671672, 0.3565179746706239, 0.3821294504630451}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.11578773741816173}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3066368368100698}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.1383942560729694, 1.7884223731610565, 1.6543407303680526}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.44699746727757583}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.35712832653947}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.36898207352020806, -1.4743659137306686, 1.9864165794319195}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.062071039230898184, 0.32118062405352}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.0038925855034760426, 0.00017517036500003247}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.2219853627705306, -1.4693300978700004, -1.9913248875171687}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.079742486895589, 0.39265319176390606, -0.08731026064455222, -0.4717451874095063, -0.11971101971106606, -0.6393997997010697}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.11995515843721982, -0.22676289389566462}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4423266526692494, -0.022506459888572694}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.8910211469884173, -0.4552858521429952, -0.06413640315451552}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.41691658971337575, 0.5447658268307799, 0.40426802673216145, 0.5201729129442768, 0.39302052008895083, 0.4980093346418095}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.09485294622110929, -0.20122536363686006}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.07807566131000998, -0.4734023928384634}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.9627325473823674, -1.918715380576153, -1.6159013211525632}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.0, 0.0, 0.2600714681174151, 0.0, 0.23134866242391353, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.06296359761155934, 0.39734687904998656}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.48290068638015937, 0.49174581503487746}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.6113300302029989, 1.3379683806141687, 1.5252755267920652}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4468852411196155, 0.5531147588803844, 0.387878324241217, 0.612121675758783, 0.37311609072723695, 0.626883909272763}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.22207352774231848, 0.09764814907846009, 0.21654965270985205}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.15263319084830662, 0.02363620076717643, 0.10600178146235761}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.6943196461976768, 0.7677037592078051, -0.06732894116754107}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.5288967318025417, 0.18908337816565093, 0.47290611242594394, 0.3231198729166233, 0.09860105189439441, 0.27224776390285566, 0.13768121536407577, 0.01706165428275351, 0.09142172263520454}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.2854799070857307, 0.09701928300662255, -0.24588640180483767}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4454733836604853, 0.4525714575179951, 0.39921702613821897}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.3581168150622447, 0.25959022740093696, 0.04104414195146777}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.30297131245878084, 0.6420642733519806, 0.5163128506163693, 0.37295017357189403, 0.6172180160079278, 0.5830696143047471, 0.38765248826750354, 0.6121962600646425, 0.5960720021373636}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.08088879255270964, 0.27442207100123683, 0.334055431281005}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.1409736753486297, 0.4173441960407681, 0.037792338610018295}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.07513607250464016, 1.6968025602231784, 0.599232418842357}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.1348960091665765, 0.43796319266439054, 0.06289195171531672, 0.0037213650518304053, 0.8829842686974136, 0.6046184496640856, 0.09250248853003187, 0.5817867974305683, 0.2379691827239617}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3417689453631786, -0.4363376237726406, 0.39679210846300617}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.19003770436345468, 0.11269862061740887, -0.3768253589616565}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.43286440028177475, 0.6267363502082528, -1.4963232024424817}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.42081841224866684, 0.4057745648219753, 0.17340702292935783, 0.36054813087012616, 0.3145102751989731, 0.3249415939309008, 0.4436276533161162, 0.47302669092644195, 0.08334565575744178}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.14745747812237497, 0.1496320011204728, -0.3266145149671863, 0.27272507870546014}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.27503312413855263, 0.026963278576632943, 0.09603128700029162, -0.00993296539219879}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.2423264752085852, -1.18809099961129, 0.7994091071519152}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.31076597505509485, -0.009296516833298303, 0.17517863116425159, -0.07602147241587692, -0.45022602672112505, -0.15081315520842728, 0.48407905257521266, -0.3339551767704367, -0.1571542732098718, 0.14658046299370447, -0.1650673307924826, 0.2080859462736689}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.4974453414102197, 0.37656853620486086, 0.395895134629658, -0.31255329195818016}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.1496589863890897, -0.19725921116993972, -0.1846057444261664, 0.3002704400484174}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-1.421508963178976, 1.93887975561235, 0.4566315692067029}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.6358655618236415, 0.3246343533410813, 0.3213937126446785, 0.6779938879166658, 0.24709881221724214, 0.6301503570560159, 0.6417544979810519, 0.4241566517283534, 0.40689694246828784, 0.4936738052122166, 0.49904311920345756, 0.5393059155908421}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.46784077877766994, 0.4690254995523482, 0.09711329882904107, -0.396815618184576}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3633298465460991, 0.48200255249823476, -0.031845084637938115, -0.28723368237078895}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-1.0817849451986308, -1.1321544505342298, -0.8011714441906301}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.14277326468558726, 0.0, 0.0, 0.14203547940097339, 0.16633817328843992, 0.0, 0.0, 0.16202288579837043, 0.011490825838475827, 0.1062327156596482, 0.0, 0.03068365952754548}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.14271201960844893, -0.23194392377587236, -0.1668349360430058, -0.4866966942600973}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.14405975671687377, -0.14772731218984392, 0.4132463758475077, -0.21746710211089926}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.05474200751490077, -0.7254236671445589, 1.396816031922071}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.21293025460541498, 0.21318958644169486, 0.3722595545867377, 0.20162060436615253, 0.19871467481548427, 0.21122699916864435, 0.35307322370934663, 0.2369851023065248, 0.24140571646615167, 0.2123362024387062, 0.4075199322606684, 0.13873814883447358}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.050311345400932184, 0.3280274892839804}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4595090763400146}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.7895229209657049, 1.1289126818301467, 1.0256071604545922, 1.9819762590693109, 0.8545175654171637, -1.2128450889135145}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.7901015086029441, 1.1612514485182768, 0.10465447531817507}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.37541064506236244, 0.01642517730065496}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2620698477886788}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.0017592233167671445, 1.118853211215575, -1.7216361495344974, 0.8835044175416393, -0.7382720159028135, -0.38489790556000614}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5698177560202773, 0.7156330597633818, 0.6301599369469104}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4394750637020659, 0.05601635999018728}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.040090339817846155}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.6740873771152596, 1.4803120024024952, 1.1086199958119916, 0.5799878144430402, 0.27939306097275596, -1.6386926085231526}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.0, 0.5597899893024685, 0.0710830280144713}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.13115551570603656, -0.3203270193314878}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.48491814987455084}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.2758359613326866, 0.4001785865921028, 1.980786904926704, -1.8289819689278661, -0.8686734408380699, 1.4432907167297677}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.26267273370819544, -0.4953325777766642, -0.28800431072177424, -0.21660076208684764}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.07133311993701463, 0.28996087902869994}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.6790754948750144, -0.5566284551559777, -0.7283799463174021, -0.9734182288605271, 0.877953878711244, 1.1291318281021794}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.5254239441263331, 0.21495035678518315, 0.3621733288158737, 0.7105805736118258, -0.25734811373571925, -0.2074644371184876}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.20314995320214013, 0.37660510143441484, -0.40861800878512256, -0.2652828755251434}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.23433963343920827, -0.18963349751882885}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-1.8518042403130375, 1.4118970976248275, -0.8408320689680662, 1.701117543090548, -0.904284348532987, 1.8408035754622052}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.48030870767034817, 0.5479756847329095, 0.5586031452626271, 0.42620989434156686, 0.5683717627632551, 0.42349060819977136}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-9.026173787851643e-05, -0.11610480720724681, -0.29131116822726955, 0.09322651616859445}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.13314716154828743, -0.36026850831180846}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){1.4292964722184847, 1.8012796673102076, -0.6112849898215864, 1.210295271669056, 0.5902976455178885, -1.9070949744199877}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0, 0.0, 0.08822245149130448, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.1392497846173063, -0.025703798913099374, -0.2928009108679597, 0.07385008175158503}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1122423351669779, 0.23458913498677614}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){1.705753464276472, -0.6491927650815752, 1.3738386579913988, 0.07253856580209561, -1.1766915993994496, -0.5347216411386309}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.6117727817066937, 0.3882272182933062, 0.5595941206949346, 0.4404058793050653, 0.3096003673168976, 0.6903996326831024}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.19245309526616117, -0.1007267717162752, -0.24741271709049728, -0.3391282293429366, 0.2085226101526919, 0.1939526887465638}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4311050959954692, 0.28700535617304, 0.47015239064175207}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.6263049468831556, 1.568474337969754, 0.10447447897116646, -0.7096429867093419, -0.7012449258890499, -1.231123818151091}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.39365206502012584, -0.08995276019689635, 0.6437634634453538, 0.48247870626347633, 0.501817011012542, 0.3543005163687433, 0.6900689803078808, 0.8780111091846693, 0.0851471936286966}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.08341313735953859, 0.36762794586161607, -0.413070703058539, -0.16278821055713666, -0.20121070553701637, 0.2857447897295874}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.48074888508443825, -0.10101488224752475, -0.1991277944805303}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-1.6592797813660138, 1.5549983835893002, -0.4475765747499345, -0.8850559539050873, -0.04379041940661965, 0.7926797458009971}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.7138188086526408, 0.5820633876425625, 0.6408533270907194, 0.5294767338214627, 0.5567401786381554, 0.4104825931950659, 0.6831979293268584, 0.44720620264356764, 0.5090458663672796}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4090870210918055, 0.12495621616670582, 0.1562811352590635, -0.4225211933617552, 0.49770154133447153, -0.048839712930975776}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.1440825778217557, 0.12304327791031056, 0.17758990750191572}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-1.6296617693109536, -1.585451749744569, -0.4004882159344003, 1.8292930432900052, 0.6604817649291679, -1.229201820638946}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.0, 0.5382448518336589, 0.0, 0.20882958353237718, 0.0, 0.0, 0.2606806871098186, 0.7456279380901604, 0.5663465639847136}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.44597852125871407, -0.05326063549529214, 0.170855847036408, -0.15698986565026696, -0.44620267034370487, 0.4484339033929453}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4493241722775465, -0.3060931160576562, 0.19377582745642852}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-1.8059492139663509, -0.4023502286155134, 0.6948654797150571, -0.37629903326266945, 1.931303217095754, -0.4705681160250439}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.5574227682911523, 0.0896282544473919, 0.35294897726145574, 0.4182199099499782, 0.31363824145740343, 0.26814184859261836, 0.30911582698276974, 0.5019018743910848, 0.18898229862614555}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.18485482658854613, -0.005290337693668379, -0.30058535812457854, 0.01533434155566693, 0.26204050626123554, 0.07305557158416864, 0.4423900846415795, -0.020771261450569845}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.18522796810606135, 0.10659578213198762, -0.49284453285042396, -0.22205936006551863}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.43120104209977583, 1.9225652423531385, -0.15916677598458184, 0.11971073229441753, 0.04295200061197946, 0.5602789459802269}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.2751085813383733, 0.2656897738845368, -0.4653825695346573, -0.45275253088227096, -0.215284025078743, 0.1562746697497293, -0.5258071394368644, -0.2949597064843916, -0.18025214830819075, 0.10227654836997851, -0.44065787021996694, -0.21469552135146486}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.060712449225317044, 0.0007247785453028399, 0.4899792434831428, -0.32831014279691206, -0.05516653394341031, -0.09383870195472521, 0.1876556015523856, -0.13446900679886853}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.08012117075403102, -0.3920231975647892, -0.2944272266042637, -0.024175687045254413}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-1.6842557520399453, 1.1064920948718546, -1.4430003499394073, 1.5499043731309485, -1.8205072267728655, -1.461503871792368}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.5456669836597466, 0.17071814997167245, 0.4242515090975006, 0.3801233723686573, 0.5421131379286414, 0.16687860339923802, 0.4108959235239927, 0.3767474165022145, 0.5472558763022033, 0.30912623396084016, 0.48579119501445417, 0.45778149229232096}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.04104597504357366, -0.21266824445894017, -0.36120308595814765, 0.015579241043764402, -0.2881238859579399, 0.30260033653806917, -0.25522088682909605, 0.3620418008171945}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.37538597560737186, 0.14315796694956795, 0.3009778430456733, -0.44723375475768445}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.7219153277280514, 1.3488062497449094, 1.7600140295416682, -1.8020721195525717, -1.5183921766618513, 1.1626054972059352}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.0, 0.42492938881153947, 0.9171281177007398, 0.22533835901171995, 0.08009903037918176, 0.0, 0.0, 0.0, 0.0, 0.7097184181343145, 1.090267712109146, 0.36120343097272134}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.4598559463859647, 0.20581915500491854, 0.3399104078779168, -0.1350263605478541, 0.0727292502586494, -0.4071033388932175, 0.29994905327082244, -0.2639013042128686}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.1011405037920664, 0.2681971566805672, -0.167051922865609, 0.17395189850755088}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.059745235397542285, -1.4565306388749573, -0.7216125644973732, 1.9883720048748499, 1.6467206073751206, 0.9405431215750442}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.125401715927453, 0.284157789196415, 0.27769735131736584, 0.31274314355876615, 0.5263185602797047, 0.2171080567097293, 0.09918205895885714, 0.15739132405170883, 0.10939701112016548, 0.428689577274566, 0.13832571153227188, 0.3235877000729967}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.27587546222889825, -0.29286023424237684, 0.03669230348416119}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.27040367212969396}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-1.2808956923339232, 0.1248973655973229, -0.23642973396606637, -0.23616627569268012, -0.6719533472284462, -1.1496400342073154, -1.3377534566564369, -1.2700200643465012, 0.9933243176756958}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5785187400228695, 0.49016162623588516, 1.0478427561924837}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.02506626358978592, -0.23950211687464606, 0.006264668912438931}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.03872119809042529}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.9473568649941653, 0.07726221987418125, 0.410374377067094, -1.4545673887177135, -0.6567119382779651, 0.7404000581493526, -0.07150514552809017, 0.20812218552829265, -1.6670741553286206}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.492273588381405, 0.5216715370458622, 0.4748205834092708}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.42645249550303777, 0.015020150226135565, 0.004145963329778679}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.16058438703252342}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.6681980653958988, -0.6883889941633083, 1.093691981572782, -0.7130595883353532, 0.007581965692961212, -0.7160844001802182, 1.7813596663101365, 1.6896828674768667, -1.3233456224524263}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.0, 0.0, 0.9401424101996589}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.4233968634132712, -0.11580552244210807, -0.2034745968476398}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2720208012301182}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.40424259128199536, -1.5413514157061092, -0.7813370063424587, -0.4447141984142444, -1.7637520696422837, -1.1318406978988325, 0.20628748734726665, 0.8582948286165175, 0.18149543196153317}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.21404436902563562, -0.1688276058675231, 0.007758140959803317, 0.48033782270569614, 0.055846644697828074, -0.30972813784319797}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3077728456909936, -0.25339810409167207}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){1.5220789433725352, -1.0740362729644848, -1.91813540288206, -0.7846682448745366, 1.5657332618203053, 0.38527603588478776, -0.5419734495673301, 0.23410682940669103, 1.4653770864978788}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.1484262263935365, 1.0118331658910238, 0.2143766928341753, -0.6621938203667614, 0.3956241172026281, -0.9545228861370071}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.10496515090035752, -0.0029858812713741134, 0.1087504073831993, -0.04631113640077433, 0.0282135037667538, 0.2418161178501691}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.48328931917276174, -0.1961387345548139}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.6180202472613132, -0.37644933655010737, 1.5425847860460635, -0.10044855993346458, 1.618959711449305, 0.28171531078178713, -0.05756318338937838, 1.4993959883363148, 1.5834143941872112}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4379372227912469, 0.5343560162440801, 0.38508255477722814, 0.48058800735293, 0.42028306192393733, 0.5576735122060077}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.36675075548207314, 0.3703110061160244, -0.14195054260650697, -0.029887167273655257, -0.32799594849369385, -0.34341063673303773}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.19577594605567372, -0.14506343272513578}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-1.7171993167403468, 1.5700452161722995, -1.7168180231780688, 0.45455371450194315, -1.055204025589899, 0.8107988819030871, -0.414858029498693, 1.1592930394984853, 0.7743076964813}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){1.259116474267321, 0.0, 0.0, 0.0, 0.2757591238608492, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.24505351171195056, -0.36592537878361375, 0.29800394776448813, -0.4701365860842648, 0.27189798058389425, -0.08154127424086532}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2566043429204209, 0.4916187076455486}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.31293725364590363, -1.6947615691119817, 0.5333677207674792, -0.48640073190372446, -0.7778545961545746, 1.3522334363198407, 1.0076330069096238, 1.054703893587631, -0.1097710842582531}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.6811327310390971, 0.3188672689609029, 0.47833246212392233, 0.5216675378760777, 0.3225774922908044, 0.6774225077091957}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.22580490277039444, -0.0037011434276867927, 0.20434172219322444, 0.27872329790271577, -0.39127166431326077, -0.17953685381772921, 0.47422772739527663, 0.15734991127591158, -0.04801415415547028}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.20456638919142345, -0.1281030007628785, -0.22947680136178594}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){1.2689475349249912, 1.822587978023945, 0.8756630750243799, -1.52195375656565, -1.5423062645236194, 1.3119484076661512, 1.3805682702421005, -0.6655964762197146, 0.9924401613741631}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2541570268482981, -0.6447585839760683, 0.6170331390716682, -0.27443691546818505, -0.18438932153091914, -1.2569033195113986, 0.3124330946108559, 0.33894299733490024, 0.27284423057212315}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.047101949249179986, 0.13440011330487733, -0.22113561076881938, -0.044659576683930724, -0.227572365560073, 0.2635718046780309, -0.2358897644109098, -0.22556094757404455, 0.09250562702642096}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.466458363684778, -0.41423476381982294, -0.038414030360428786}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.6226382059958553, -1.4855605129718348, -1.0969072172466077, 0.24118758365799753, -0.06911505765591386, -0.038671665148936274, 1.9782257407118649, 0.25355770075769746, 0.8077200093568213}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.38867621729010754, 0.4164243450743054, 0.5846943061784784, 0.38797425895219656, 0.39664353773079225, 0.4791881811774311, 0.37336270514332187, 0.4140149984751739, 0.3804753016312665}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.14571560605840161, 0.375139142482784, -0.0756167393564775, -0.016640608767385046, 0.09718402955437566, 0.17533168647380293, 0.21301632182197194, 5.110830004906308e-05, 0.32772238535510134}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2528034620847802, -0.4851091325020923, -0.46530638187622175}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.41805918464449476, 0.12668689488433005, 1.3055345973937156, -1.1678271469320554, -0.5055283703666746, 1.442481233402912, 0.5291172706233254, 0.29855260001658346, -0.4751675374407256}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2625261532822638, 0.0, 0.05160643511395746, 0.0, 0.0, 0.0, 0.4778334920351667, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.32056868816097384, -0.11292499209484808, 0.15727019764991712, 0.026997382531738112, -0.32165256505295503, 0.04618366858178591, 0.49996720346864754, 0.37492006937048883, 0.0692640069431335}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.13795730321207167, 0.3383452355566382, -0.09441490374502604}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.7754523745074895, 1.8374148376786001, -0.8174001559667925, 0.9783753760305962, -0.6335932167820655, 0.8880584955127571, -0.7773443148652874, 0.24408119719259025, 1.962384374137403}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3569933724564661, 0.24860547972915892, 0.394401147814375, 0.2514815399134727, 0.44648448106496674, 0.30203397902156054, 0.4740087476497602, 0.3378135969414297, 0.18817765540881012}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.1675905916070931, -0.24257904345037362, -0.07811015603922511, 0.05644917717368636, 0.2841285165686305, -0.2597707238180891, -0.056906484617325725, 0.498538935024902, 0.4808410119788832, 0.2232110898882922, 0.10065570122539758, 0.15296340523269736}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.14321345129869445, -0.3317907976271086, -0.24258540666664308, 0.3995005779579175}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.7754515969016125, 0.5498850532714683, 0.44950355224006877, -1.9899797242044475, -1.706446274275704, 1.0679679576486771, 1.2293125398643756, 1.3168093267177623, 0.5376554855017952}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.1046704603501925, -0.24854703169891174, 0.2035652207540814, 0.6966966337031824, 0.1402405331295746, -1.2064003735377145, -0.466549770840223, -0.05308849599669768, -0.012192033625032461, -0.0279211902919827, 0.6024662653110916, 0.8886827498597032}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.12067934746804487, 0.37879167213414133, 0.44408378175592034, 0.08958608526972023, -0.1634869901867877, -0.30288446506949573, 0.09665210395180501, 0.31312609816553494, 0.27247771774338303, -0.092860965081073, 0.4913674848223317, 0.07756526512990691}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.18154684411059407, 0.14304240346093433, 0.4638026622521837, 0.3225674934308641}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.3957377477075208, 1.531887953254155, -1.0484841474415765, 1.7386502410734836, -0.14622677895641312, 1.81044142554715, 1.8721011615472842, 1.1384383450909494, -1.0532294301781833}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.47136820160327414, 0.5435681322223666, 0.6501137637498362, 0.7370535330691627, 0.6850052480157133, 0.44382636204028, 0.74637368178634, 0.5571716254878702, 0.5019714793849828, 0.6091268824397238, 0.67133701042633, 0.6516772517169505}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.008698556254505885, 0.3544452337681895, 0.08340715371247553, -0.34178155712578917, -0.025522834976193787, 0.38461223195757, 0.4605685942522988, -0.373359847841762, 0.10916399211482297, -0.10135615449189739, 0.3062193302221733, -0.3691159339772899}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.43000357886710316, 0.10324754112833667, 0.14168512977118264, 0.2767607830158837}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){1.9079156114888578, 1.952207604566846, 1.4789887759950893, -0.6897908636175623, 0.784764837108471, -0.5585839897343652, 1.2559977492812249, -1.0833738794070777, -0.3084057210658693}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3687092348006924, 0.0, 0.45298752579065216, 0.13526717527205281, 0.0, 0.1041376781265523, 0.0, 0.7931677462326346, 0.0, 0.0, 1.0909797546102526, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.21380998115900263, 0.22298592452158383, 0.3395641331230028, 0.4114566408220265, 0.4137334653294986, 0.2148656100821491, -0.45819559184859804, 0.11650838120169715, 0.19248604463269736, -0.2825157842756675, -0.460079836647033, -0.05114827891201068}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.28919556695755655, -0.0240017294866548, -0.4126626798623715, -0.3379119620820472}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.18240858282640815, 1.8841966560318908, -0.536794599593335, 1.7906391499946106, -0.8731981059788656, 1.986389010947165, 1.2384423829391258, -0.21284632316129448, -1.4066260934023704}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2321921845510518, 0.5196505771007438, 0.17378977118769917, 0.07436746716050521, 0.20787102317813155, 0.548659685860537, 0.09718981692423631, 0.14627947403709513, 0.14683611483287426, 0.4751696537930756, 0.12063141256921503, 0.25736281880483525}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.09635890288131788, 0.46300791745497627, 0.4720325022052063, -0.20568243694009747}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.16710648767084302}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.09732748112619438, 1.497602293840087, -1.8045164479295845, 0.2506963894796881, 1.3806022241936313, -0.41303737038294974, -0.9457658305731091, -0.49558556077887417, -1.2857271006530588, -1.780103832819242, 0.3182089356425939, 1.4159020674616012}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.052224420890903844, -0.501665366312338, -0.6742256555813042}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.1496122295427741, -0.2923789264725054, 0.34401103231201435, -0.20695489193597327}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.322455983486838}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-1.352871394192615, 0.5451165133804832, -0.30345683181017424, 1.88309739721109, 0.5485660640488326, -1.9574456669528897, -0.02482725296623345, 1.6922596070781326, -1.0809340111913492, 0.38594274106094906, 1.4764651437470908, 0.7696959770121525}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.36971505594988535, 0.649782154924381, 0.5978516178896188}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.40190595851157873, 0.4223542364817787, 0.40989448408489026, 0.34792701575297424}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2819878903580715}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.9892722697833447, 0.5246489859053587, 0.3829178029693199, -0.7890787180014929, 0.9402559778829476, -0.6420106932173217, -0.5838718310486968, -0.9753318855120634, 0.6735363654685749, -0.3078737548604247, -0.5922575395458116, 1.8328790285638563}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.7835841237838559, 0.0, 0.276202859162082}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.46031807166630856, -0.24100853920499232, 0.006287077471172631, -0.45233607015431043}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.363036600112449}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.22674424265325532, 1.1200777182335107, 0.6350974071818709, 0.5685125092986301, 1.252312525313327, -1.4032204443178484, -1.6458243133656478, 0.5749478658998548, 0.47269296049637166, 0.5140796423576126, -1.5460078877928476, -0.5958087989334286}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.06897963971607013, -0.27024988518254933, 0.4078334068067516, 0.3676830359786809, -0.20973397667699012, -0.04853632958984444, 0.44426546496022956, -0.2623834546174655}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.15930110679138898, 0.15846676813060034}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.9778948997278052, 0.45840359387622565, -1.8696072036641485, -0.8706155090326191, 1.955109194213167, -0.9831277499698534, -0.891245293116051, -0.11124967788040951, -1.4578949011913402, 0.35029687590022274, -0.778389895813151, -0.3011844636458094}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.9797264027495545, -0.6710470546043302, 0.15546977265620004, -0.5706280752404904, -0.464125469744858, 0.1804488097763034}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.34999393437150095, -0.3863429274162232, -0.42230643099933707, -0.34151916691890893, 0.07397792272615478, -0.4070696496950792, -0.10254228007867039, -0.4728894291067638}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3453419517863243, 0.01779906672318765}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.9773098691936357, 0.5058134938288168, -0.12865366766436015, -0.23833194593368212, -0.43008772864065126, 0.6991725079672451, -0.6896119612132865, -0.6782612938428709, 1.4499623859346902, -0.45911872968750833, 0.2244142378864864, -0.4219111140251095}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4859032764269968, 0.5025235278813972, 0.6788771651606706, 0.5231901354209845, 0.5161344817976101, 0.6197442713170135}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.18051173120493302, -0.1436962434003064, 0.06874185186811521, -0.17616139809470455, -0.46810339061253425, 0.3717648402691619, 0.04414392582940618, 0.32900164894286066}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.10819618797547437, 0.07122344486681687}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-1.8278985423093626, -0.4783752166125703, 1.202297847020089, -0.9934407514677823, 1.8382635367762834, 1.180773113050925, -1.1191619757482933, 1.8063001755868333, -1.3140654146870192, -0.3629268353200241, -0.7556085321336963, 0.6115990760000121}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.1046338714032992, 0.4752563658486149, 0.0, 0.19456751123527022, 0.0, 0.7192800615036928}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.32714114560450414, -0.26883312572955287, -0.0023939398590269167, 0.17045845458906028, 0.12947320668857876, -0.2554448928598232, -0.47462227215316544, 0.07789630367493039}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.43440269050460145, -0.17040366353010472}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.2271565751283786, 1.3325991787267872, -0.9940714074180175, 0.907328659500171, 1.1446319487668952, 0.8621275126121497, -0.508630213308146, 1.5381935621874332, 1.0301105212771007, 1.227510966799744, 0.7371750813135272, -0.9412151547691368}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.32911596374458735, 0.6708840362554127, 0.46329230202348526, 0.5367076979765147, 0.5459154395676186, 0.45408456043238143}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2101639268275154, -0.4791196756281011, -0.2673243106822438, -0.05410293760040252, -0.04205707994181673, -0.08838584561602092, -0.25694470479905307, 0.32443381902525414, -0.43827267280463034, -0.22399608346147837, -0.1841762648272136, 0.11398480944425826}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3156984463411472, -0.1285099988066064, -0.30445234891067574}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.44378359099595643, -0.5826026872724062, -0.7684337221584596, -0.9746707598573208, -1.8358961834576868, 1.1957745871059724, 1.7140915738704137, -1.1379599806671146, -1.188961866495179, -0.9798965841408731, -0.5307428798717009, 1.7577420752439652}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.7597211211243349, -0.17712310668559916, 0.0509761837063013, -1.0397112077258714, -0.9666065701739739, -0.21308318100814516, 0.5820907498696928, 0.7147458005915032, 0.7342362799230319}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.011274874728777085, -0.05064093629342925, -0.42873603328999355, 0.08109866104489938, -0.11936036948078621, -0.02627697929754713, -0.0830345329487272, 0.48272341823825804, -0.3023845822123018, 0.4415356946373311, -0.3033363758370935, 0.4673644570748312}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2702438693634521, -0.4829814430481377, -0.1358900628800952}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){1.4575301780371, -0.46483570608873004, 1.7058622253408706, -1.1196827834890501, -1.0465545080593244, 1.7454518220568995, 0.7224155436910031, -0.3263609403714747, -1.690076997984038, 0.7643656478761263, -1.0368243409072422, 1.6566354327618948}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.25875681725595573, 0.2096757724233148, 0.13912023681569, 0.33034436439026305, 0.3494501480785717, 0.6409723121872031, 0.5623899867263433, 0.6420908210475418, 0.8583213306227215}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.3553265948376243, -0.3946328962889232, 0.40934480203108325, -0.256155778923876, -0.3038932247277527, -0.2602436763852628, 0.11071185266252981, -0.000439230781875688, -0.3579529020046105, 0.42395334377477567, 0.29847638909909324, 0.3641833499531587}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.16799104581960023, 0.02547965097462601, -0.09257509020977095}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){1.7881572157171357, 0.8194885506266445, -0.37520280121180694, 1.7747137663376802, -0.03851597310520516, -0.6566073917873658, -1.4797995450361423, 0.2391855274530692, 1.0619665439578867, -0.8008357159426853, 0.47398989353997045, 0.7992937557956563}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.0, 0.0, 0.14910578375438516, 0.0, 0.04412590897922032, 0.0, 0.09596379248866616, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.4905337389552422, -0.1949044404303023, 0.29166550152871795, -0.4790118619403947, -0.3276595971053865, -0.33024969776171964, -0.33053740071251503, -0.35762208724911904, 0.27477059219693245, 0.15513755905920323, -0.19889519596616567, -0.3019292539206302}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4368365125246999, -0.2501277395283752, -0.07785904527510057}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.04229824180351027, 0.28156547102780927, -0.17716407472504914, -0.6413724730114652, 1.4122946603259954, 1.384561377059479, 1.824358728326438, -1.9656672740917296, -1.634809931465623, 1.7230091049292366, 1.2699269084794094, -0.5284246680114881}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4616884885621197, 0.2390808249192954, 0.2992306865185849, 0.8066597273378548, 0.026823559238065422, 0.16651671342407967, 0.4157433055336609, 0.2685925870473668, 0.3156641074189722}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.4485028975817905, -0.3693827989582962, -0.13531440033323328, 0.10934137498501217, 0.2981186285828783, 0.46808959329632593, -0.14763584007805208, 0.461272998469497, 0.41710947686958966, 0.1841984657036705, -0.1858813949912993, -0.2844881151591804, 0.009760971144502806, 0.41047118785922077, -0.2985434316739297, 0.48212937073420614}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.10145487101982298, -0.03650161724016843, -0.23722985821720144, -0.4407160552301037}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-1.0453019670534545, -0.5708896500884872, -0.8444883221861876, 0.09912641255573229, 0.47514869728133036, -0.5871140735556968, -1.8069205253663094, 0.14492459149292847, -1.8589271054240117, 1.7427155426992815, 0.3017540572311024, 0.9724710249467119}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.906262698088468, -0.4449520298109616, -0.6496178313866668, -0.38534477375350257, 0.36556776474747454, 0.16394310344368807, 0.1474572388185536, -0.06775489718254984, 0.3569595689438469, 0.6290895049341786, -1.0243473556125724, 0.6352436813941211}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.10000185295617814, 0.27945776190301164, -0.1675197011433116, -0.38306868234210323, -0.21270246898829914, -0.17596559072131712, -0.3837049316679134, -0.35164942445852143, -0.4365157015097402, -0.23030657953717326, -0.16394758311591362, -0.28650242986118823, 0.00218602108510757, 0.4512012157451245, -0.276850029444732, 0.22622928747030857}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.14132908848490278, -0.285438201846102, -0.32355947118520967, -0.23461803762171174}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-1.8254590574096268, -1.217520653648399, 1.7168663681024587, 0.1994061416732591, -1.9675191418259725, 1.9199285057794429, 0.9484550927617552, -0.9055837652034868, -1.442112420370441, 1.3866624204777742, 0.045975108763919526, 0.9713595873573695}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.4060394913849569, 0.3984786856722109, 0.6023050166980632, 0.22826071373106377, 0.7431946220761522, 0.43775894830777895, 0.5491102502420432, 0.5398914372735755, 0.5727934120579999, 0.3584906645180179, 0.425741662192613, 0.644492083447468}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.0970299556957368, 0.09119962016347183, -0.025897176492548857, -0.4217669739314174, -0.4528777614465802, 0.1454996651048469, 0.04496025291683314, 0.10592221498226928, 0.12299645407625648, -0.1417115087114188, 0.24824049645874624, 0.32302994110983807, -0.2464160801910834, -0.07292514518529303, -0.056209136249684266, 0.2597600387827279}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.05132742575752358, 0.05418293624842707, -0.09495761848183204, 0.34292324463359614}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-1.633996640795076, -1.7137782803834587, 1.710463930178423, 1.4817341533958484, 1.897736952783748, -0.7376620079534066, 1.376002348298345, 1.5850196319882337, 0.1652684061217693, 0.4915281245814631, 0.3773305260915727, -1.0416481629546168}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.0, 0.7786809657316873, 0.8501796059520266, 1.1592954428663107, 0.0, 0.0, 1.096580797995299, 0.2634653101237924, 0.5096796162554853, 0.0, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 3, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.15765230419372567, 0.2330184085744561, -0.34730429228434256, 0.12967893499701433, -0.2181817225794036, 0.25231223493627974, 0.30835176589957625, -0.2973244495258771, 0.21579682751391616, -0.4113052624081939, 0.34093022903274783, -0.08230492744338469, -0.20608382345776488, 0.13194425917962838, -0.27957841667167305, -0.12365402993452301}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.09966541331562273, -0.3347004354871468, -0.4812750659991518, 0.4040551905972658}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-1.9349812408599654, -0.698099096701724, 0.590315008480832, -1.9164107123321288, 1.5070705458424882, -0.004797204718388404, 0.7006286113901221, -1.3573692246907063, -1.896382886609453, -1.2345978179423476, -1.6265018944228173, 0.6283174729246697}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.11909347992928718, 0.3485861724589001, 0.13949197855495832, 0.39282836905685437, 0.1263860041132765, 0.25774319293963915, 0.32818366412064026, 0.28768713882644403, 0.3321456565663109, 0.07570058620071538, 0.07071332891976292, 0.5214404283132108}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.23774893840943456}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.460992341529301}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.6955620151604585, 1.017297681362539, -1.1106354765569977, -1.4845776972991716}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.8641104106410615, 0.702853785319624, 0.19693993601801835, 0.10803557001010011}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.46443735156264554}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.037278687168519675}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.8105233332785042, 0.5812341269150942, -0.30130819664880093, -1.168365769520305}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.5839861279652011, 0.5579060471378082, 0.4558112220151474, 0.3589529828909607}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.1841293949723699}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3314241688680172}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.7977970002053207, -0.010084797029566772, 0.4550714142380756, -0.0907345541639053}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.47832204782659454, 0.3295672612925439, 0.41521619304089474, 0.3147172703067296}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.03719999210851932}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.16724610376931603}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.0500159691095057, 1.5140654220341823, 1.0026732990719407, -1.2986995298824158}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.12092386871819205, -0.10113733378530287}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.11502183310731662, -0.054296435246178}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.18048718000864694, 0.862348609699962, 1.1410130778527607, -0.14414044871037301}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.0931966250466343, -0.07255042741468057, 0.010743303038642987, -0.14151207442469493, -0.022953882524690855, -0.16969545575436845, 0.13245185380415106, -0.039718454572993674}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.0840195947782717, 0.23652871473402026}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3809321214306671, -0.01711814460158978}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.5715480110580189, 0.6380682374224631, 0.5963254006589978, -1.9193602981343285}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.39437628871195696, 0.5294831004605411, 0.39304218210394365, 0.533401011303945, 0.39387917681507384, 0.5309428907636995, 0.4453027091314272, 0.3843554555034177}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2536798899348677, -0.1868977187551243}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.013720090289576214, 0.07954661673762742}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.47120697753140606, -0.9892829362456337, 0.616401153087561, -0.878591990392303}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.13325582448628498, 0.1676141258997443, 0.26468127667081126, 0.26444134072530745, 0.0, 0.0, 0.23660120970995194, 0.2437534554584729}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.05396908297202607, -0.0981346101696241}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.05224715948872716, 0.2943568311875845}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.40450436974630266, -0.20496593498440374, 0.5632871938893431, -1.7220546873840021}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.4098781454466421, 0.590121854553358, 0.41201142951514097, 0.5879885704848591, 0.4202551381440459, 0.5797448618559541, 0.39588054405389134, 0.6041194559461087}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.02249840717072049, 0.285691563254168, 0.2943841832964901}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.48840734471549796, -0.4377279224290719, -0.37059271316769227}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4087586389011908, -1.2962093443785894, -1.2514149009033204, -0.06036786682417228}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.47921092642294943, -0.3209490278877447, -0.25026063508938035, 0.5175699903238201, -0.8080439963292513, -0.7521762423938622, 0.5165621866955277, -0.7952466017477012, -0.7389894667351743, 0.489765525563336, -0.4549745126723891, -0.3883640583400775}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.25984862429570454, 0.08163577451748816, -0.39009408187553973}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.36134296395646837, -0.4566066428015011, 0.10759299537726574}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.2599006000909876, -0.6494510262946638, -0.7691016414956948, 0.4848781059650813}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3943943397912801, 0.3827661276890996, 0.5520553608892608, 0.37049311719754, 0.37528141956272165, 0.5892679618142639, 0.3632714750298628, 0.3729942163886697, 0.60051586153152, 0.4414330658797748, 0.3972292808877058, 0.47962252231102537}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.4654904154548284, -0.3185342939030211, -0.3371953439605684}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11132559125995689, -0.49481157680043397, -0.13088202817376582}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.6210224418746697, 1.3394213256719096, -0.4089614499754508, -0.2667448294643795}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3016932265140385, 0.0, 0.007017868617319095, 0.23549275274775827, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.3507770741835319, 0.12166253778439151, -0.4804812485061143}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.33481774650992524, -0.3130823919349255, -0.22106949979705548}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.23487514692678202, -1.5865184347213805, 0.6992092604710924, 1.5020874124939683}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4445841999283178, 0.24544002870460285, 0.3099757713670794, 0.25660836158423844, 0.1930878631767131, 0.5503037752390485, 0.566107525470626, 0.2523166611400799, 0.18157581338929404, 0.6513084874162498, 0.2415153899053923, 0.10717612267835784}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.0017204926508496143, 0.41442213064230404, -0.32320118101506723, 0.011099298204262475}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.294054545822078, -0.22779392380188068, -0.02103757757169833, -0.3640311736171502}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4271371535163353, -0.0788534191245347, 0.385086857245414, -1.7336665310616568}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.2933196594885483, -0.05077883456515209, -0.15908881004359196, -0.3592902509761526, 0.29419021255017613, -0.26047252576390095, 0.004447940616427372, -0.3649063912304391, 0.29339200671424853, -0.06820540793988741, -0.14549810462679674, -0.3597569797540411, 0.2970373063477935, -0.9462637014277047, 0.5392854927537238, -0.3832736554321528}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4956996836549935, -0.028798726592954016, -0.4672312051326196, 0.23131517883566421}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.022912028864770728, -0.49853977792531756, 0.10574837045144436, 0.410111062559837}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.3876554579489513, 1.324870034257906, 0.2998224368857927, -0.602763978429429}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.5535618737902224, 0.37526297332527664, 0.48116482788854403, 0.6224080177428215, 0.6636605064047565, 0.36895689572151036, 0.37442674704067064, 0.6718520571943345, 0.5427786375916206, 0.37585617297462237, 0.49141633638490323, 0.6176214264660639, 0.4314646559436077, 0.38197330156317094, 0.5956514701059533, 0.5672604758398885}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.002015814243424563, 0.498131596849995, -0.3449308644639604, 0.3681498893505265}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.46035714368331804, 0.268909276901386, 0.24961413614912054, -0.3840004223422129}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.7212402945556935, -0.62827598112067, 0.5662147986048618, -0.5910025743286171}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.0, 0.6281818565409744, 0.0008360978617837633, 0.0, 0.0, 0.0, 0.4663259134390161, 0.0, 0.0, 0.5509587586905241, 0.05430917619405834, 0.0, 0.0, 0.0, 0.45346916501271645, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.36462501954166304, 0.23193245190261014, -0.40829915189462485, -0.158348421769264}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.42214856054998506, -0.37891064889767856, 0.38383080311614026, 0.11387583603992835}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.9384661370656282, -0.966630073423671, -0.7979441631120383, -1.8511801590618515}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.24678247695080335, 0.2275153523072984, 0.26750104978399003, 0.25820112095790826, 0.10259742664993522, 0.1217920873755382, 0.4848909223587159, 0.2907195636158107, 0.11231450486848696, 0.13037594826727797, 0.46592874279717567, 0.2913808040670593, 0.061733916618178244, 0.0824102021769767, 0.5780351825284229, 0.2778206986764221}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3555769535264288, -0.23393816540539603}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.32970139958880174}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.24871904705476489, 0.06995952088304591, -1.9064915449891413, -1.802595625878268, -1.7115275321806576, 1.872629535307479, 0.5109986798382131, 1.036172638119552}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4017739586565113, 1.4293017687656886, 0.5002016273844159, -0.09439828024905433}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.2977735427160658, 0.47180392956152606}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.48538500987497246}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.19342755819646618, 1.146624791219426, -0.3422389421101748, 1.7401594643346439, 0.4966025639075329, -1.2988734490122051, 1.1467155631032155, 1.4635284334832535}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.747243532766203, 0.769322456471979, 0.5051114512778931, 0.8201471902258292}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.2753702941734161, -0.29328984167102756}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4548437469991301}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.24925363493456532, 0.2986670739289563, 0.8577463665092679, -0.811808981849806, -1.2145323386384872, -0.21656156721855702, -1.3568491596415404, 0.396891022760991}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.0, 0.0, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.14993997578290175, -0.151891076453598}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4259506666556403}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-1.1414511913662846, 1.5744340955800618, -0.3364537702834278, -0.8227686217069947, -0.5746966448690927, 0.5797206574616864, -1.162282495160425, 0.18407955736456527}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.1478353705768115, 0.4606857185785145, -0.17772432323418397, 0.3110209582075404}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.0775535170235091, 0.18075397461693343}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.06315849025233211, 0.9519737548241629, -1.7966115873205912, 0.7068467257630795, 0.07125945944018275, -0.7671600112144734, -0.198013579710834, -1.5538942697622526}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5067771715210396, 0.4656129640941862, 0.6687904486006767, 0.719899699040874, -0.2864008126009745, -0.07051340637253978, -0.6090299703011581, -0.26734788067244253}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.058100773517139936, -0.07935905597459503, -0.16382663726515323, 0.38309376332126466}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.11494098984778289, -0.3662775615143631}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){1.637952226400015, -0.529769429968812, 1.0259871964034417, 0.5296875656608928, 1.4290928569573214, 0.1364820106140856, -0.6789604826836766, 1.967436673394979}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5154492557099281, 0.30204699988636124, 0.503323659781108, 0.41788990329191317, 0.5052694313769737, 0.3663017072776441, 0.49956380060787386, 0.6221460132222479}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.43213594212711615, -0.4042024986789897, 0.26958001573651946, 0.1386924632131119}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.465926405495812, 0.23455002258390223}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){1.8629320948672512, 0.10891280801417125, 0.10155532831625891, -0.6902153078410844, -0.16123681967435433, -1.511122313675774, -0.057198112784635935, 0.034114865821794016}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.0, 0.7518646716532251, 0.0, 0.1661996483976504, 0.21454923447706897, 0.0, 0.0, 0.22386202921233028}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.49256553961472627, 0.16835372489232558, 0.49060671079422813, -0.02871348397788198}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.42678136183330195, 0.3104555517085237}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.4749947660939733, -1.0333002406267102, -1.802501775934846, 1.445663964489833, -0.36696480681968513, 0.4103947619496022, 0.8262970124553854, 1.7609656815874688}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.47842007679501986, 0.5215799232049803, 0.5981320459717462, 0.4018679540282539, 0.5489631661988189, 0.4510368338011811, 0.6141932392665497, 0.38580676073345027}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.12830626806907686, 0.31061217535544594, -0.1916179480901501, -0.30187910565123033, -0.3943568832510146, -0.4418028029998381}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.17875931959728253, 0.3326916355922088, -0.04785819064355634}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.3433787619377555, -0.6581495797145109, 1.2496656200158363, -1.0161776840870869, -1.136101780764517, -0.2562630897588023, -1.8079387760713974, -0.9315500093467914}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.06972760054552757, 0.5971707758814073, 0.37832791679984534, 0.023462090633794397, 0.39999608414091736, -0.09172228048338929, -0.04660809581253467, 0.6277495999916793, 0.513389118035504, -0.3425613325134058, 0.960340637826632, 1.0766763154605519}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.21480444635363716, 0.10673321465812224, 0.38608437473359547, -0.4599605583350379, 0.2662250597189436, -0.3033118272548895}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.45040247546217904, -0.2229068539641681, 0.06410414908246698}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-1.7667431865263268, -0.07829137375173678, 0.07634304255314417, -1.5994513238443662, -1.7984945913362536, -0.014199967091892418, -1.8782951754557322, -1.3687329035529014}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.5156303788526359, 0.2954607900274566, 0.4055239579652134, 0.5734856051962636, 0.632336256898284, 0.6386618913559144, 0.5156354586154465, 0.28684718864115016, 0.39881785180320545, 0.4752320527995354, 0.42103547272327413, 0.49480213271576645}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.2925253088974452, -0.30397899404744855, 0.15713053739652427, 0.28528313326655186, 0.14338954650803015, -0.0322261432048454}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.36442305712872225, 0.19296644975904254, -0.48697577748179255}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-1.7675832053696143, -1.9000831249192611, -0.03726522976895774, 0.12816724559374792, -0.5914166565744896, -0.6423920390603253, 1.5282041307160807, -0.9126225635655287}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){1.4590712372008947, 0.0, 0.0, 0.3363639295926011, 0.22367489758436931, 0.0, 0.732701083097916, 0.0, 0.0, 0.19480276055030207, 0.1727381616463216, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.14055318701460862, -0.22487806274644828, 0.18064704114146213, 0.14436315111569997, -0.04586982021793684, -0.42158492645533974}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11265961375713474, 0.4240637687711114, 0.4255982500058494}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.680556924307588, 1.471870581203376, -0.9379634705499291, 1.8504827780603814, 1.354637717952604, 0.8049306908213003, -1.8005855698162083, -0.10070138550372709}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.23159735667226392, 0.5595684812071928, 0.20883416212054323, 0.21115562690713965, 0.5498621011115644, 0.23898227198129593, 0.2599306138216434, 0.5043876467990472, 0.23568173937930934, 0.23951918200458552, 0.2931434687272843, 0.46733734926813014}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.2782195380457887, -0.10037047023330914, -0.15379796128524448, 0.01216115579362076, -0.13873454090039317, 0.4413236087127773, 0.1697810388721046, 0.08532820882291137}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.420964836307403, -0.3590311159365862, 0.4429377850816135, 0.22616513843237895}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.4456542836569035, -0.5501629869551476, 0.686502117728871, 0.030246209714708705, 1.7604065689080333, 0.15343819592466712, 0.8208616837952154, -0.2628019430120285}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.6001746829402037, -0.2971810134683637, 0.26196551274180124, 0.10355706893776079, 0.22693070795358025, -0.46424591319278236, 0.36104459537252964, 0.34530103606692475, -0.08421532994367131, -0.627912071462462, 0.2664244862859734, 0.5381414009621328, 0.21896263244075453, -0.48847394477329886, 0.21307521437076254, 0.3431074688050384}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.37361778125427414, 0.3312395129361341, 0.2964040001364173, 0.07228826738376659, -0.4557394139729585, -0.2011403927654395, -0.20479058346501267, -0.1852122052336962}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.32242130314467266, -0.02901051020415868, 0.20066848290266204, 0.44683264459701577}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.6366954529413702, 1.6273717157182874, 0.9612848525390536, 1.4446623286070337, -0.17852678973405478, 1.4731135288953694, -0.025925167945447747, -1.6746985781626527}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.7501386440006022, 0.5688960417704307, 0.3972758111915883, 0.5037585059796784, 0.7613515504379689, 0.58912522966076, 0.37098187599291477, 0.4956004793143546, 0.6777987201299359, 0.5061402562620088, 0.49643194647950717, 0.5524450492149452, 0.4397957236022758, 0.4606426167665623, 0.6339808590563839, 0.6818564577725281}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.05619929714707139, 0.47560612976122585, 0.11876722589057354, -0.22859645270066575, 0.24748524257012894, -0.13981004303831657, 0.2833870385022116, -0.3027825840225393}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.024878955313623274, 0.051568898651169204, -0.45042642923732057, 0.19935549717530598}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.8221658565614605, 1.066528621851917, 1.9529006946652667, -0.7995913350670767, -1.8280088173430107, -1.3781630449692797, 1.8150893612620367, -1.1783022063776385}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.5285737380820149, 0.0, 0.0, 0.10942035236557121, 0.0, 0.4662932394028601, 0.14467857186607924, 0.9948845721190491, 0.0, 0.1495045458349571, 0.0, 0.09860526003270956, 0.0, 0.5364977314190502, 0.163519883806876, 1.0704976826867063}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.13621194867232223, 0.13774073742755377, 0.0643783143675517, 0.212050684828047, 0.4087705275186847, 0.19424806802923356, 0.36221382700791926, -0.23490642454483168}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1338187248277929, 0.16079782523888164, 0.09267861652615483, -0.22569474784139765}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.7967835653378508, -0.6675820652984359, 1.6838599342248948, -0.2941995264248334, -0.6340488607530115, -0.07475182416368087, -1.6955231388927023, 1.3761866473225641}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.2835569181138915, 0.2935417400222833, 0.2108989876628043, 0.2120023542010209, 0.22105265434269064, 0.196873284998947, 0.33016312830855693, 0.25191093234980544, 0.2861100433476569, 0.30592709870722445, 0.23002705053220537, 0.17793580741291323, 0.31020035810315194, 0.3987192168791191, 0.20269726359299756, 0.08838316142473142}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.49699044983846585, 0.4473957188099221, -0.03368035522415236}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3546522687326087}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.9470720302419027, 0.9401485186801284, 1.1212959124395976, 0.45704740404049415, 0.2002568453984379, 0.38725008688386575, -1.8960001842941594, 0.8391761640267967, 0.8108539909793486, 0.09443598182430835, -0.6880928710440424, -0.3349991464821871}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.44248524541133716, -0.5052491288573878, 0.9357756884153755, -0.6981529642158333}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3866222331206456, 0.46467777619080763, 0.20150218095601113}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.25545946220033533}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.42811043769133006, -0.016305481240862285, -0.9989844808606851, 0.24988248098404098, -0.2859889926894117, -1.2104124401462366, 0.1209216462928695, 1.080504552587723, 0.13990237725852372, 1.0303892982633207, -0.8036227142408632, -0.8050491136257496}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.47030202332618176, 0.4938193421678468, 0.696880651272832, 0.5295121823625077}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.15678478468444235, 0.30626325403682975, -0.32290086485418}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.32173679378182807}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){1.872331546876583, -1.2139223032278137, -1.7474057980691708, 1.5798780430684913, -0.537304969026164, -1.4525979774395519, 0.6865731040195668, -0.10128777513257381, -0.22937112400373794, 0.1327159972628178, 1.7901898264786098, -1.6185450613933337}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.8077489409300725, 0.8739260075685525, 0.4724244207727947, 1.413443604567196}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.2998557213449662, -0.016861354884377233, -0.3793372959396719}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3612456603349643}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){1.0313866126128461, 0.514907206135002, -0.05821068576165933, -0.30352019452667456, 0.7659449409911652, 1.1947344602853343, 0.6737312023384785, 0.8352977072302994, -0.5775431571855116, 1.3512839925829123, -0.0017711495017103118, -1.0347608965643977}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.4210886425018583, -0.14050493291177402, -0.4162104436265601, 0.05247135016244209, -0.4639239066920249, 0.24966866512830432}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.19561709744825018, 0.3157613957707127}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.8616795317844193, 0.9844011754439803, -1.5679871529938056, 1.6676447320257881, -1.8071493784248784, 1.6933258913093279, 1.912293094527561, 0.19556772620213847, -0.9623091015184997, -0.9458746386035792, 1.0782189211044622, -0.32687266547944427}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.6815257742967586, -0.5776165911598432, -1.3487098720814186, 1.6644151809767198, -0.6278171328893869, 0.08511502396737425, 0.18723271003287467, -0.3156913198064548}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.41618678892860883, 0.3140285522991426, -0.293896787431534, 0.07090837112149462, 0.18438454315916086, 0.36967689302442897}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.35714387433160244, -0.07467231780177941}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.6730615396504662, -1.6980766959037128, 0.9609946491066395, 0.43867713774814066, 1.8061986855204237, 0.029009757093355848, 1.0311907287027653, -0.44190948685341347, 1.0578280560281264, 1.2843046638327373, -0.6232626484352948, -0.5765238358888034}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3232987103717631, 0.4799508571240995, 0.7499578661890441, 0.5744896769921642, 0.5833758995507797, 0.5764021478869968, 0.7037815340749449, 0.4227115788496721}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.14391923460637668, -0.08685695047823938, -0.46999401415804987, -0.18160548088359207, -0.07772973381468096, -0.13523300587645903}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.0029107300303898853, -0.254842356558578}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.07476468508556522, 1.3393686936498228, -1.8852950277522922, -0.10182487474584612, 0.09856666442163053, 0.9664662903029044, 1.824037444709472, -0.25934750180989896, -1.748541594756266, 1.2906867129440132, -1.702320465228453, -1.1331370950100443}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.7560730913855738, 0.0, 0.0, 0.0, 0.5789054131968248, 0.0, 0.49176064234769096, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.07636082446470649, 0.2478539507536056, -0.052868620994010684, 0.3130117991738871, -0.05171123616726381, -0.012022356754146535}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.06616629663902074, 0.17517915962902286}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-1.9811897747651637, 0.22276688730658112, -1.9068862158569, -0.35839571585717556, 0.9312690078388846, 0.3119622663360615, -0.4197553829925331, 1.481322751026945, -0.9041771993856447, -0.6295255532426536, 0.36708346358086397, -1.7136413460223308}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5919729373074085, 0.40802706269259137, 0.5273981583712719, 0.4726018416287282, 0.5838686413340741, 0.41613135866592593, 0.521884422447958, 0.47811557755204204}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.3065185978038838, 0.07802788487787604, -0.4814158282343074, -0.36293732764227504, 0.3372731203085966, -0.26535538723445073, 0.19581201415754879, 0.30381027639677693, -0.05798197463671595}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.11631125961763966, -0.4948085687827227, 0.32370251742183154}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4034868227614221, -1.6473098336982135, -1.7614253418514458, 1.0778825639164533, 0.2543218600995294, 0.759992839159604, -1.3921455320562903, 0.4384667094359007, 1.842222245424313, -0.935283794235473, 0.1060210554589025, 0.7224071128737575}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.47945446299549954, -0.7294386220294922, 0.0043713484814918435, -0.7927306970009563, -1.0019046528549156, 0.5679645823739576, -0.5422550813387692, -0.33050755175267843, 0.0774987054645768, -0.16913500231638284, -0.3112957349002754, 0.13088640913048694}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.043265624479940756, 0.24543442335761467, -0.4871581310440992, -0.1382500076370351, -0.360259675972992, -0.34503316880735135, 0.3117595976207209, -0.19972612243358123, 0.20960012664609107}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2558819787506603, 0.2870270478601227, -0.18953579389644037}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){1.795729941264712, -0.3780630799869029, -0.5003491862110319, -0.5441204759705314, -0.16229605301025796, 1.0208116664126856, -0.9731117056481504, 1.5875024376355893, -1.8489895590358767, 1.055086483195145, 0.7254120640422181, 1.1222442220629394}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.6188181370416529, 0.5860367544968592, 0.5844178876513867, 0.4243870757080545, 0.5171199418074568, 0.4718314682594617, 0.8181937692218632, 0.6195430975121399, 0.23191546656503034, 0.4832217139932728, 0.375806305639079, 0.5571828017062846}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.2544488335808389, 0.22472032190679359, -0.2559828475196281, -0.15968040589832977, -0.4907046882630962, 0.4028569026091441, -0.24968397691805666, -0.008126383806841608, 0.21431830315341116}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.40166136966095956, -0.31667300058599024, 0.47268349748411376}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.8857539942668975, 0.9150822796849405, 0.1965019031805051, 0.7139750692228817, -0.7319217876823569, 0.7267209787920228, -1.9007973243322698, 1.433698090754632, 1.6794842530685066, 0.06174639618233346, -1.3599701612038957, -0.23846141938562315}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.0, 0.0, 0.7285197219802286, 0.0, 0.2212411857940908, 0.45611284718418876, 0.0, 0.0, 1.2955755670805043, 0.0, 0.24474521500405377, 0.41721140445046523}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.022575789328952545, -0.0019076238065343087, -0.4009768181258533, 0.4850060547553987, 0.48805828091353143, 0.08852239125776273, -0.2084619619495558, -0.1862560726720195, -0.3817846983117307}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.008990481241197723, 0.31113598298942724, -0.10330905042873273}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){1.8157221202737968, 0.982136597108874, 0.2834562674643215, -1.6878817279895486, 0.12993482148917357, 0.2250276514825318, 0.1371469820278004, -0.2615838425143049, -1.0985121177202521, 1.9574445644860723, -1.4120783360052198, -0.62978701848141}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.13458672285531106, 0.797869589394409, 0.06754368775028004, 0.3258725056489865, 0.24467225407627455, 0.42945524027473897, 0.3759565406107482, 0.2834775568771604, 0.34056590251209135, 0.3339374209654022, 0.4182633255972828, 0.24779925343731501}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.36731068929749466, 0.4139080071200977, 0.24163000077936114, -0.4921708499084284, -0.2543680807743145, 0.02362294341284954, 0.3259572898676497, 0.27585605896717136, 0.2873061267892052, 0.012075731469473161, -0.22614282997146407, 0.05155176198839151}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.006289218997079571, -0.3096511742533309, -0.45207794660392475, 0.4347291609174805}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){1.4405284127079354, 1.7494973949545543, 1.6227618609807841, -1.2924237553058981, 1.2103866493262068, 0.5567108981621907, 0.4237527112835955, 0.22559567137319458, -0.15287663519229255, -0.3886645777726758, -1.1788176743178562, 0.6918123866221721}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){1.6516496331624038, -1.425319150512808, 0.9663116723048292, 0.14014453650188147, 0.16707493919540525, 0.03170954489805733, -0.3795139484420801, 0.1741013641837328, 0.21837439274267897, -0.5792056403772659, -0.29564312236845663, 0.38094838140373655, -0.4572308817862868, 0.19783443557890545, -0.7051880596552185, 0.7322810642309885}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.42445027237711486, 0.12313989583876239, 0.02819276785411673, 0.1834623372612294, 0.4203414723277281, -0.01360626785209973, -0.418181044013181, -0.4504311045695576, 0.2806881752246537, 0.2755763685950413, -0.19878778741909486, -0.26023388841840667}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2830397326102184, -0.08352663618126299, -0.448477671122016, 0.2576950981454682}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.9417080404725784, 1.9285177019934272, -0.6313861291914917, 1.2639465957872895, -1.662579494551033, -0.8179581267758347, 0.3368895791343074, 1.2807552020905182, 1.4078741076045196, 0.8833199736230739, 1.0868007526083279, -1.4458964611491498}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.5257293645678639, 0.7126865865771702, 0.13145336825778456, 0.573990177608141, 0.3819609857183868, 0.36833605754855814, 0.3875197613427994, 0.7593957957577674, 0.5835711565249259, 0.6218665933368647, 0.316246203017655, 0.4327987986971139, 0.5002947593191464, 0.6353017987042835, 0.15274391357892556, 0.6595626277306726}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.16383204581148847, -0.01736302849997895, -0.3270937846444478, -0.24990318009372203, 0.3971958995137128, -0.26657881402273953, -0.011725396177276304, 0.17632626139828367, -0.4818297607823867, -0.18891160423416842, -0.0707280022225737, 0.15343490620030642}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3529484282301689, 0.1551541821678828, -0.21600117160475762, -0.16521289478745438}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.9602578220278719, 1.9847048676137473, -0.08299589392612372, 0.05008998362306549, -0.5907141185897817, -0.7158036211096408, 0.4067059181245325, -1.0828693417805622, -0.1961168312343622, 1.830402818225401, -1.045729922890485, 0.5103745280198817}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.5029563855932999, 1.2055672477351893, 0.1852037127924998, 0.0, 0.5891335853059052, 0.09882539066950832, 0.024148578933054443, 0.0, 0.36926745342420036, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.16657304352122393, -0.11323140421222899, -0.20996742896707665, -0.4711187740035728, -0.4143942944371414, -0.2617176309801068, -0.474457574683797, -0.1051394991197857, 0.27533864452404666, -0.1512570773896338, -0.3472914067859222, -0.40383673352583993}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.23532397619818513, -0.48643993851390765, -0.07221961923277986, 0.2998380923909494}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.15587336468713087, 1.3026619058709619, -0.8376683371963796, 1.1020565864153733, 0.6017696532384202, 0.812180883770766, -0.30111046705487743, 0.46709218487295256, 1.536387698777283, -1.0449372927953147, 1.5207108255166406, 1.0664783411967118}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.25746486561191584, 0.14815721197779788, 0.21400387155547576, 0.3803740508548106, 0.2510490174913482, 0.11168075569396942, 0.3137109965729529, 0.3235592302417294, 0.18024786643074853, 0.12331470660309847, 0.4925236591778993, 0.2039137677882538, 0.18670387561337476, 0.11951798960372065, 0.5150284069117467, 0.17874972787115784}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.032863320023355014, 0.4768215692349189, 0.13575463806156862, -0.31694331220309324}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.42490690131356335}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.7206088093979237, 1.7261671778053747, -0.3499288666053131, 1.0975839472458944, -0.05704357635597779, -1.2475073597349766, 1.5847397693771272, -0.1003608971573855, -1.7559606346415015, 1.0974861062302157, 1.867560919156686, -1.9677192112862767, -0.9931773896623701, 1.0757564553092767, 0.40862739424326255, 1.597049451102809}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.8289226875872825, 0.0751383320818595, 1.7676907533639157, 0.45451059727517146}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.09857225653709711, -0.4224851645190868, -0.32491289209887986, -0.1508967978933592}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.47115573376436637}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.1651554000888269, 0.5881310060583602, 1.564061235676312, -0.40637822399323786, -1.436043971097547, 1.0185792365631223, 0.27764057658199937, 1.963033664472778, 1.989254304020149, 1.2868502087318627, 0.5603121620273637, -0.4177837329732337, -1.7190311379582774, -0.3489873395044367, 0.42254916494257255, -1.0220390196561753}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.2404497954518802, 0.24115443416213342, 0.20917151347336693, 0.4657203018743941}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.038314637295195464, -0.4735108454646534, -0.4018567565975183, 0.452139216408476}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.36929591226453773}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-1.3940877330881567, 1.3400984649615384, -0.8116838910719428, 0.7792889870824706, 0.2950752043233553, -0.15473247630853004, 0.5232948224015539, 1.932155276858445, 0.15764378870086082, 1.8417484365215144, -0.8672248955253794, 0.8828544225064703, 0.6337923567198791, -1.2354161127661603, -1.99600221823964, -0.9891668185201103}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.359858557087609, 1.1171827301544006, 0.2509214080912295, 1.333428231949573}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.0892996101909006, -0.4352508153249831, -0.1005543339060384, -0.2805546842488523}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.39071318907488484}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-1.247577792612181, -1.167414962485951, 0.7848983631934674, -0.020090634780619787, 1.361209898769491, 0.9416014616592006, -1.765674064925883, 1.640841369271568, 0.7797233529787189, 1.3926249974896883, -0.9672513853988587, -1.4065250179139777, 1.4550653396449391, 1.9433853142852207, -1.2986192732721507, 1.700669974457019}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){1.0, 1.0, 1.0, 1.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.042290772092505424, -0.16861002837916683, 0.0516363798821553, -0.4456021367323759, -0.05082989099144086, -0.09814418003798886, -0.30453335489526934, 0.32249452370642706}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.24773898436353914, -0.44890704977745366}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-1.7163290515571754, -1.9718511808566417, -0.8420051276396339, -1.2384975814539754, -0.2620846149881988, -1.8280870281009625, 0.3815739518747696, 1.7756523412441374, -1.1500057491731663, 1.244731332038445, -1.6234572107481622, 0.8749012679263553, 1.6410949078838861, -0.5874439354631429, 0.29810809263103977, -1.8981114968466835}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5205490904452907, -0.3111305551626886, -0.7221203192173598, 0.2002669453966437, -0.979935128300798, 0.263932219750155, 0.7819088864657711, -1.1775839423751058}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.09841305385379073, -0.1720256463672919, 0.3354498438495209, 0.027725559823682855, 0.3091922920608282, 0.4485671242951321, -0.12987364874061458, 0.16235869173629114}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2671217372612481, 0.3957515269255172}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.8187620957775716, 1.078853070258449, -0.797346238422056, 0.630114230757155, -0.9922308964608089, 0.6376728792627087, 1.72878402044558, 0.9844815388103267, 0.4160677677591851, 0.8441586622601638, -1.5174691746465916, 0.8928649821895069, 0.8115452731557737, -1.5993743232774036, -0.7731730846941578, -0.19948410435361907}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3492961127987853, 0.7922766125801194, 0.5331386821615406, 0.5769624199634905, 0.2982444245526648, 0.776450833144047, 0.45586186932134964, 0.4993187905694568}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.09735811456281818, 0.34534217560264946, 0.16933834795835945, -0.22660791584554796, 0.3793704751660034, 0.10781877371489279, -0.0462216660705882, -0.16407088708381945}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.21092778353750274, 0.060981305694876475}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.5172907072467572, 1.1444454657024234, -1.4865201101584757, -1.5229707741663678, 0.4910222709852623, -0.43844648948197795, 1.6300724009833445, 1.2243562283962963, -0.8603146209341173, -1.438522944597823, 1.9475657820893306, -0.3436716887102911, 1.359443416517526, -1.7159477053594259, -0.9105444588176512, -0.3601966592176713}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.7499078918265826, 0.3067137930424872, 0.010293670728609622, 0.0, 0.2055800468137288, 0.0, 0.0, 0.4928872905500535}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.27631079019033866, -0.0401843421960385, -0.45090379908796685, 0.25884943767526847, 0.1593743362117288, -0.1565515166490875, 0.3935894832460348, 0.31420250967823904}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.42111329063833935, 0.20561139437071496}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-1.8617087003378572, 1.1272134689981468, 0.823618373174559, -1.9957872904778169, 0.5883939307792474, 0.8024802605528683, 1.6005129901822, -1.4894827527413592, 0.17438119203803426, 0.0591411408292859, -0.2691253117849146, -1.0071315837233041, -0.4028104501835976, 0.7721887441818471, 1.1554191611990534, 0.45255144286473437}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.2144474091279274, 0.7855525908720726, 0.15011330727323524, 0.8498866927267646, 0.42154633836166155, 0.5784536616383384, 0.17012179591277676, 0.8298782040872233}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2288742631230659, -0.34847275233195274, -0.29190673718472915, 0.19424011714136935, -0.2829991257064788, -0.1725741831997204, -0.2511116577576965, 0.22076135227718086, 0.3763495309146232, 0.45827601878346036, -0.15913723431229987, -0.2250099796451246}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3609706317050747, -0.2872187657945794, 0.4413044127881133}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.23912847694144945, 0.1903627818284117, 1.4849819854223765, 0.6721054619372131, 1.931164899519962, -1.7636193581039294, 0.7262877975264055, -1.354938295969271, -1.6005349434242868, 0.15265141283981976, -1.7056726960562396, 0.2019173084615007, 0.8642072585670824, 0.4318571996571188, -1.690169690622652, -1.0984947690343954}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.04643834064676783, -0.6122649947357861, 0.23099263822065066, 0.942346192274809, -1.0108789170701251, 0.5491681657432473, 0.4785723110057589, 0.6122773673348985, 0.13490294538129638, 0.6882751312780937, -0.42439994566537775, 1.4805994230095552}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.44946270867739135, 0.19157259516704295, -0.359594723721419, -0.21164204718014568, -0.08321029047734252, -0.18172023596169617, 0.07688016599881964, 0.49595199491417385, 0.42852643861639383, -0.47750766289949087, -0.4675408963278077, -0.3577425526062995}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.36586999561572653, 0.147281277763875, 0.2390614655904475}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-1.6692059151909544, -0.6767587431587598, -0.6659446893724614, 1.6810276937216067, -1.774813037211445, 0.4454129758683032, 1.5472717301130907, 0.5108525180338166, -1.9518075843596625, 0.3349215349414991, -0.03921237193357996, 1.4250622196642642, 1.2405634792146438, -0.6394602287263753, -0.9903884477944218, -0.1963318923164361}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.7047792877354249, 0.7670392957894482, 0.3910028649976106, 0.6420798066379202, 0.6425240746014518, 0.16241779068815246, 0.7349324679971233, 0.7216332446811001, 0.22291844912283493, 0.520855508071815, 0.49668606653322694, 0.8333150460068668}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.28587857694008656, -0.40462938215884303, 0.37070600359575634, -0.4468061682073309, -0.07553595459784257, -0.1261903692119617, -0.35142658379486524, -0.05382776775173237, -0.14980914490110298, 0.1651831872093501, -0.4580272656138984, 0.3111578087629482}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4108573392438042, 0.4688140464878423, -0.069087106937325}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.40811610465215553, 0.34203773184738484, -1.2269426880142515, 0.7443447729882959, 1.7983856992648954, 1.041322555660324, -1.9386617524672323, -0.18112813586295173, 1.3480234772122581, -1.8474318869575548, 1.2844924595233853, 0.9270592286277339, -0.5993724553869386, 0.2503510120868029, 1.9805403945703306, 0.5580037418541957}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.0, 0.84759347816656, 0.8421331933967179, 0.0, 0.8926133882251013, 0.6651077554827681, 0.013250135083505421, 0.09881159241419485, 0.0, 0.14406973090367914, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.057674956537953626, -0.2360080282547633, -0.2023310448194885, -0.2469117494180617, -0.45693835894035006, 0.3402305029222329, -0.2650678752605742, -0.06029527497748921, -0.1042518081564725, 0.464178503928557, -0.05123052139508, 0.46755265979521754}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.0819714375916184, -0.059372583239980625, 0.4893157590871283}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.7449506884683501, -1.897339164476357, -1.9390334657369825, -0.52129115141061, 1.0249534442358823, 1.910083186660203, 0.3315161252685268, 0.9222085298104727, 0.7072016913424446, -1.8051078315542908, 0.3352429847459599, -0.9883022403899231, -1.59840123839296, -0.6806588480073699, -1.0678206931045242, 1.1262341702028706}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.6882030899331197, 0.16474003032068452, 0.14705687974619575, 0.06793899109362327, 0.14341160327854138, 0.7886494056278354, 0.696292167010613, 0.14242201007285366, 0.16128582291653337, 0.17286186115690969, 0.35873856120112385, 0.4683995776419666}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.12718397796677594, -0.37832473366233943, 0.42421799985418107, -0.07052303795825143, 0.37711157804661455, 0.19068827159149349, 0.19356032806583168, 0.27190944697734354, 0.2944678044601068, -0.0026117686513077443, 0.20306507135250307, 0.12850394907659635, -0.20277581267464118, 0.2689168943252137, 0.1619557969598897, 0.46782899335038586}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.07975751023421451, 0.22218612582912012, -0.4983984690996205, -0.4678735689685858}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.1995063272855977, -1.1343385375437727, -0.9426346191636901, -0.8915764291619674, -1.2342277123333933, 0.6378821479844778, -1.3512501874239264, -0.22260093479287812, -0.38029804759137864, 0.1901832223451967, 1.3912796730446968, -1.7079463885963895, 1.9479598008182015, 0.32426637533623826, 0.6130294152499003, 0.44696893581210473}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.19727394928865719, -0.49423979513067984, -0.8601712876897202, -1.3022317522876043, -0.5621212509762045, -0.4436945168125225, -1.1665016092649392, -0.36904672763258595, 0.7668297599295342, -0.08007316911574575, -0.5478382644600834, -0.91331587323526, -0.0621332510752928, 1.2588113658176439, 0.25628820318540924, -0.4672832992409905}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.09971155318943103, -0.021323865148849208, -0.41939303837486075, -0.4179767880278207, -0.29507459586784146, -0.40022074845924105, -0.4275636604998503, -0.397560807563927, -0.3833383486468691, -0.10337003854480142, -0.270991329098453, 0.23913440804652286, -0.4616875713597274, 0.43973969849290495, -0.3965607663762253, 0.01652550470097225}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.18846447681398348, 0.21365548305462512, -0.2452426964768919, 0.08701067086515846}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-1.9443846843172712, 1.7226037088862496, 0.641704144231428, -0.9067142791867728, 1.8343319563266274, -1.3873021611640728, -1.781876634326907, 1.0425339295512526, -0.797133950398027, 1.5716642621213261, 1.5208903356545949, 1.9911321529726922, 0.7068351492588545, -0.4575283361216953, -1.2706753856735427, 0.4010387093032781}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.42330626442422653, 0.5458897322038869, 0.4828382602912804, 0.8134746410586744, 0.58311497815401, 0.639919068508922, 0.4818010056339098, 0.3438737442153759, 0.14534846743319138, 0.164926925985175, 0.4904677640041906, 0.640132598105272, 0.5639131834409945, 0.639237466217446, 0.4928352835313856, 0.5174947719971201}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.17491036805803162, 0.3828284509118358, -0.31382664908446023, 0.4511711186927422, -0.033372145154277666, 0.4817047489453641, -0.2825530925598436, -0.17369237368580792, -0.11016504848927133, 0.35897449137506043, 0.2107195775602747, 0.3498575565949552, -0.48640500057390024, 0.047612420956868684, -0.2361264850841499, 0.3143301959435897}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.10622157662479392, 0.12151406313847424, -0.3482520625862323, -0.3760869720955673}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.778894183587231, 1.562603462136202, -1.6465880743265764, 0.4327172318487018, -1.059355032980771, 1.6358932717459589, 1.0655179826148857, 1.0502515070718426, -1.478343211085178, 1.0997761072946464, 1.063273454994575, -1.8968327221769083, 0.7108702319545617, 0.00613762296501541, -0.9002287320012559, -1.604087278483394}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){1.5526400431125191, 1.2903098107610247, 0.10291068595115516, 0.6019895341944602, 1.0572354517582672, 0.46139849244045344, 0.947659716412146, 0.29560619840342195, 0.0, 0.7296510960814401, 0.0, 0.0, 0.0, 0.6337274599384854, 0.0, 0.0}, NULL), + .output_tolerance = default_output_tolerance, + }, + { + .batch_size = 4, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3316993523981008, -0.061166940517019874, 0.25130402972935073, -0.36898273163189255, 0.3159953334068575, -0.022581372185559445, -0.08213196360723685, 0.3192241781818247, 0.006185914887412158, -0.12033403942944909, 0.015994498948398994, -0.24377550041259766, -0.13295165502995243, 0.36026441953638855, -0.45768541508823046, 0.056947089076054835}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.49365098703718613, -0.14681707460690263, -0.30395154478912445, -0.03630498411060834}, NULL), + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){1.3324963789856636, -1.2350673990529968, 0.7528713334499462, -1.4296459108466455, 1.4171342075764608, -0.25829343238712976, -1.3905354292213588, -0.8349874753012747, -0.3027288889144675, 0.7896921946937558, -1.7606897518045086, 1.6346064302607144, -0.6431176079432466, -0.9326874177402247, -1.5864562488785023, 0.42833360338162363}, NULL), + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.2667431486102422, 0.2480396390434306, 0.38112678592038435, 0.10409042642594275, 0.09861135307944034, 0.3094927350419568, 0.24411925431546994, 0.347776657563133, 0.041527485241592055, 0.27578153748948203, 0.08031971776993561, 0.6023712594989903, 0.12354442127806951, 0.25332324462476985, 0.19463449284049086, 0.4284978412566698}, NULL), + .output_tolerance = default_output_tolerance, + }, + }; + + run_test_cases(test_cases, n_test_cases, "layer"); - run_test_cases(test_cases, N_TEST_CASES, "NNLayer"); return 0; } diff --git a/tests/arch/generic/layer_multi/include.txt b/tests/arch/generic/layer_multi/include.txt new file mode 100644 index 0000000..c0506a0 --- /dev/null +++ b/tests/arch/generic/layer_multi/include.txt @@ -0,0 +1,8 @@ +src/nn_activation.c +src/nn_app.c +src/nn_config.c +src/nn_mat_mul.c +src/nn_mat_transpose.c +src/nn_error.c +src/nn_layer.c +src/nn_test.c diff --git a/tests/arch/generic/layer_multi/main.c b/tests/arch/generic/layer_multi/main.c index bf03085..145fc32 100644 --- a/tests/arch/generic/layer_multi/main.c +++ b/tests/arch/generic/layer_multi/main.c @@ -1,168 +1,17144 @@ #include "nn_activation.h" +#include "nn_app.h" #include "nn_config.h" -#include "nn_dot_product.h" +#include "nn_error.h" #include "nn_layer.h" +#include "nn_mat_mul.h" +#include "nn_mat_transpose.h" +#include "nn_tensor.h" #include #include #include #include -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 3 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.0001f - -// TestCase defines a single test case. typedef struct { - size_t input_size; + int layer_idx; + int layer_type; // 0: input, 1: hidden, 2: output + size_t inputs_size; size_t output_size; - float weights[NN_LAYER_MAX_OUTPUT_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - float biases[NN_LAYER_MAX_BIASES]; - float weights2[NN_LAYER_MAX_OUTPUT_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - float biases2[NN_LAYER_MAX_BIASES]; - NNDotProdFunc dot_prod_func; - NNActFuncScalar act_func_scalar; + NNMatMulFunc mat_mul_func; + NNMatTransposeFunc mat_transpose_func; + NNActFuncType act_func_type; + NNActFunc act_func; + NNTensor *weights; + NNTensor *biases; + NNTensor *inputs; +} TestCaseLayer; + +typedef struct { size_t batch_size; - float inputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_INPUT_SIZE]; - float output_tolerance; - float expected_outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE]; + NNTensor *expected_outputs; + NNTensorUnit output_tolerance; + size_t n_layers; + TestCaseLayer *layers; } TestCase; -// run_test_cases runs the test cases. void run_test_cases(TestCase *test_cases, int n_cases, char *info) { - for (int i = 0; i < n_cases; ++i) { + for (int i = 0; i < n_cases; i++) { TestCase tc = test_cases[i]; - NNLayer layer; - NNError error; - - nn_layer_init(&layer, tc.input_size, tc.output_size, &error); - assert(error.code == NN_ERROR_NONE); - nn_layer_set_dot_prod_func(&layer, tc.dot_prod_func, &error); - assert(error.code == NN_ERROR_NONE); - nn_layer_set_weights(&layer, tc.weights, &error); - assert(error.code == NN_ERROR_NONE); - nn_layer_set_biases(&layer, tc.biases, &error); - assert(error.code == NN_ERROR_NONE); - float intermediate_outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE]; - const bool first_layer_success = nn_layer_forward(&layer, tc.inputs, intermediate_outputs, tc.batch_size, &error); - assert(first_layer_success == true); - assert(error.code == NN_ERROR_NONE); - for (size_t i = 0; i < tc.batch_size; ++i) { - const bool laf = nn_act_func_forward_scalar(tc.act_func_scalar, intermediate_outputs[i], intermediate_outputs[i], tc.output_size, &error); - assert(laf == true); + NNError error = {0}; + + NNTensor *last_outputs = tc.layers[0].inputs; + size_t last_outputs_size = tc.layers[0].output_size; + + // Iterate over the layers + for (int j = 0; j < tc.n_layers; j++) { + // Init the layer + NNLayer *layer = nn_layer_init(tc.layers[j].inputs_size, tc.layers[j].output_size, &error); + assert(layer != NULL); + assert(error.code == NN_ERROR_NONE); + + if (tc.layers[j].layer_type != 0) { + // Set weights + const bool sw = nn_layer_set_weights(layer, tc.layers[j].weights, &error); + assert(sw == true); + assert(error.code == NN_ERROR_NONE); + + // Set biases + const bool sb = nn_layer_set_biases(layer, tc.layers[j].biases, &error); + assert(sb == true); + assert(error.code == NN_ERROR_NONE); + + // Set matrix multiplication function + const bool smf = nn_layer_set_mat_mul_func(layer, tc.layers[j].mat_mul_func, &error); + assert(smf == true); + assert(error.code == NN_ERROR_NONE); + + // Set matrix transpose function + const bool stf = nn_layer_set_mat_transpose_func(layer, tc.layers[j].mat_transpose_func, &error); + assert(stf == true); + assert(error.code == NN_ERROR_NONE); + } + + // Set activation function + const bool saf = nn_layer_set_act_func(layer, tc.layers[j].act_func_type, tc.layers[j].act_func, &error); + assert(saf == true); + assert(error.code == NN_ERROR_NONE); + + // Init outputs tensor + NNTensor *outputs = nn_tensor_init_NNTensor(2, (const size_t[]){tc.batch_size, tc.layers[j].output_size}, false, NULL, &error); + assert(outputs != NULL); + assert(error.code == NN_ERROR_NONE); + + // Compute + const bool lfr = nn_layer_forward(layer, last_outputs, outputs, &error); + assert(lfr == true); assert(error.code == NN_ERROR_NONE); + + last_outputs = outputs; + last_outputs_size = tc.layers[j].output_size; + + // Cleanup + nn_layer_destroy(layer); } - nn_layer_set_weights(&layer, tc.weights2, &error); - assert(error.code == NN_ERROR_NONE); - nn_layer_set_biases(&layer, tc.biases2, &error); - assert(error.code == NN_ERROR_NONE); - float final_outputs[NN_LAYER_MAX_BATCH_SIZE][NN_LAYER_MAX_OUTPUT_SIZE]; - const bool second_layer_success = nn_layer_forward(&layer, intermediate_outputs, final_outputs, tc.batch_size, &error); - assert(second_layer_success == true); - assert(error.code == NN_ERROR_NONE); - for (size_t i = 0; i < tc.batch_size; ++i) { - for (size_t j = 0; j < tc.output_size; ++j) { - assert(fabs(final_outputs[i][j] - tc.expected_outputs[i][j]) <= tc.output_tolerance); + + // Check outputs + for (int k = 0; k < tc.batch_size; k++) { + for (int l = 0; l < last_outputs_size; l++) { + // printf("expected=%f, got=%f\n", tc.expected_outputs->data[k * last_outputs_size + l], last_outputs->data[k * last_outputs_size + l]); + assert(fabs(last_outputs->data[k * last_outputs_size + l] - tc.expected_outputs->data[k * last_outputs_size + l]) < tc.output_tolerance); } } printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); } } -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.34f, -0.78f, 0.59f, 1.25f}, - {0.45f, 0.12f, -0.33f, 0.1f}, - {0.14f, 0.76f, -0.48f, -0.81f}, - }, - .biases = {0.1f, -0.2f, 0.4f}, - .weights2 = { - {0.25f, -0.15f, 0.2f}, - {0.3f, 0.45f, -0.25f}, - {0.5f, -0.9f, 0.1f}, - }, - .biases2 = {0.5f, 1.5f, -0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_identity, - .batch_size = 3, - .inputs = { - {0.9f, -0.3f, 2.2f, 1.9f}, - {1.4f, 0.6f, -1.3f, 2.7f}, - {0.6f, -0.5f, 1.8f, -0.9f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {1.1739, 3.203, 2.0571}, - {0.89665, 2.983, 0.026}, - {0.75265, 1.39375, 0.719}, - }, - }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {-0.45f, 0.88f, -0.14f, 0.23f}, - {0.52f, 0.21f, -0.88f, 0.45f}, - {-0.33f, 0.44f, 0.62f, -0.67f}, - }, - .biases = {1.0f, -1.2f, 0.3f}, - .weights2 = { - {0.39f, 0.17f, -0.41f}, - {-0.29f, 0.36f, 0.27f}, - {0.13f, -0.31f, 0.11f}, - }, - .biases2 = {-0.1f, 1.0f, 0.2f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_identity, - .batch_size = 3, - .inputs = { - {-0.5f, 2.1f, 1.9f, -1.3f}, - {1.2f, 0.5f, -0.7f, 2.2f}, - {0.3f, 1.1f, -1.5f, 1.8f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {-1.08838, 0.02158, 1.91978}, - {1.41095, 0.49076, -0.15257}, - {1.67703, 0.36982, -0.04847}, - }, - }, - { - .input_size = 4, - .output_size = 3, - .weights = { - {0.62f, -0.32f, 0.71f, 0.14f}, - {0.39f, 0.24f, -0.56f, -0.21f}, - {-0.29f, -0.51f, 0.28f, 0.67f}, - }, - .biases = {0.25f, 0.75f, -0.15f}, - .weights2 = { - {0.19f, -0.45f, 0.28f}, - {0.54f, -0.33f, 0.47f}, - {-0.35f, 0.62f, -0.2f}, - }, - .biases2 = {0.7f, -1.1f, 0.3f}, - .dot_prod_func = nn_dot_prod, - .act_func_scalar = nn_act_func_identity, - .batch_size = 3, - .inputs = { - {0.2f, 2.8f, -1.5f, 1.6f}, - {1.1f, -0.8f, 2.3f, 0.5f}, - {-0.9f, 1.6f, 0.7f, -0.2f}, - }, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_outputs = { - {-0.73629, -2.95982, 2.21633}, - {1.68903, 1.02658, -1.14717}, - {0.25842, -1.73464, 0.81991}, +int main(int argc, char *argv[]) { + nn_init_app(argc, argv); + // nn_set_debug_level(5); // for debugging + + 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 + TestCase test_cases[] = { + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.6320926234978839}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.17602903779079582}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.2387472703170177}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.09511507335162572}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.393047371544085}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.48730161120044346}, NULL), + .inputs = NULL, + }, }, }, - }; + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.5591622663121779}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.9252928238028268}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.17940052352514158, -0.02615429659178148, -0.05170417551969542}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.48089305212753397, 0.25259833720857927, 0.10244853900812656}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4992141177085686, -0.0973806261522352, -0.2575423460516981, -0.4816525412697036, 0.27906482420991574, -0.007064925612758177, -0.12280223326388273, -0.12323456931455323, 0.319364696449859, -0.0839274804907495, -0.28527308045204647, -0.24742558026124595}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.13749947248342176, -0.02118516308041518, 0.21678909199467022, 0.17365545318760678}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.07484678711125714, 0.18158087685904012, 0.12529509692629293, 0.1714402618834503}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.1943917563821278}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.5361345643711561}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.42651873395918116}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.28450685708742096, 0.2589536567735904}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.08221461506556649, -0.274231232403917}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.2442932953265584, -0.14422143551384892, -0.35652851434555866, 0.1090625665522097, -0.4559839576443476, 0.41965421663519165, 0.41453672122494756, 0.35604176860988823}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.458577587211373, 0.22105225932961647, -0.3494996983371903, 0.4426032642119033}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.42335038687001847, -0.2540515564737893, -0.43598162384121486, 0.40210470458619796, 0.3740398003743294, -0.3363327094471328, 0.49974130668639594, -0.1531960296532764, -0.1871218406558416, 0.347104020990443, 0.38023110263249615, 0.17655865154664596, -0.4463248457283463, 0.059213773519614876, 0.1945129418277548, 0.32419730266546243}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.18857134113802954, 0.0052305408491463146, 0.3490037878830786, -0.20648436730242037}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.17711955065481155, -0.07909359780279657, 0.18171271362934172, -0.27877201051351197}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.048997698432867054}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.4664093877339543}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.6976934389501706}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.4862689115135179, -0.11188581303011635, 0.2700869946742117, 0.4514735502665438}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.29030555923550283, 0.4629461424887975, 0.012839839323685931, -0.10295787237990817}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.23414539834613501, -0.21134454505552536, -0.10960188586949926, 0.13561732371232704}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.33114885673920824}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4724328306259571, -0.26373766577493984}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.33673174774118786, -0.21838004445168113}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.1947128788862139, -0.32676667970669726, 0.03173259230468373, 0.37095862065672913, 0.34109026805366327, 0.4720555400219495}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.28225720971335977, -0.3029694936276297, 0.11062606560895016}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.02114449408827901, 0.11663699608232281, -0.3600667567083453}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.08876418378048034}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5647443478045194, 0.4352556521954805}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.5552606788754164}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.3144669524984106}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.06196536077918258}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2086538315014007, 0.023166420540233768}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.18348724162738217, -0.4439268239576085}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.46505616729534754, 0.5349438327046524}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.019752633960700372}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.3811495560306797, 0.32005648720313784, 0.23665887760270887, 0.3469682305023296}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.10911562376633555, -0.15576699437209196, -0.2703310085569506, 0.44462578845283707}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3781179159131305, 0.20903191222000317, 0.3648232366839691, -0.2706854400714567, 0.15967124826812773, -0.4560911618851302, 0.4033691205438483, -0.3426505857408071, 0.08213091786884952, -0.3568541517837498, 0.03976662587299429, 0.3826065503026983, -0.41136464939862993, -0.131671706565609, 0.37006430709172367, 0.3942595693085421}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.43247430820766886, 0.4365604908055828, -0.07743857550469035, -0.4514780963997008}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.37511254410895223, -0.1172486450127257, 0.3563591158062387, 0.03302885891341645, 0.15159295172518428, 0.48791945108535206, -0.22619305544512025, 0.015578764742528728}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.17183189171156943, 0.1859265977520259}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5028339880955152, 0.49716601190448473}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.8380072942396855}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.08847579381675741, 0.2579761599060061, -0.48221657243706784}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11286757765848654, 0.15114242636134823, 0.22206680116695998}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.16915506126838098, -0.4759674846377109, -0.35102541370419904, 0.4828951385157133, -0.10885349554274804, -0.40248257098073204}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.45191480318773725, -0.15501968214798656}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.44208678482162345, 0.19419746450443587, 0.221186357455198, 0.10348358079419628, 0.3760981203222017, 0.38145879955464246}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.413824916860111, -0.4588230950889738, 0.3007797288750268}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4911918671375408, -0.3735972375742086, -0.35697408634804717, -0.4331686153644586, -0.1594725287441343, 0.29631638750032163}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.06648549642239454, 0.24117629086464354}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5700820166084305, 0.42991798339156945}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.48553144737951914}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.44505517974913655, -0.19095725760111848, -0.07522356983548562, 0.28689478597579354}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.04262408514670368, -0.09650789317894115, 0.19480434378698697, 0.48856748477711043}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.31027546301457765, -0.4962320179911416, 0.3802606777860795, 0.38046406791270293, 0.08212736560627454, -0.3998709158466325, 0.012248208883173906, -0.011391129068417105, -0.009422638288266172, 0.254958476683133, 0.42300343926874573, -0.16695592228169842, 0.11641615854086562, 0.4964066783874884, 0.2844932456463556, 0.3667834717623596}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.446505578290058, -0.06401808388263064, -0.40410367305207506, 0.25032907365706436}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.28371408088266004, 0.0828085479138726, 0.4129555215305304, -0.07278746893900723}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.09415105098670429}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3888791283998829, -0.2960177019309589, 0.21134431832017253}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4338274409109468, -0.45974590768548007, -0.17128089572359684}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3725961589973664, -0.0655272848886409, 0.2127224975547477, -0.010179359962674162, -0.19201437592339765, 0.20949757553739168}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.10274784532378267, -0.048272700625361376}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4718294355961887, 0.2876728204073926, 0.24049774399641882}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.19343041206752343}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.09419297136752058, 0.3487130742982124, -0.03314819975031069}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.14408049175038307, -0.02220369976399328, -0.4386489153647595}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.30419498702807524, -0.18295934722565654, 0.39469206961026815, -0.21545140926964834, 0.4994717871989176, -0.08456692466724125, -0.2648519413543121, 0.07975612334384052, -0.3937371871205916}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4863580663896162, -0.008435694524493664, -0.18754877959591887}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.40821249109229424, 0.3123808864251049, 0.2794066224826008}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.09952880825457222}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.12498243265631892, -0.09826376158077677, -0.27950192251264283, 0.17729092108606748}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.061674417923333835, 0.4336336195203927, -0.11199589955884592, -0.2095740788057301}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.027819606213163595, -0.4743710449938574, -0.3354437190022481, -0.4608193240944538, 0.3042743153236789, -0.18594524246783295, -0.0036434596846993683, -0.08237248132820085, -0.09290497572136103, -0.17397150115167304, 0.0021072937530233204, -0.1487293000215243, 0.28681293587371337, 0.13321379673229117, -0.3499587567712291, -0.3138035602117837}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2129196723024246, 0.0703761033728818, 0.08115939433651032, -0.1076056861800262}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.1816582561672161, -0.2893687853104254, -0.1667415081138247, -0.09930240464175688, 0.3793473991650206, 0.09773264641609969, 0.03529100096610116, 0.4656065984977471, -0.3421975215575632, 0.013206155418259424, -0.37127626532381297, -0.1740926243280666}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4761699949010888, 0.20476233550803824, 0.10477887889692761}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3544993242910098, 0.4526077535159188, 0.19289292219307141}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.13912451569577589}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.003086272169466109, -0.4297970620913606, 0.11644999483480167, 0.06964566738299416}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.02755005564929458, -0.1540443934129495, -0.2031613392391287, -0.28367333668609085}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2901632400521177, 0.376449161004196, -0.1403610347936597, -0.11925985589337273, -0.3674557248910444, 0.18179901014863686, 0.35513812964585967, 0.008408194876581288, 0.24685335079374315, 0.1571778001086166, 0.13028764734077813, -0.20072231917224603}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.0731922072971597, -0.15940860740172902, -0.3210791034006274}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.19817336293345367, -0.4356519269012775, -0.3671695262150436}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3236951088189599}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.06561693034228244, -0.32127867378141295, -0.019245058840784424}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.10860467160331555, 0.35292409583183326, -0.49996654062422297}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.334881537004324, 0.43977038066483276, 0.22534808233084322}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.27635183320842227}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.4729086897643523, 0.15178576502751773}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.18129642460772777, -0.4566932524966151}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.2790970205955621, -0.012150433382389525}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3620980992522711}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.24766967404668583, -0.4319764694602952, -0.18775289369540482}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.21965755155905808, -0.3152445880720649, -0.1921143390468929}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.1982705369893768, -0.24345755362439625, 0.13171559218800166, 0.49655152821050685, 0.39069341726934725, -0.4285692705943476, -0.015224624573833778, -0.12167001662065546, 0.385939721047015, -0.27123232256055185, 0.4990280858090611, -0.12689016347208948}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.0020366147520587408, -0.002376591897432112, -0.4912413070420558, -0.12466914765705805}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.22780122385444945, 0.24163254706948922, -0.27340575833476277, 0.02585804031057981, 0.21178212029271504, -0.021912796857411987, -0.4367038326225865, 0.1995780845231392, -0.21785843703338237, -0.07841856957784621, 0.11299842938346649, 0.01063141135248813}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.18084595229111156, 0.4814407241301999, -0.18113689854963766}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3219864262148907, 0.28510722487009227, 0.23568073987774016, 0.15722560903727684}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.7731642994609453}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.005624209269820102}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3562999777811403}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.05391617084441436, 0.3298437409826229, 0.4451170501785131, -0.00948539176205132}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4134935062417946, 0.19473632009736008, -0.03622154367639918, -0.2810198321177071}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.161174993052952, 0.3905051284007794, 0.15283095177546271, 0.29548892677080596}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.33577570737583695}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.22471757829338235, -0.200050207603102}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3115736314977754, -0.07883046478679268}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.30696662077804127, 0.3366195051682861, -0.22858957300408012, -0.2171869243927793, -0.024041517453293526, 0.15018420934485588, 0.1274584784522267, -0.23073899271030873}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.007145047353394718, 0.46506069140062567, -0.05682146051058368, -0.3969492180160906}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.2214910019788553, -0.19250001674716, -0.40149704740895287, -0.47879226371288763, 0.3240187694462223, 0.4715927820070108, 0.2711949479728125, -0.3751455345437027, -0.1961052676272511, -0.044804550836944235, -0.0915408111278051, -0.2076563060350316, 0.4830388260831825, -0.13622596636212259, 0.12394634553242112, -0.019182152120132523}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.22911143655124844, 0.344836762144879, -0.3407249115843246, 0.27716937881352743}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3120092474737031, 0.1970905908213717, 0.2891765998815916, 0.20172356182333354}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.1220066188641935}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.09442238309366546, -0.4697586758838419, -0.4412632158098151, 0.062458444470072094}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2088214569816712, -0.0614917647398151, 0.021510314506775652, 0.45548379040151965}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.10841025752830757, -0.16241786295448746, -0.208887184720834, -0.11090854768424196}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.062273766422244026}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.22040742720791762}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3378167842476836}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.05950099804998732, -0.25971386357944704, 0.12866650455324713, -0.042280636574971386}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.41350738717897684, 0.06343409341966721, 0.3138305387663848, 0.012221854669108079}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.149223592950628, 0.17632250306942202, 0.14602150813359338, 0.5284323958463566}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.6453612888012774}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.016797963596288934, 0.1762429949897124, -0.31358949083118415, -0.15788214103248555}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.17806515111142018, 0.29551148338665834, -0.09872474048631019, 0.30985753568488716}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.05727095610605837, 0.3652123810894796, -0.16601731383596308, 0.2830318118479025, -0.014631096587904291, -0.06222322418975024, -0.1964319808092212, 0.03372781616677312, 0.4364176109597565, -0.07101665704553017, -0.3997012950050115, -0.3880990540522423}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.042150381593127006, -0.3432678103751594, -0.12442610182358649}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.4141357805649226, -0.14053094673648192, 0.4876567051266414, 0.02569205179037337, -0.4830352196034474, 0.23645146142776308}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.47175163893176386, 0.279828271414467}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.24087896202982761, 0.2725525463811289, -0.12780625922573086, -0.21051859555759256, 0.07428626720066023, -0.36280164978867513, 0.3447967252474954, 0.1102315866606226}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.17406178994859334, 0.30602233590342365, 0.3830658866365476, 0.26668849909705217}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.15212072359258144, 0.15123651876921684, -0.25840402125389295, -0.10339056047326567, 0.006187830475332445, 0.044894883276825115, -0.19085737262903713, -0.05709050876908617, -0.12045054313528847, -0.30947300664231914, -0.45819974719521117, -0.31161795687632765, 0.12488781748555255, 0.11667932872506881, -0.03826768208981135, 0.32980412145101135}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.44783318352835855, -0.3553951404239626, -0.23846544944782022, 0.47334417668475604}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.46132479194592807}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.8165862111423381, 0.6542762070992845}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.016068101383409084, -0.2682111214633376, -0.10990760911535036, -0.030840002231699026, -0.4471081587294966, 0.39066777002992137, 0.36874989382068823, 0.43118524456160445}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.33175212417114275, -0.01845458708059755, 0.45754089368496265, -0.06885741082602426}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.25298069840114745, -0.3621654068532182, -0.26731430349292906, -0.37039877345527694}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.19458539738522707}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.5808433954199539}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.7255654569262295, -0.9028614503186962}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.1896730728429108, -0.10813067958920908, 0.12489736444883481, -0.18198505968990597, 0.2358288302738587, 0.07060396050700912, -0.23607003524299952, -0.092739502305076}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2089326970411688, -0.24878693059723977, -0.2868264796760508, -0.24878279510066725}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.16899361566762094, 0.1785535038288948, 0.4819117200202131, -0.15571974598324623, 0.27641581690047434, 0.4187960027786086, 0.14091239633922437, -0.4520216211419691, -0.42232858595337075, 0.05042487643650084, 0.23447478801738098, 0.22807430907352977, -0.036957429186210033, 0.1743946313902679, -0.4509263604774094, -0.4046989623354067}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2518916243758983, -0.46961553897541697, 0.3771710553741944, -0.31641864651155216}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.25922052935698514, -0.12902686759015936, 0.17855148091624085, -0.36582056678554475}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.24654688450279338}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.3689135671827171}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.5562150001231372, 0.6555918164079246}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.025124381286315445, -0.11866145879579004, 0.45554840508444006, -0.2632823757321313}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.01397957576932729, -0.1274184238759255}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.44399022171691527, -0.43561168161659547, -0.18925490651818944, -0.24949882786491695, 0.2636701721475425, -0.07976483508913279, -0.1063206307002057, 0.264938939507096}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4540729858155077, -0.46723471380677284, -0.40590872995870286, 0.4251083221652946}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.06278275226852026, -0.05135979012543146, 0.06147144866431575, 0.3623282046977544, 0.23243943227997133, 0.049807813266369405, 0.4614010839175484, 0.027180503887746954}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2502193767361247, 0.23494984612314185}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.016299816036297043, -0.2185198253726438}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.48301432807541156}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.43768027894025857}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.18934314236263483, 0.577377458940171}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.0030871973009718445, -0.15602266962562517, -0.3236636712357892, -0.48290632944654555, -0.12214610210020727, 0.20565505648187, -0.27604807140208654, -0.22574517610243905}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.021897528586234172, -0.297141761646617, -0.4896062997376597, 0.35761036816006986}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2954292815268289, -0.35064567049926076, -0.1861525341461231, -0.2722152898181135, -0.28936694480704617, 0.16080818490861815, -0.2307926108127134, 0.13193697501863055, 0.19552230504891088, -0.30879221659440237, 0.005560866586946656, -0.062125071639239304}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4627318182562983, 0.36663147014481123, 0.42046520274795396}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4461030520238084, -0.11052739056939975, 0.30521115754810946, -0.4460833651698236, -0.36759613603139174, -0.4196211728141096, -0.20012788003226545, 0.45867617275865546, -0.151777820572085}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.35386547194918505, -0.008245220971501488, 0.45407487507737865}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.2381210148941214, -0.026381416235976896, 0.4711922968425477, 0.10081060293302091, 0.09493433349880176, -0.06906891349437361, 0.2671478331760079, 0.020372180267489437, 0.3214699254343266}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1679171589397216, 0.3757314288483625, 0.08462589036865575}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.15074510567317345, 0.2934638841097218, -0.11745102126603191}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3170114968826496}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5391550407469572, 0.4608449592530428}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.6399652712865327, -0.5133189327166776}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.07308066282247538, -0.3004996176847704, 0.22479523510421662, 0.1524657197079059}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4254815365711676, 0.49447109918903154}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.37832366225141356, -0.24050572418775007, 0.26534945030363544, 0.220276651019504}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.13569162910285926, -0.14674230117747133}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.385383573272584, 0.614616426727416}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.9914548045312248, 0.5260827000808421}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.24321875803082615, 0.029076977547141336, 0.27420344297112886, -0.07974667811037983}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.10157590083985468, 0.37182124732727184}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.34525536058647033, -0.2522381320297885}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.03844870714160953}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.008294908631688469, -0.17501027165619487}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.38725263795083975, 0.07950660636739448}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5183103155508129, 0.4816896844491871}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.9904487039242387, 0.9313089105858725}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.22074245727408937, 0.24108404274210893, 0.03096925770404646, 0.15252589719565723}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.46742812886986096, 0.37720332787535704}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.24801639716038326, -0.032915163389407476, 0.3567512474800898, -0.3181385633340069}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.08303000853993758, -0.3219728226186964}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.0645804830826292, 0.1015168797408067, 0.1312969480049343, 0.4641733877510248, 0.2922591693022063, -0.3137068389343973}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.10091397158142035, 0.3205148986079698, 0.2521648426506594}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3598686924295672, -0.25252248957004775, 0.36012009643041887, 0.1768338751495553, -0.2084156927207248, 0.10199816712787835}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.41932560408288255, 0.42601772432381313}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4999273634026485, 0.5000726365973515}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.5453413868054251, -0.302888328094022}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3587554297315141, 0.10539862057648253, 0.38045865371897925, 0.30586370302360066}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.03277146958894861, 0.005819316224726978}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.1820912318393202, -0.3393693029921311, 0.3335258281893474, -0.3084279740075706}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.41979385713857753, 0.08631725799504608}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.4879104993675376, -0.2590833476140003}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2128231537343629}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.29679325405967916, 0.08596038812401363}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1858218998940242, 0.41975206490890227}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.09091814110731, -0.3015432180287423, 0.3244074227051963, -0.09561094316355001}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2784739043939253, -0.3646238556085275}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4530375564199207, 0.25843393578783597, 0.2885285077922432}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.04187773044371279, 0.2496921370414511}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.23450444276418192, 0.48274680068220155, -0.44688192355478773, 0.47352663863575917, -0.20675583763123473, -0.3680488905992263, 0.1917083124485932, 0.4810655193822686}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.38450307533065686, -0.27260208962249044, -0.2763375306588858, 0.02924739343057048}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.30873881232127154, 0.15460976800985182, -0.32379360409628943, -0.4230826607103534, 0.11595983531795961, 0.22038423215911596, 0.24462016598076286, -0.20141236348502733, 0.37149685126972287, 0.39001249220174516, 0.4770638951573908, -0.1227063380996598}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.34527456301215287, -0.15192253762891594, -0.17944004350242737}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.368865198378658, 0.22232411585662928, 0.4088106857647127}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.5119316541729246, 0.02489911646783982}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.050076923963506714, 0.16667970126778076, -0.19133006271565778, 0.24615182947623637, 0.005938489011264481, 0.1459286992505915, -0.23549733033162035, -0.3375900529124435}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.42026472340444765, -0.45567703170600504, 0.1501427327613113, -0.08639115347287929}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.4171803667889483, -0.4299911230755816, 0.3723286182263613, 0.37811896896082053, -0.3875196434719814, 0.11906004486944022, 0.16787502898194406, 0.2278415013759667}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3070651543259447, 0.35595444379253516}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.32054320875748676, -0.002325014970358308, 0.28510607854102, -0.07259834100619422, 0.33549132738015164, 0.37899348820484635}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.24888744156446252, -0.354611001997021, 0.14910967088039884}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.23705210463026585, 0.23894709183192214, 0.524000803537812}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.34049901881604416, 0.2997475895740642}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.46544724089122913, -0.30310849333923773, 0.355195272820122, -0.09816926028482342, 0.37631176126264987, -0.21241600872422017, -0.2859992886319336, -0.15699409785799368}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2359196045366485, -0.05651784443329311, -0.1780813248424269, 0.47633480612284906}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.011570347968845152, 0.17214666848937743, -0.19226991505187985, 0.17416617668427392}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3941299557766207}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4158651241469047, -0.2865824245033146}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.11742951589695738, -0.043453959334418424}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.13057968835026945, 0.20332305061154643, -0.1755490467405132, -0.4109865281237619, -0.395906147014225, 0.3182625490822726}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3925679180220434, -0.3708262922412441, 0.4819462429190061}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3288356875849158, 0.3312754174466985, 0.3398888949683857}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.2044462750267475, 0.8099682371455721}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.15627065794634865, -0.25036198029148515, 0.14892321930208485, -0.3528131963477902, 0.35832324456633124, -0.2437978555722562}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3804010672561846, -0.4857322117170654, -0.12140305911272031}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.05654806765681275, 0.31742937044823427, -0.4055273218923865, -0.08676591711767367, 0.46680501604886615, -0.3436595297790692}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3288372593051838, -0.15812277386960805}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3580767374810173, 0.1827398119604563}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.42948457191231293}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.029611506938645782, 0.4425277981208501}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.15628549380811807, -0.35242357956792947}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.06889694762458098, 0.37922916890804137, 0.32356293448406115, 0.07594932890383632, -0.3133975439569051, -0.32056777451255225}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.01112404602097139, -0.0037321359253911224, 0.021936542504760403}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.1929681172935595, 0.23615139332545237, 0.3421821332328769, 0.22869835614811126}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.526722424291135, 0.8049697018938837}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.08725512822304748, 0.13312165088002437}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.23269973298214142}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.012347727653915452, 0.1143359387140882, 0.10266568472982596, 0.46336727626517615}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.35332707530975704, -0.15137895870220697, 0.21949109342069495, -0.18344814200419424}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.21848408750440765, 0.36257381681661854, 0.1338191154934276, 0.2851229801855462}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.8870186981084449, -0.40309820549845177}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.39904354211635085, 0.44102932078876533, -0.26685860701641384, 0.04583380569594264}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.23557871514864792, 0.37487201383308133}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.3472562745289425, -0.07099698547055466, -0.08617120550770008, -0.17235250807950242, -0.47107982884052235, -0.4931998735698163}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.24881600966803985, 0.48628870097093424, -0.16309365675562348}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.31048531407244595, 0.22807150071632076, -0.44063200705999805, 0.25139650404315816, 0.45542831413004425, 0.24232410645679836, -0.15625811509113385, -0.03817346076831163, -0.052741412775871854, 0.17486516469108704, 0.2753054559900916, 0.3520086293879727}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.12170298913151978, 0.2931410304636173, -0.3757803982021578, 0.15510148388237432}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.22199830744529675, 0.3282725487279736, 0.26596482383766357, 0.18376431998906606}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.43609569213100174, -0.9782305446749284}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.16796426232810657, -0.260701494305699, -0.22914018775286993, -0.3748674457781359}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1180080024998047, -0.04086525738047486}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.390441087496058, -0.3655651344915385, -0.12373008888733206, 0.14763013675689596, 0.10578855255808606, 0.20591512972546178, 0.27822174291597246, 0.07962286177727462}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.22190086412725396, -0.054395946327356226, -0.3015306441186957, -0.008505227786228198}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.07984101877154892, 0.42246872223182297, 0.3716018270516568, -0.2228730978825273, -0.021974617996755597, 0.37876890908182037, -0.4307618240482741, -0.11918627697394568, 0.3484429837876606, -0.2968127066320476, -0.028294132076763567, -0.30239473757600466}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.0691185454639216, -0.4200860648358796, 0.04390917357117263}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.23158381442550557, -0.08585133288967572, 0.39502126380039515, 0.07909429266561308, -0.2442229504281369, 0.16131533048755087, -0.21621148503771848, -0.22794932272395396, -0.18234478148897604, -0.4304444030293515, -0.03459801483285152, 0.44148053624800987}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.06803548252769587, 0.49362253218153684, 0.33883744368003965, -0.07821867577352226}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.1903746328653984, 0.3593405337111569, 0.19837859895019133, 0.2519062344732534}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.6298948478989073, 0.9232497916754128}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3158319014267209, 0.1777480254492365}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.035436954719714864}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.4107267801542095, 0.4401029484213764, -0.06678741838129842}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.21268796324455286, 0.2823732421328984, -0.39062597306298275}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.1196269340677073, 0.03583505811570464, 0.4521367101243309}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.29031357001044855}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.05378496745622674}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.15842406379398477}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.19526218170622756, 0.33541371147573185, 0.11574210628193993, 0.10577871476010214}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.14540851758275153, 0.4676647255491976, -0.09162718597515374, 0.14883086700779447}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.6150060754118821}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.11221300700715786, 0.7458467368798636, -0.18888795354512822}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.005667981740609784, -0.2643882076973947, -0.22184214241062017, -0.18779277477453804, -0.18181845477177538, 0.44599226257573266, -0.4105693630579128, 0.2691689345654502, -0.26484119113595217, -0.2337935256498893, -0.3596409938342142, -0.19105624083461548}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.2384698729783865, -0.37342533561014446, -0.4553376979798801, -0.08408529287845368}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.20968567687861617, 0.48056643242433517, -0.11480212512130394, 0.2546039364144651}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.46840459260355993}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.46380055173272294}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.03840394273999137, -0.6598106661874574, -0.8167832500139989}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.09301213538363995, -0.40193107367869174, 0.16751954229204313, 0.4713963956048759, -0.0731393127134582, 0.03406752021951365, -0.21682694147103465, 0.15773899158051963, -0.2880020407668292}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3698180246868419, -0.08298314522066752, 0.42785727960877484}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.14704187995614915, 0.15434999485809542, -0.10120288315000991}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.42879433469601724}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.3192689586004359}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2409388125474452}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.641412813705243}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.08348399334405521, 0.57779592553312, 0.9377305455190066}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.10884967724568428, -0.12324620630800809, 0.121215426664253}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4178919419081817}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.1618634917317675, 0.09114939132189981}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3538552046854455, 0.4115330369247713}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.35676789396453334, 0.36264991414106906, -0.12966895816057344, 0.3376532455707598}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3618957995826806, 0.3390613632292768}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.25671566127004886, 0.0787617175577301}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4077116306184698}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.4579384274205672}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.9960688627058996, 0.6960346661863728, -0.5286694930518192}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.23388077182424816, -0.0996101306609255, -0.3254583560069213, 0.49795906256229394, 0.24724207008032828, -0.10926856020272557}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4456500258039745, 0.16704705690070398}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.29547060364356525, -0.12154358382466524, 0.19466029362945692, -0.06631875299055268}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.29923845582525765, -0.1841736909869206}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.45394179850976524, 0.015323367505753471, 0.39027795045485103, -0.442650105601031, 0.39999001349583285, 0.31279194075301286, 0.15229350585226797, -0.08913548278837113}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.24040490584403518, 0.030847587727539927, -0.2964975674672079, -0.41150272189203974}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2589442440204891, -0.3725682842323832, 0.19977273151555763, -0.19290045841773373, -0.23568871262244406, 0.15004552895997392, -0.23282277349038205, 0.4200271444995026}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.19566098557771294, 0.0541815648689048}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.4830418886493204, 0.18640638966202983}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.050014521117800026}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4067690028350572, 0.5932309971649429}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.7861660841081397, -0.2732136644862886, -0.35921486256586577}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.056174265611114715, 0.3100194947800986, 0.19523137611529018, 0.07634715890880839, -0.2780055937902093, -0.3304881989199119}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4291520003856828, 0.3494599143329511}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.17218033989570647, 0.21139010044824402, 0.2387291187217886, 0.4446477053755482}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.012205582068202214, 0.25221057906302924}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.42374755512232726, 0.5762524448776728}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.6396295197944157, -0.46759076680584366, 0.8421733130250493}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.1201953598904757, 0.34931122790539826, -0.3554250275617481}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.09207621985359038}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.26312695384450135, 0.47102692449381334, 0.23206876265997922}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2241869279045634, -0.24606339279621903, -0.27702715504967024}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4152549665356252, -0.02361151228614844, -0.09198055898601976, 0.34614813828823543, -0.029329024290685957, -0.18216548466088167}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.08784703687450901, 0.3952549848590048}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4082721741044211, 0.5917278258955789}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.7152511375448578, -0.61751413882233, -0.19076769522988246}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.276126912553892, 0.019306807610944166, 0.29995084678173733, 0.31582023876382803, -0.10953186575986129, -0.15607094715063252, -0.11665710887465486, 0.1932522165040077, 0.06299044940496024, 0.027303228807485147, -0.44369036258133177, 0.007404832738755696}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.33648532776120166, -0.3154382491771376, 0.47476690197874827, 0.4731603274269002}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.07754603227170775, -0.2446126325118969, -0.25975304308400715, 0.3615100014740583, 0.04443060699734147, -0.4372738952988734, 0.406703937456804, 0.369121221262782, -0.41457770445929676, -0.2989607815825832, 0.40476432896615944, 0.14903355048854872, 0.4070715545108924, -0.31905286319821946, 0.46398034123024434, -0.13248116438813362}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.18822335119987255, 0.42686093365864475, -0.3135490179155014, -0.10252479001578974}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.0592415831896822, 0.2968517589350036, 0.13179397204768994, 0.40657404387900353, -0.4331852372423457, 0.34591262194515504, -0.23683035319195544, -0.21940459507462862, 0.456180804290664, -0.06612290343563998, 0.034063463635502056, 0.3043705501430124}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.49654991151176464, 0.12253788667874266, -0.3583238806892223}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.23010116096423583, -0.008272906185094575, 0.49185808217287796, 0.4495559587935165, 0.08121174304219192, 0.19546875683222065}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3364827082713635, 0.18389137901973485}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.399737179451136, 0.6002628205488639}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.33079616131294354, -0.4389982151736602, -0.6287869428596087}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.45600819586574715, -0.42622456593161284, 0.06837500860728785, -0.3755575878687052, 0.4636696482598738, 0.1876331557908405, 0.14948367524571027, -0.12163020387900325, -0.3257475366175776, -0.19821779935088368, -0.1976861871170149, -0.023960375411999246}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.20630113757737356, 0.45347979066768673, 0.35918777605895247, -0.07120149402800302}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.4306337662244414, 0.2327093197464033, -0.09257587141189627, 0.31355841762075776, 0.15898277278913997, 0.4931270562202532, -0.40033125139500203, -0.3937558170005596, -0.46303449691392495, -0.31094104473871953, 0.22896680519468504, -0.31689838276031956}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4839184791799933, -0.1434549045802921, -0.10640018715020394}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.2657952639230494, -0.1129113602250601, -0.480716326020169, 0.014014954739071994, -0.23719515639154864, -0.034491455969586804, 0.037819172550746405, -0.09175624695633133, -0.2418530833015946, 0.14382888756160228, -0.49287748413807053, -0.2815693676717371}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.35350473554850503, 0.45085148504865524, 0.08517605554390983, -0.42078306043478086}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.2312568893440028, 0.3100148190377029, 0.18376752091877846, -0.2907705195810051}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.030937173879239888}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.35723335101013465, -0.006203757815054889}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.016367479808949148, 0.46817064740388137}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3441454465099054, 0.2591776657266802, 0.3966768877634144}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.8097896457636042, -0.9832935423550595, 0.06169920784353011}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.38725381181600804, -0.37640331805516225, -0.4735514065938268, 0.21592984292016337, 0.37447761834114346, 0.08471545879515929}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1593781845051413, 0.40052677054076835}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.04857999706479288, 0.11350184856741408, -0.018162725360565846, 0.314316503874994, -0.01884700687833729, -0.38189931088129925}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.31389134326807444, 0.015280769075606382, 0.44122783584052605}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4599734740577226, 0.36137222230634114, 0.17865430363593623}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.6333038594240039, -0.7497475243768588, 0.9674251718375673}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4777498612584383, -0.05201925280572961, 0.46274200161747525, -0.4574445992881544, -0.07415404005387094, -0.003231860826117372, 0.056865639687060154, -0.17656268591529278, -0.44768724775965285}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.07047676487917753, 0.434104674078568, -0.1901106754570545}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.08680996311370937, 0.29953186660075637, 0.43328804116847663, 0.04292326684651959, -0.42059845265924267, 0.1592940347837385}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2931089647676163, 0.42196650378053824}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.3842890587682338, -0.1588127386256638, 0.07708511390618167, -0.3218312642479334, 0.06939018564786859, 0.08814747764070852}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4907554152999689, 0.4123942938838112, -0.3402843376890037}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3487958083669105, 0.26478582364981695, 0.38641836798327256}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.8846412009491065, 0.9906948848814556, 0.4419991840373425}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.34604838580196406, -0.13133926256155604, 0.46599983896382446, -0.37519940584979083, -0.44719056461334117, -0.4036456610817716}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.20169412582988167, -0.23029099920786666}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.00133605021294525, -0.3184044894121155, -0.1148171971800449, 0.4885968217036276, -0.30073493916647287, 0.18174445583029142, 0.1706509527775244, -0.4851302543493661}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3096392321171565, 0.4850802776452313, 0.1569855620518723, -0.056070116065299325}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.28513741649563495, -0.2403530151630553, -0.22230945083613352, -0.1960997050301253, 0.24997367693364192, 0.07205276969840169, 0.2347668096392317, 0.3933050574299275, -0.4515238433395794, 0.05182095420042343, 0.34169810543946055, 0.3672993282696111, 0.24544978666245043, -0.031625922401916085, 0.0005086793781924337, 0.4569166526888777}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.08854728588139416, -0.3401537773355664, 0.41051449861565337, 0.01225849210420149}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.44248397156332764, -0.45414006928779604, -0.14957229929888072, 0.4525250785434163, 0.41016383929606604, 0.02956708637909511, -0.27443703903928884, -0.4605924506851067, -0.237606156799808, 0.49793998318501753, -0.40343840949123433, -0.05394288631370181}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.03490681786958705, -0.13227954444725287, 0.2583737990931223}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3591149513552409, 0.3849600705957717, 0.25592497804898745}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.8171656816971702, 0.47772655651189444, -0.467969310532657}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.29710529204263925, 0.40881314739669383, -0.42310969427528766, 0.050025690572022885, 0.4581987635538678, -0.4033879864833766, 0.43225887568219823, -0.35121141804095135, -0.2383061342461874}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4274888441663114, -0.22290104502548458, -0.47583755102067826}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.26757725335039495, -0.46790660001561146, 0.4318933798692046, 0.2296363231890679, -0.362922169134107, -0.13962690177313808}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.49598827429058934, -0.1495450630582511}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.2757409836660797, -0.09658056182896146, -0.1779097310409442, -0.18071872632847463}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.1748604573904563, -0.49488067414771164}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.03413405674296843, 0.2914965118495577, -0.17092260748480026, -0.09746456578475937, 0.4478953040062035, 0.37808769536604414, 0.04645811358404828, 0.25808116942632797}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.21221949184748978, -0.4313924619166244, 0.45165850842221733, -0.31422419917913724}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3910872654730889, 0.21745744475618056, -0.3641790171669441, 0.46765839755307936, -0.3351616377039722, -0.48856770858436716, -0.2967420139814514, -0.43364649071148975, -0.08007720670335794, 0.11692376161772666, -0.49480666838575704, -0.0782085669624456}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.23104967815617694, 0.2639626597706838, -0.03684393140472886}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.19019417915782888, 0.2768243823462886, 0.21312435049965994, 0.31985708799622253}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.23140121452433116, 0.2877241071388019, 0.7496645004110134}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.04299920505153265, -0.2979868856257233, 0.1904114537738879, 0.13607275218934378, 0.3892609571376391, -0.1829934577804937, -0.2868368837336741, -0.42041517168297426, -0.46309760458414806, 0.029127826434659942, -0.031030628197171506, 0.1492526681265004}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.16517139193634411, -0.008538606744654564, -0.3908869610528185, 0.004157476093577639}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.2490806765311867, -0.3335404253683478, 0.3608499374346722, -0.21942869918208652, 0.2768611229807002, 0.39359025974005046, -0.42116465881915444, 0.17097440194344682, 0.1190999706245095, 0.05820860415541318, -0.1430420624094202, 0.10103069938046005, -0.050496598690611516, 0.2194042776608055, 0.2765111060421397, -0.13675414312663836}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.13269436629631914, 0.2034553443533207, -0.051031322531828405, 0.3788356418476295}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.24865547748092431, 0.20932511315661007, 0.3027838578950526, 0.23923555146741307}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.006677301257975277, -0.5612237699354381, 0.06659913831797248}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.34096694233919955, 0.0686886045679973, 0.31789693316463685, 0.18942619965841279, -0.3039534656708819, 0.23966252879545913}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.41117497370339584, 0.24993732117463618}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.46148041384090277, 0.09336780305078152, 0.23268731016055377, 0.0072469193464541615, 0.4143326270341362, -0.44649745766844007, 0.23085895864922523, -0.40394313963688455}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.14568890534828582, -0.3012090148265798, 0.31610606364063754, 0.4205489367431515}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.2288825850662306, 0.3631008116964505, -0.2525294977206145, 0.22374217241473582, 0.2567793503647353, 0.34783909257045076, 0.1052004223625358, -0.13676840266717782, 0.07147546785019543, -0.43233867981977436, -0.18004267960534293, 0.2661403726360868, 0.0968897456459249, 0.09777647942186862, -0.47072152239301335, -0.34206417156279}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1306975325345111, -0.05898809936995142, 0.27013840953529533, 0.3190271249513974}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.19923607239285096, 0.26702368898457984, 0.2039852542644622, 0.3297549843581071}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.10745108188712127, 0.9701091011094771, 0.04269684926231765}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.30265952857492295, -0.1813501644764718, -0.03634520705406874, -0.1541765201173012, -0.33356217099948426, 0.29443365130961063}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.19273102137617604, 0.1828113651751161}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.08722597852736802, 0.175658994079246, -0.29738212760011096, -0.16667015910822192, -0.2119376334108457, 0.4323634825115876, 0.11248943984306237, 0.3946387002249978}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3213611882295003, 0.09004787364008371, 0.19555250851436334, 0.39904616357818656}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.05914460026159141, -0.41636664161907866, -0.2601057836853914, 0.23411204377677763, -0.022197237719428164, -0.2666582957548397, 0.34127868675952355, 0.43073623334758115}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.08707343274431689, 0.3785139549121177}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.48836682892022876, -0.3454107414291566, -0.4391112070234955, -0.16671630671719517, 0.14997121619145393, -0.29896628728676244, 0.15652568221645835, -0.4859985063804949}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3026468333602029, -0.11578773741816173, -0.3066368368100698, 0.28459856401824235}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.32210860405903924, 0.15529904864581454, 0.32668855437088473, 0.1959037929242613}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.8942111865805282, 0.8271703651840263, -0.8939949345551517}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.09256978029195595, 0.3951528305665293, -0.29539357873347294, -0.46177904634124767, 0.3601700352220283, 0.13808561491886207, 0.4823222942663369, 0.46840324107927334, 0.26007910171648463, -0.3545322641568722, -0.028102484494113678, -0.32732366566928406}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.08661883367354672, 0.14488821087400272, -0.411567358097101, 0.012815157966155732}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.01603410078862888, -0.09485294622110929, -0.20122536363686006, 0.07807566131000998, -0.4734023928384634, 0.24068313684559184, -0.47967884514403825, -0.4039753302881408, 0.06296359761155934, 0.39734687904998656, 0.48290068638015937, 0.49174581503487746}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.15283250755074973, 0.33449209515354217, 0.3813188816980163}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.15748104007804287, 0.21271621224693693, -0.1140946101201088, -0.4069498812881396, -0.3344777181297408, -0.22816983667329027}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.14539598903115147, 0.08448267343020255}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.2854799070857307, 0.09701928300662255, -0.24588640180483767, -0.4454733836604853, 0.4525714575179951, 0.39921702613821897, 0.33952920376556117, 0.06489755685023424}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.010261035487866943, -0.08088879255270964, 0.27442207100123683, 0.334055431281005}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.1409736753486297, 0.4173441960407681, 0.037792338610018295, 0.01878401812616004, 0.4242006400557946, 0.14980810471058925, -0.3417689453631786, -0.4363376237726406, 0.39679210846300617, 0.19003770436345468, 0.11269862061740887, -0.3768253589616565, -0.10821610007044369, 0.1566840875520632, -0.37408080061062043, 0.14745747812237497}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1496320011204728, -0.3266145149671863, 0.27272507870546014, -0.27503312413855263}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.5914330977576051}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.053926557153265886, 0.19206257400058324, -0.01986593078439758, -0.1211632376042926}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.15626905337086117, 0.026109650750120394, -0.0282639870303234, -0.13429781872112212}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.0037531838756300617}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.22554760910316551}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3720734663511871}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.45289028611619314}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.6993969576864578, -0.1852574080188507, -0.5022824087050146, -0.6847588869225989}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.11415789230167572, -0.46784077877766994, 0.4690254995523482, 0.09711329882904107, -0.396815618184576, -0.3633298465460991, 0.48200255249823476, -0.031845084637938115, -0.28723368237078895, -0.2704462362996577, -0.28303861263355745, -0.20029286104765753, -0.14271201960844893, -0.23194392377587236, -0.1668349360430058, -0.4866966942600973}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.14405975671687377, -0.14772731218984392, 0.4132463758475077, -0.21746710211089926}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.46870221705254855, 0.38960727936926487, 0.05963897370033966, -0.0276636270580628, -0.16675978929170165, -0.27826468421057415, 0.3360148875581336, 0.316407298716916}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.22418671097974519, 0.11055558706543878}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.04159578082553084, 0.437517524693827}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3472847005991253}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.45214158925490455}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.9585821742127811, 0.09500461071074295, -0.4783105286998557, 0.9874293069480502}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.22087610438540983, -0.1845680039757034, -0.09622447639000153, 0.4394750637020659, 0.05601635999018728, 0.040090339817846155, -0.1685218442788149, 0.3700780006006238, 0.2771549989529979, 0.14499695361076004, 0.06984826524318899, -0.40967315213078814}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.13115551570603656, -0.3203270193314878, 0.48491814987455084}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.4923077255484116, -0.32833916697504584, 0.007853560468215504}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3943838125678274}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.36082267918244193, 0.26267273370819544, -0.4953325777766642}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.28800431072177424, -0.21660076208684764, 0.07133311993701463}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.28996087902869994, 0.1697688737187536, -0.13915711378899442}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.18209498657935053}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.5831908141430817}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.48670911443026355, 0.438976939355622, 0.5645659140510897, 0.40629990640428026}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.4322632916913779, -0.25902318034531835, -0.33029155235245555, 0.3194366418597586}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.31032916186041337}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.3529742744062069}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.21020801724201654}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.42363887484318696}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.18151440501063398}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-9.026173787851643e-05, -0.11610480720724681, -0.29131116822726955}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.09322651616859445, -0.13314716154828743, -0.36026850831180846}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.35732411805462116, 0.4503199168275519, -0.1528212474553966}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.302573817917264}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5998477432762727, 0.40015225672372734}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2951488227589443, -0.9535474872099938, 0.2784995692346126, -0.05140759782619875}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.48697195629663825, -0.31468798676313714, 0.2884737307920242, 0.21141041760473223, 0.12582931174115686, 0.009178324367550394, 0.32854365198414504, -0.12641605581472004, 0.2429799390310018, -0.44651458928326593, 0.30680829584057046, 0.051466891561353756}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.26619331418818415, 0.05692812583239826, 0.4713240466561368}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.2769450326926627, 0.01373378773782663, 0.3293762204807429, 0.1857044275360089, -0.25145444354326596, 0.017151143596459972}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.30037344487450457, 0.1581844860664663}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.6161118710342632, 0.38388812896573676}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.6378216921123718, 0.12053770696242339, 0.5634984056298127, 0.2857062382538511}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.16278821055713666, -0.20121070553701637, 0.2857447897295874, 0.48074888508443825, -0.10101488224752475, -0.1991277944805303, -0.41481994534150346, 0.38874959589732505}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.11189414368748363, -0.22126398847627182}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.1502308942513918, 0.12825684926723702, 0.02523021865603481, -0.06662787008076065, 0.40373219607382116, -0.10486345739885017}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3999891396525481, 0.19423221531571877, -0.26038075519320913}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.2932055244029321, 0.400637292061631, 0.4786559276553769, -0.42608515620322573, -0.10837214471904, -0.4708524594819513}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.03144425010159957, -0.40490569879098626}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.5798005458341127, 0.4201994541658873}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.7202885829398131, 0.023971493107912467, 0.20948444817975354, 0.826791868415435}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.4484339033929453, 0.4493241722775465, -0.3060931160576562, 0.19377582745642852, -0.4514873034915877, -0.10058755715387835, 0.17371636992876427, -0.09407475831566736, 0.4828258042739385, -0.11764202900626097, 0.18485482658854613, -0.005290337693668379, -0.30058535812457854, 0.01533434155566693, 0.26204050626123554, 0.07305557158416864}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4423900846415795, -0.020771261450569845, -0.18522796810606135, 0.10659578213198762}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.043594742401992015, -0.28912783121913876, 0.45453394189954777, 0.19010191008603794}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2614338731026078}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.010738000152994864, 0.14006973649505672}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.060712449225317044, 0.0007247785453028399}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.4899792434831428, -0.32831014279691206, -0.05516653394341031, -0.09383870195472521}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.1876556015523856, -0.13446900679886853}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4541963955041644, 0.5458036044958355}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.16024234150806205, -0.7840463951295784, -0.5888544532085274, -0.048351374090508825}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.39756680113541343, 0.2559152032379054, 0.3819819605907506, 0.3947250473862379}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.44625868547987924}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.04104597504357366, -0.21266824445894017}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.36120308595814765, 0.015579241043764402}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.14419421406537536, 0.16217503879054718, -0.06834638221530775, 0.4467123979673834, -0.2690848660233769, -0.4309298932479483, -0.22806911876226788, 0.05151441186309724}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.27400861056743897, 0.08824059322478994, -0.42669809572784634, 0.10537736952604315}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2906513743014838, -0.4598559463859647, 0.20581915500491854, 0.3399104078779168, -0.1350263605478541, 0.0727292502586494, -0.4071033388932175, 0.29994905327082244}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2639013042128686, -0.1011405037920664}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.2681971566805672, -0.167051922865609, 0.17395189850755088, -0.014936308849385571}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3641326597187393, -0.1804031411243433}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.509132895488454, 0.18185787961940825, 0.3090092248921378}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.9941860024374249, 0.8233603036875603, 0.4702715607875221, -0.5517509244577965}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.23844039094963887, 0.10873060502412668, 0.016104453651428763, 0.09248846420067802, -0.3390854862265843, 0.0688575464558484, 0.26157672205576044, -0.39674927880920485, 0.14771296207280182, 0.10585664348673063, -0.38775029220930435, -0.22860446181098926}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.44847019210828754, -0.4781054518650125, 0.12809979514240322}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.26686518443256024, 0.006179902846481955, 0.40293726774002303, -0.37015982615680887, -0.03414607542885839, 0.4234638265155256, -0.09603149084654672, -0.043272401749860245, 0.22200048031830377}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11606837754288679, -0.4536520427836467, -0.062429394542083516}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.21359805585329716, 0.4281243614783321, 0.3582775826683706}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.5569884428468999, 0.15955591697917093, -0.09571647155429797, -0.38840222696329674}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.1782648970838383, 0.001895491423240303, -0.17902110004505456, 0.44533991657753413, 0.4224207168692167, -0.33083640561310657, -0.4233968634132712, -0.11580552244210807, -0.2034745968476398, 0.2720208012301182, 0.10106064782049884, -0.3853378539265273, -0.19533425158561468, -0.1111785496035611, -0.4409380174105709, -0.2829601744747081}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.05157187183681666, 0.21457370715412938, 0.04537385799038329, -0.21404436902563562}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.18321840831817582, -0.44687145218001445, -0.26397464755291766, 0.2677657394876469, -0.4589848458187815, -0.4112602379426219, -0.31069171517700156, -0.0959744063653728}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.41327976450671366, -0.44279868674402734}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.2347980208056667, -0.23611235919357088, 0.04732567343493277, 0.24068760542963963, 0.1880624284322877, 0.3032512039316084}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4269768558665059, 0.2996784195955873, 0.0980474386639063}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3537177190869329, 0.2603651225746721, 0.38591715833839507}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.017620048996604964, -0.2510137149420961, 0.8632598819838564, 0.22793017780574054}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.1545050618153283, -0.09411233413752684, 0.3856461965115159, -0.025112139983366144}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.40473992786232627}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.261013653236559, -0.42274241242670274}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.23170368295798893, 0.1175759742651078}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3703110061160244, -0.14195054260650697, -0.029887167273655257, -0.32799594849369385}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.34341063673303773, -0.19577594605567372}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.14506343272513578, -0.4292998291850867, 0.3925113040430749, -0.4292045057945172, 0.11363842862548579, -0.2638010063974747}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.20269972047577178, -0.10371450737467325, 0.2898232598746213}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.341328617471262, 0.2758564129231752, 0.38281496960556277}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.38715384824065, 0.4901070234239011, -0.7318507575672275, 0.5960078955289763}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.06609356978459635, -0.298241589825908, -0.0668338593587603, -0.40171176946447273, 0.48248176707501933, 0.2977282261573494, -0.32698127900554297, 0.4174873782575116, 0.21658624936294812, 0.347443877444106, 0.3871204313032943, -0.28869549361112734}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.42247859036507296, 0.11769018117938113, -0.47889674085155987}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.20434172219322444, 0.27872329790271577, -0.39127166431326077, -0.17953685381772921, 0.47422772739527663, 0.15734991127591158}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.04801415415547028, -0.20456638919142345}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.21237581021693952, -0.4074862091449136, 0.27220825072859967, -0.12737803370568335, -0.39418354541427225, -0.33182664875370693}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.17613178619752012, 0.1325421619798397, -0.3548038055479461}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.24811004034354078, 0.047101949249179986, 0.13440011330487733, -0.22113561076881938, -0.044659576683930724, -0.227572365560073, 0.2635718046780309, -0.2358897644109098, -0.22556094757404455, 0.09250562702642096, -0.466458363684778, -0.41423476381982294}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.038414030360428786, -0.15565955149896382, -0.3713901282429587, -0.2742268043116519}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.06029689591449938, -0.017278764413978465, -0.009667916287234068, 0.4945564351779662, 0.06338942518942436, 0.20193000233920533, 0.14571560605840161, 0.375139142482784, -0.0756167393564775, -0.016640608767385046, 0.09718402955437566, 0.17533168647380293}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.21301632182197194, 5.110830004906308e-05, 0.32772238535510134}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.14409583463333658, 0.22499301677147757, 0.2513785563024008, 0.3795325922927851}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.5056069241695604, -0.9702182650041846, -0.9306127637524435, 0.20902959232224738}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.2996874140678617, 0.3718948081735015, -0.08948565741168035, 0.17246061459645856, -0.042505848167245786, -0.02284402717174483, 0.41567965880936464, -0.32366227224892896, -0.49290640363786364, -0.3733884643221632, 0.11068282669035623, -0.15464322136083675, 0.01322018017011628, -0.4322477057578623, -0.37592440191715915, 0.39250941253650184}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.14408360896972783, 0.2981313678498956, 0.2960368052541099, -0.3699960760314993}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.4696500751424305, -0.2733223714258525, -0.45017712753568706, -0.4745069195210808, -0.008175069674740576, -0.10029488574218814, -0.45373387216761496, 0.43367736779597466, -0.46014394113726476, -0.06032008485927476, 0.4276775749168533, -0.17731026145481188, -0.19227834951781853, 0.45385194003752816, 0.14822060199896625, 0.4261956065784315}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.32141802474229775, -0.34297350255242676, -0.15078964381921522, 0.02871968338611275}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.3777747490524693, 0.1953349216742415, 0.2570916960397239, 0.1697986332335653}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.43495191102047936, -0.8953011457888902, 0.9423634001227406, 0.7424942538067782}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.19386289922540312, 0.13747126331786708, 0.11237588806001719, -0.49749493105111187, -0.426611568568926, 0.2669919894121693, 0.3073281349660939, 0.3292023316794406, 0.1344138713754488, 0.12067934746804487, 0.37879167213414133, 0.44408378175592034}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.08958608526972023, -0.1634869901867877, -0.30288446506949573}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.298831096389339, -0.026716919448392717, -0.29385783965036993, -0.25306893891567384, -0.07407214807297846, 0.15745373307506105, -0.44209411261199116, -0.09981405016926936, 0.06783947216397146}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.40505448429982693, 0.15471485169956078, -0.3409142774501521}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.471593662609626, -0.21411617500004698, -0.01107198035262269, 0.20350491976756813, -0.3777406306221367, -0.46345319422563436, 0.20468741276339764, 0.04264003675017669, 0.4767952828363117, 0.17023523269756458, 0.4302743708675888, -0.4226236500992461}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4343540516538068, -0.19130259657919302, -0.0037469893011153887, -0.4989385426145506}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.318008450357006, 0.2646569466809876, 0.17047413635683328, 0.2468604666051732}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.5494389115837317, 0.5442036856842645, 0.9459402869641247, 0.22517720763754157}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.14168512977118264, 0.2767607830158837, 0.47697890287221445, 0.4880519011417115, 0.3697471939987723, -0.17244771590439056, 0.19619120927711775, -0.1396459974335913, 0.3139994373203062, -0.27084346985176944, -0.07710143026646732, -0.21380998115900263}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.22298592452158383, 0.3395641331230028, 0.4114566408220265}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.214092088601482, -0.4894400533899337, 0.18246585590026065, -0.2821502857470063, 0.08230723602685486, -0.18961820721685774}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.12662410325446516, -0.2866803838997749}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.0240017294866548, -0.4126626798623715, -0.3379119620820472, 0.04560214570660204, 0.4710491640079727, -0.13419864989833374, 0.44765978749865265, -0.2182995264947164}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.49659725273679123, 0.30961059573478145, -0.05321158079032362, -0.3516565233505926}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.09635890288131788, 0.46300791745497627, 0.4720325022052063, -0.20568243694009747, 0.16710648767084302, 0.024331870281548595, 0.37440057346002176, -0.45112911198239614, 0.06267409736992202, 0.34515055604840783, -0.10325934259573744, -0.2364414576432773, -0.12389639019471854, -0.3214317751632647, -0.4450259582048105, 0.07955223391064847}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3539755168654003, 0.1496122295427741, -0.2923789264725054, 0.34401103231201435}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 1, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2554390550453693, 0.29859538505491573, 0.2746718845711669, 0.17129367532854808}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.41390978387194655, 0.644911966973676, -0.6764356970963075, 0.2725582566902416}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.12790992132742451, 0.06409652260796361, 0.19363419719516173, -0.025465380446663688, 0.12859772833485072, 0.4120499210787303, -0.27500736268992965, -0.039176763079194155, -0.2337680109409691, -0.17867216394771612, -0.12108635215197328, -0.4682409397520536}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.12639386320168522, 0.06418442563703564, 0.4673734698644424}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.13116224647633967, 0.09572945074232997, -0.19726967950037322}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2350639944707369}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.35116652663075953, -0.15163898277158272}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.0701536884038455, -0.32535754574066733}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.1480643848864529, 0.4582197571409641, 0.46031807166630856, -0.24100853920499232, 0.006287077471172631, -0.45233607015431043, 0.363036600112449, 0.05668606066331383}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.28001942955837766, 0.15877435179546773, 0.14212812732465752, 0.31307813132833173}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3508051110794621, -0.41145607834141196, 0.1437369664749637, 0.11817324012409292, 0.12851991058940315, -0.3865019719482119, -0.14895219973335716, 0.06897963971607013, -0.27024988518254933, 0.4078334068067516, 0.3676830359786809, -0.20973397667699012, -0.04853632958984444, 0.44426546496022956, -0.2623834546174655, 0.15930110679138898}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.15846676813060034, 0.2444737249319513, 0.11460089846905641, -0.4674018009160371}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.48523760944832867, 0.4436307370962308}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.43530775451630954, 0.9775545971065835}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.26632356105140353, -0.08318259960273222, -0.25146009672041036, 0.17482845922987322}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2022064723476955, -0.32854945641231625, -0.10485978312785882, -0.18512396429734623}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.44667438359786893, -0.1885197821372686, -0.15230870564298393, 0.2104640609989341}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.019829411823617527}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.49614904294334106, 0.4961506396723078}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.7121976013912177, -0.5398537837663002}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.01779906672318765}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.24432746729840893}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.01663854369642903, -0.24319436818050588}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.42674059713242996, 0.055292827448197635}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.1251436149507984, -0.1589178492841522}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.03751738267012383}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.5976183538872106, 0.595461142237688}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.43719335816472316, 0.6095482491866284}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.10547777850627738, 0.18051173120493302, -0.1436962434003064, 0.06874185186811521}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.17616139809470455, -0.46810339061253425, 0.3717648402691619, 0.04414392582940618}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.32936437136081, 0.028329100990470035, 0.4503574300037724, 0.15918138161604245, -0.1763117477254983, -0.14841802230745704, 0.35884541242991297, 0.34283931400770895, -0.37070441827021916, 0.08776825630348206, -0.08668353280809793, -0.1006673767472186, -0.3167209378548126, 0.38990008572414336, 0.1069052504535104, -0.20164625919485935}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.15344108266834955, 0.3311527793888632, -0.006665143151035946, 0.13861545357521698}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.47462227215316544, 0.07789630367493039, -0.43440269050460145, -0.17040366353010472, -0.05678914378209465, 0.3331497946816968, -0.24851785185450437, 0.22683216487504276}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2861579871917238, 0.21553187815303743}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.1271575533270365, 0.3845483905468583}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.25752763031927517}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.6081245179622807, 0.6081245179622807}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.613755483399872, 0.3685875406567636}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.40807046212133824, 0.2663473711973452, 0.19709930742290382, -0.11893689300196575}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1371482123281279, -0.21610500356842466, 0.1140589210618681, 0.00024041402663155242}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.43827267280463034, -0.22399608346147837, -0.1841762648272136, 0.11398480944425826}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3156984463411472}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4348945781256828, -0.05505416997481816}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.1732103776510754, 0.2469007842830685}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.2436676899643302, -0.4589740458644217, 0.2989436467764931, 0.4285228934676034}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.28448999516677864, -0.2972404666237948}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.24497414603521828, -0.13268571996792522}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4394355188109913}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5482860324729755, 0.4517139675270246, 0.5482860324729755, 0.4517139675270246}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.02254974945755417, -0.1012818725868585}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.20008470550998048}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4707114966166047}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.10495165382532023, 0.03998019856933843}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.14208070920946758, -0.05166723431933362}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.30032352533246937, 0.6996764746675307, 0.30032352533246937, 0.6996764746675307}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.21352870849466798, 0.5302487492064181}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4673644570748312, -0.2702438693634521}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4829814430481377, -0.1358900628800952}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.2531062335983585, 0.408873728859913, -0.45843107089341206, -0.3201540467265147}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.42502995533021504, -0.027515659625799382}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.2634771956621873, -0.4811506936141793, -0.20361952713808862, -0.3452045676053024}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3429168618160572, 0.47739957380796516}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.493293111644113, 0.506706888355887, 0.4925584907148483, 0.5074415092851516}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4858350918496712, -0.46791778639935266}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.256155778923876, -0.3038932247277527, -0.2602436763852628, 0.11071185266252981}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.000439230781875688, -0.3579529020046105, 0.42395334377477567, 0.29847638909909324}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3061418806611824, -0.005749355811777379, 0.36404729193020535, 0.22264951428055235, 0.20008997399264672, 0.3467803031668014, -0.3794710863852617, -0.10795841000697759, -0.10047243285292284, 0.4215734834227719, 0.29245382964459343, 0.016308149438289066}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.31449007019556263, -0.07377014593409403, 0.15147419050204325}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4905337389552422, -0.1949044404303023, 0.29166550152871795, -0.4790118619403947, -0.3276595971053865, -0.33024969776171964, -0.33053740071251503, -0.35762208724911904, 0.27477059219693245, 0.15513755905920323, -0.19889519596616567, -0.3019292539206302}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4368365125246999, -0.2501277395283752, -0.07785904527510057, -0.010574560450877568}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.07039136775695232, -0.044291018681262284, -0.1603431182528663, 0.35307366508149884, 0.3461403442648697, 0.4560896820816095, -0.4914168185229324, -0.40870248286640576}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.43075227623230916, 0.31748172711985234}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.37681729124289687, 0.6231827087571031, 0.37681729124289687, 0.6231827087571031}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.26421233400574407, -0.897005795163581}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4615367231122076, 0.12159099883840507, 0.42688438145904706, -0.4971302079551698}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.21267690772089476, 0.4733525139188244, 0.3423233771108797, -0.18729511138648947}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.1858813949912993, -0.2844881151591804, 0.009760971144502806, 0.41047118785922077, -0.2985434316739297, 0.48212937073420614, 0.10145487101982298, -0.03650161724016843, -0.23722985821720144, -0.4407160552301037, -0.2613254917633636, -0.1427224125221218, -0.2111220805465469, 0.024781603138933073, 0.11878717432033259, -0.1467785183889242}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.45173013134157736, 0.03623114787323212, -0.46473177635600293, 0.4356788856748204}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.4940851386123728, 0.37854475080965566, 0.0004316998977791364, 0.3745871807074569, -0.18269428523681086, 0.28808918809367356, 0.37240003290798074, -0.29279306444305886}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3491374190773857, -0.30333036882069486}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.23030657953717326, -0.16394758311591362}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.28650242986118823}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.00218602108510757, 0.4512012157451245}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.276850029444732, 0.22622928747030857}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3776447749583501, 0.35061835692090837, 0.27173686812074166, 0.3776447749583501, 0.35061835692090837, 0.27173686812074166}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.28265817696980555, -0.570876403692204}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.40463970054225595}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.45740467277441}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3106354087917519, -0.48144074582147167, 0.3015809323627615}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3211577386268989, 0.24690206333981546, -0.007962064913557776}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2521804425224687, 0.35737837546463247, 0.39044118201289885, 0.24855246787009588, 0.3595734095185659, 0.39187412261133814}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.8302560340405114, -0.7396487125833051}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.34666560511944355}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.011493777190979881}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2784690826909987, 0.2985775589287252}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3128041809357912, 0.3095550915467219}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.48651006037650835, 0.29691402349993334, -0.02486656200170334, 0.4968027219617531, -0.4603522448018458, 0.11817148594773175}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.23069883325516816, -0.06771502030618537, 0.27173626611816815}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2357122386152825, 0.32112558244057177, 0.4431621789441457, 0.2357122386152825, 0.32112558244057177, 0.4431621789441457}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.14817397932819798, 0.3983196682302781}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.2597600387827279, 0.05132742575752358, 0.05418293624842707, -0.09495761848183204}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.34292324463359614, -0.408499160198769, -0.4284445700958647, 0.42761598254460575}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.39219856988217106, 0.036069492366794464, -0.1848560285270171, -0.27218286025334226, -0.039785775979480964, -0.005038703807577316, -0.46764376316716805, -0.020736089053839835, 0.04821439342459799, 0.41715327451391815, -0.11896077429729923, 0.46494761578499477, -0.47524104802445866, 0.4042661544107812, 0.419749698105095, -0.05617099104318368}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4057861098333956, 0.39852572298567546, -0.3348715764214827, 0.24729505492519632}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.20608382345776488, 0.13194425917962838, -0.27957841667167305, -0.12365402993452301}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.09966541331562273}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3347004354871468, -0.4812750659991518, 0.4040551905972658}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.48374531021499134, -0.174524774175431, 0.147578752120208}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.38048969045094844, 0.2732520447489359, 0.34625826480011573, 0.38048969045094844, 0.2732520447489359, 0.34625826480011573}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.9582053561660644, 0.7535352729212441}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.020486762189545815, -0.40185571342216664}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.15122297425496778, -0.1147005990792026}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.40662547360570434, 0.15707936823116742}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.23774893840943456}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.2054628351620622}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.16051541451868112}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2776588691392494, -0.3711444243247929}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.46443735156264554, -0.037278687168519675}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.20263083331962606, 0.14530853172877356, -0.07532704916220023, -0.2920914423800762, 0.1841293949723699, 0.3314241688680172}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.19944925005133018, -0.002521199257391693, 0.1137678535595189}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.16758322227249392, 0.36052506933663614, 0.30022797357218095, 0.17166373481868905, 0.16758322227249392, 0.36052506933663614, 0.30022797357218095, 0.17166373481868905}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.04536727708195265, 0.07439998421703864}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.435230152588308, -0.06560098470362763}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2528027240137136, -0.46807490158583887}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.43612851484921666, -0.42032600642097995, 0.3433590204642849, -0.38994077261013127, 0.3227588723981514, 0.30847191598703816, 0.2844719200227652, 0.23192117708895266}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3847016959191829, 0.3813797215858751, 0.19836032479306964, -0.36064424005983886}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.3917095722047292, 0.24409923523169091, 0.1996989756383246, 0.1644922169252553, 0.3917095722047292, 0.24409923523169091, 0.1996989756383246, 0.1644922169252553}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.047998333616360966, 0.7435630956220187}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.14908135016474944, -0.47984007453358213}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2536798899348677, -0.1868977187551243}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.15337821409444052, -0.3313888729944956, 0.014496916925007541, 0.48698556165471885}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.07599815935158727, 0.30263682042085316}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.19874882398646043, 0.0848673689943018, 0.4589694127020003, -0.3967228651130654, 0.13164483345120037, -0.02775058417900067, 0.3438307871631259, -0.4081077540106953}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.40592699338265925, 0.02874272163498537, -0.25880954423243296, -0.3537730569968218}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.3362130882568235, 0.23406309142609477, 0.15472995460079253, 0.2749938657162892, 0.33621147744779234, 0.23245028883844487, 0.15433865121385573, 0.2769995824999071}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.5388194788904084, -0.9494466691882961}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.32405233609464734, -0.3128537252258301, -0.01509196670604307, 0.25984862429570454}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.08163577451748816, -0.39009408187553973, -0.36134296395646837, -0.4566066428015011}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.11174888584744302, 0.4874877731326016, 0.20086550196800068, -0.23065565808698896, -0.06510588501014125, -0.4681231515000336, 0.28225225331488735, -0.45856599799301045, 0.42716807875922636, -0.12625174694420427, 0.042485176811036474, -0.20364242915171893}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.29160794912099564, 0.33617734486843487, 0.2583858881203611}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.12166253778439151, -0.4804812485061143, 0.33481774650992524, -0.3130823919349255, -0.22106949979705548, -0.058718786731695505, -0.39662960868034514, 0.1748023151177731, 0.37552185312349207}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.0017204926508496143, 0.41442213064230404, -0.32320118101506723}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.011099298204262475, 0.294054545822078, -0.22779392380188068, -0.02103757757169833, -0.3640311736171502, 0.10678428837908382, -0.019713354781133674, 0.0962717143113535, -0.4334166327654142, 0.4956996836549935, -0.028798726592954016, -0.4672312051326196}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.23131517883566421, 0.022912028864770728, -0.49853977792531756, 0.10574837045144436}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.21664521113213686, 0.27494205105639435, 0.18949154738469987, 0.31892119042676886, 0.21664521113213686, 0.27494205105639435, 0.18949154738469987, 0.31892119042676886}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.820222125119674, 0.19382772897447564}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.02665540892663898}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.07055863253257422}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.002015814243424563, 0.498131596849995}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3449308644639604, 0.3681498893505265}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.3937444853118861, -0.31617307849515874, -0.26938237163424816, 0.2621877542161202, -0.08067100984654574, -0.18574679909979042}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.45718053990788277, -0.1921345229102298, 0.19483762034723495}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.40829915189462485, -0.158348421769264, -0.42214856054998506, -0.37891064889767856, 0.38383080311614026, 0.11387583603992835, 0.23461653426640705, -0.24165751835591776, -0.19948604077800958}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4627950397654629, -0.3555769535264288, -0.23393816540539603}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.32970139958880174, -0.06217976176369122, 0.017489880220761478, -0.4766228862472853, -0.450648906469567, -0.4278818830451644, 0.4681573838268698, 0.12774966995955328, 0.259043159529888, 0.2977735427160658, 0.47180392956152606, 0.48538500987497246}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.048356889549116544, 0.2866561978048565, -0.0855597355275437, 0.43503986608366096}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.6414460922384463, 0.6439794263504854}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.24830128195376644, -0.6494367245061026, 0.5733577815516078, 0.7317642167416267}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.25735245799057294, 0.3054349649336654, 0.1827699434929595, -0.3558352919320258, -0.4772118574795381, -0.37171768175775, 0.22153145966207166, -0.2686460804502696}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.11895150811067001, -0.3614491999207232, 0.3346441362048683, 0.3859561037131318}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.31492377872801813, -0.21860539008202262, 0.117981023293797, 0.2986226932397973}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.34388111005952837}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4681445122062314, 0.4681445122062314}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.5376021510910118, 0.018223772122415216, -0.24041308150545704, -0.8973015912470239}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.1478353705768115, 0.4606857185785145}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.17772432323418397}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.1290009723786003}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.35330472648705513}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.30005448695860515}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.23360544638340597}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.5893831623114216, 0.5893831623114216}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.2440641082949504, 0.3256783437238884, -0.21192019406236917, 0.37228475970342734}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.0495033949277085, -0.38847356744056316, -0.058100773517139936, -0.07935905597459503, -0.16382663726515323, 0.38309376332126466, 0.11494098984778289, -0.3662775615143631}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.40948805660000376, -0.132442357492203, 0.25649679910086043, 0.1324218914152232}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.4095398222348057, -0.15562638394340966, 0.15310340368642783, -0.42826196500760283, 0.16055898439733307, 0.47538301177009945, -0.27364010633012315, -0.19681253258829123, -0.06085458595640947, -0.36643994625111653, -0.2021592667160318, -0.08955943192996962, -0.1417744135301846, -0.11231273070208136, -0.40165938345924457, -0.4179164209537174}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.31403960666454367, 0.44540652627174204, 0.11818256727124543, -0.04461500800693996}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.02871348397788198, 0.42678136183330195, 0.3104555517085237, 0.11874869152349332}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.25832506015667756}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.4506254439837115}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.36141599112245826}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.3897696779803629, 0.3897696779803629}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.18348240340984256, 0.2051973809748011, 0.4131485062276927, 0.8804828407937344}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.2883904562191082, -0.03465444364859127}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.13668187560051015}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.3943568832510146, -0.4418028029998381, 0.17875931959728253, 0.3326916355922088}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.04785819064355634, -0.08584469048443888, -0.16453739492862773, 0.31241640500395906}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.49938237082939263, -0.44774189266611475, 0.08057837969076109, -0.22185092965429654, 0.05677373494807214, 0.2538830757642776, 0.0735494709468213, 0.09304379701643761, 0.3906597626673062, 0.15214093921101213, 0.1703202646255677, 0.44210942296008127}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.0053015765853534624, -0.2547779972976879, 0.3862390628488894}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.019085760638286042, -0.39986283096109154, -0.4496236478340634, -0.0035499917729731045, -0.46957379386393305, -0.34218322588822536, -0.2925253088974452, -0.30397899404744855, 0.15713053739652427}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.28528313326655186, 0.14338954650803015, -0.0322261432048454}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.36442305712872225, 0.19296644975904254, -0.48697577748179255}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4418958013424036}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.6362409061294692, 0.36375909387053085, 0.6133529681690296, 0.3866470318309703}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.9500415624596306, -0.01863261488447887, 0.06408362279687396, -0.2957083282872448}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.4919910216178669, 0.08623184466246037, -0.2508251991826804, -0.07574012670575136, -0.15886971592421062, -0.06807042178241052}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3503300811787682, 0.4465800604106118, -0.48788278838500676}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.10415981766534033, 0.07157593910096771, -0.34343890346482975, -0.46119187870645795, -0.17021083633967393, 0.008948415239309448}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.043598173846747135, -0.30832416786825156}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.6388920930278796, 0.3611079069721203, 0.6414939004800275, 0.35850609951997253}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.7402472935638786, 0.8748415779296257, -0.5843811896178059, 0.4365693837349045}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.15379796128524448, 0.01216115579362076, -0.13873454090039317, 0.4413236087127773}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.1697810388721046, 0.08532820882291137}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.39707154885656293, -0.16231318605737555, -0.34099353308852665, -0.46680060484568464, 0.14352572234317096, -0.03470338380615767, 0.12718940159351788, -0.11287005290313334}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.008777927893098725, 0.011356925258155237, 0.05031206037327285, -0.4262649724362957}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.24034967892795434, 0.35011453029814354, -0.03157836517476842, -0.4906943362633841, -0.20350193009630146, -0.026004923170734884, -0.32846836511203803, 0.11566360162512435}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2668772225900701, -0.2677229888687397}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5333764222389991, 0.46662357776100105, 0.5385259534867919, 0.4614740465132081}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.7128043017809487, -0.29191412539521067, -0.43913917382295553, 0.1475852242160023}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.3611655821517584, -0.044631697433513695}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.36827838222384235}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.21508589447532112, -0.061455409555142504, 0.4782768113583783, -0.34057507948005783}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.28010444140878665, -0.010342815909644698, 0.47129159689091105, 0.17181494670649644}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3027825840225393, -0.024878955313623274, 0.051568898651169204, -0.45042642923732057, 0.19935549717530598, 0.20554146414036512, 0.26663215546297925, 0.4882251736663167, -0.19989783376676917, -0.45700220433575267, -0.3445407612423199, 0.45377234031550917, -0.2945755515944096, 0.13621194867232223, 0.13774073742755377, 0.0643783143675517}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.212050684828047, 0.4087705275186847, 0.19424806802923356, 0.36221382700791926}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.23490642454483168, 0.1338187248277929, 0.16079782523888164, 0.09267861652615483, -0.22569474784139765, -0.1991958913344627, -0.16689551632460897, 0.4209649835562237}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.07354988160620834, -0.15851221518825287}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.46797555212455644, 0.5320244478754435, 0.46803764656167984, 0.5319623534383202}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.037375912081840434, -0.8477615694463512, 0.6880933236612821, -0.9939808996769317}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.3955946226888868, -0.2564186592001637}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.23933616476678843}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.2350371296700321, 0.2803239781098994, 0.11426185101012354}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.05006421134960948, 0.09681252172096644, -0.47400004607353985}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.03185800986523546, -0.39775482175045473, 0.23047700023633821}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.04886792165227383}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.3866222331206456}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.46467777619080763}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.20150218095601113, 0.25545946220033533}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.10702760942283251, -0.004076370310215571}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.39588857981308406, 0.21556991411864834, 0.3885415060682676, 0.39588857981308406, 0.21556991411864834, 0.3885415060682676}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.49949224043034257, 0.12494124049202049, -0.14299449634470585, -0.6052062200731183}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.342137852533712, 0.0354951883478134, 0.30435949383376026, 0.14210431500594556}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.21865047291861683, -0.23981548356425186}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.08531506215232054, -0.373289881817258, 0.05003692076904165, -0.02459850186047796, 0.07112512138872906, 0.12305894541106033}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.47228228967614105, -0.1355652334863413, 0.45354948294796416}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4046953708207271, 0.19687369795416484, 0.39843093122510803, 0.4046953708207271, 0.19687369795416484, 0.39843093122510803}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.8853340547031652, 0.06370698622879467, -0.5262344562611398, -0.5662939618054184}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.44754745661965245, -0.4046362653483334, 0.2998557213449662, -0.016861354884377233}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3793372959396719, -0.3612456603349643}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.45862809292023476, 0.33456691716199605, 0.0029370369324084322, -0.22787206104780566, -0.06176792980221202, -0.2942990387347878}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.31514473042506297, -0.3829850080936089, -0.09484655530884123}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3418118394878299, -0.41551697074391125, 0.35997089057349674, -0.3832036528028916, -0.3682107323125784, 0.38657102400415644, -0.09610458436551628, -0.22108756192275392, 0.48631383705424436}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.12254127722800812, -0.3695461281792811, 0.24494787861481526}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.43321057629079024, 0.2518593543695587, 0.3149300693396511, 0.43321057629079024, 0.2518593543695587, 0.3149300693396511}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.395689768969965, 0.39599151785539344, 0.5218350745471216, -0.8643996726970156}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4780732736318902, 0.04889193155053462}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.24057727537962492}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.2584516388889754, -0.030686949057267432}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.12648874583701208, -0.2663865550307293}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.293896787431534, 0.07090837112149462, 0.18438454315916086, 0.36967689302442897, 0.35714387433160244, -0.07467231780177941, -0.16826538491261656, -0.4245191739759282}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.24024866227665986, 0.10966928443703516, 0.45154967138010593, 0.007252439273338962}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2577976821756913, -0.11047737171335337, 0.2644570140070316, 0.32107616595818433, -0.1558156621088237, -0.14413095897220085, -0.14391923460637668, -0.08685695047823938, -0.46999401415804987, -0.18160548088359207, -0.07772973381468096, -0.13523300587645903}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.0029107300303898853, -0.254842356558578, 0.018691171271391305}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.32873931884017144, 0.3546465451316837, 0.3166141360281449, 0.32873931884017144, 0.3546465451316837, 0.3166141360281449}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.6696843468249114, -0.9426475138761461, -0.05091243737292306, 0.04928333221081527}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.08173892679803552, -0.09604224983481235, 0.38614987628806074, 0.4595793323417877, 0.04278340991154217, 0.2072835208230892, -0.10119206028907879, -0.13214026579369642}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3540271636312353, 0.3076907903925463, 0.02231140768743123, -0.13044157260673017}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.06616629663902074, 0.17517915962902286, -0.4952974436912909, 0.05569172182664528, -0.476721553964225, -0.08959892896429389, 0.23281725195972114, 0.07799056658401538, -0.10493884574813328, 0.3703306877567363, -0.22604429984641117, -0.1573813883106634, 0.09177086589521599, -0.4284103365055827, -0.3065185978038838, 0.07802788487787604}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4814158282343074, -0.36293732764227504, 0.3372731203085966, -0.26535538723445073}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.15533004554964802, -0.458972562536463, -0.40069363725417306, 0.4933022559075909}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3969487561009637}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.10087170569035553, -0.41182745842455337, -0.44035633546286146, 0.26947064097911333}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.06358046502488235, 0.189998209789901, -0.3480363830140726, 0.10961667735897518}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.4605555613560782, -0.23382094855886826, 0.026505263864725626, 0.18060177821843937, 0.043265624479940756, 0.24543442335761467, -0.4871581310440992, -0.1382500076370351, -0.360259675972992, -0.34503316880735135, 0.3117595976207209, -0.19972612243358123}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.20960012664609107, 0.2558819787506603, 0.2870270478601227}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2749979838636737, 0.15032986405620907, 0.2613850844992189, 0.3132870675808983, 0.26709723884993886, 0.1558987395737063, 0.273928194075484, 0.3030758275008708}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.37907158779288075, 0.897864970632356, -0.18903153999345146, -0.25017459310551593}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.010760817979082571, -0.37460108283756, 0.14545114529670822, -0.05557487236801084, 0.09347762940639703, 0.07262070301004953}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.15449064732605966, 0.27488425955594364, -0.06339619870818292}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.16452970150649782, -0.45824153539525614, 0.29894509420036963, 0.2142083869076915, 0.12237897442919687, -0.3226833995408117, 0.40005400398279434, -0.2714102587527164, 0.21806608213736578, 0.03873787956928454, -0.15759426375714325, -0.40458852590202177}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.33064301109888083, -0.37190667130704624, 0.2481408542282414, 0.4099344858305123}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2672773274556074, 0.1445428646853821, 0.2826954899574736, 0.30548431790153696, 0.2672773274556074, 0.1445428646853821, 0.2826954899574736, 0.30548431790153696}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.7082121568667854, 0.33170074261427906, -0.1301781556245012, -0.8104877334852358}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.015436599045583366, -0.3399925403009739, -0.05961535484640579, 0.022575789328952545, -0.0019076238065343087, -0.4009768181258533, 0.4850060547553987, 0.48805828091353143}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.08852239125776273, -0.2084619619495558, -0.1862560726720195, -0.3817846983117307}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.4658201648955347, 0.23588758257546227, 0.46961808170326447, -0.0843770522956987, 0.16240112163770248, -0.44839461089648636, -0.16586780151364433, -0.36790937515901845}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.47020967651689993, -0.4175429460808334}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.24405505676099626, 0.3447798117202605, 0.03281752874687616, -0.004160289894392766, -0.18611720303214574, -0.3123763359046876, -0.1833326612291486, 0.22124408191315192}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.23746173266792237, -0.3772489613024672, 0.2935452448275483, 0.37107337844264543}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.12701509155654672, 0.2530394958043893, 0.2874333105575378, 0.33251210208152626, 0.12728271092046525, 0.2537764605057812, 0.2862299365083187, 0.3327108920654348}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.020784455726949647, 0.15625413525217358, -0.516458402963621, -0.6845204002924001}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.006289218997079571, -0.3096511742533309, -0.45207794660392475, 0.4347291609174805, 0.36013210317698385, 0.43737434873863856}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.40569046524519603, -0.32310593882647454, 0.3025966623315517}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.476042155965702, 0.03558104899822856, 0.11458620773092532, -0.15994858441625648, 0.35431803915869875, 0.006703351981588335, 0.18367139306328983, 0.2925624968345455, -0.45436465346669586}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.25258900461001443, -0.4192280402754138, -0.09999745721821696}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.418181044013181, -0.4504311045695576, 0.2806881752246537}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2755763685950413}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.19878778741909486, -0.26023388841840667, 0.2830397326102184, -0.08352663618126299}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.448477671122016, 0.2576950981454682, 0.2354270101181446, 0.4821294254983568}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.3079846131150702, 0.21079781978697074, 0.2134732310501845, 0.26774433604777464, 0.307964625006854, 0.21064242170268418, 0.21324711273219546, 0.2681458405582664}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.31569306459574586, 0.6319732978936448, -0.8312897472755165, -0.40897906338791734}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.02542925014951236, -0.1628074359002074, -0.49182345181085185, 0.489177232769878}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.45094496860001887, 0.015330212832748491}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.01736302849997895, -0.3270937846444478, -0.24990318009372203, 0.3971958995137128, -0.26657881402273953, -0.011725396177276304}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.17632626139828367, -0.4818297607823867, -0.18891160423416842}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.26429277916673644, 0.00609824696889838, -0.3617756541434365}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.32027135255931927}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.16521289478745438, -0.24006445550696798}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.49617621690343683, -0.02074897348153093}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.012522495905766373, -0.14767852964744543, -0.1789509052774102, 0.10167647953113312, -0.27071733544514054, -0.04902920780859055, 0.45760070455635027, -0.26143248072262126}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.12759363200497043, -0.16657304352122393, -0.11323140421222899, -0.20996742896707665}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.5243540947735339, 0.5258836248937614}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.9422375480071457, -0.8287885888742828, -0.5234352619602136, -0.948915149367594, -0.2102789982395714, 0.5506772890480933}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.22884318346313082, -0.07273025739071326, -0.35677966278287754, 0.07075351486772341, 0.14420362880662363, 0.2895511895406103, 0.02856732503348325, 0.28399447966862823, -0.1604623996422968}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2409910170399706, 0.2890267793122113, 0.40925215708498075}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.2638139171546521, -0.19128111290355743, 0.455050929517276}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.0642588379887169}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.5318398102649048, 0.5352230704898916}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3292710763242497, 0.9729239905866918, 0.9583157380351919, -0.703856751668132, 0.36821104043356523, -0.8278278532168764}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.42490690131356335, -0.18015220234948093, 0.43154179445134366, -0.08748221665132827, 0.2743959868114736, -0.014260894088994447}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.31187683993374415, 0.3961849423442818}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3991264845355612, -0.20975509454033137}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4224465635932253}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.36770052468828995}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.029801005510282863}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.47540833873887395, 0.4756983732495323}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.6292730237385498, 0.6564723491990097, -0.7730544820537812, -0.5846669167067449, 0.36751535650364797, -0.7909160826342241}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.1508967978933592, -0.47115573376436637, -0.041288850022206725}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.14703275151459005}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.12366321386094814}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.01673814014337216}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.2546448091407806, 0.06941014414549984, 0.4907584161181945}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.49731357600503723, 0.3217125521829657, 0.14007804050684092}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.10444593324330842, -0.42975778448956936, -0.08724683487610918}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.10563729123564314}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.49903098168610766, 0.49903098168610766}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.5110195098280876, 0.07662927459039093, -0.9470216909293068, -0.8037135131950366, 0.904278432816952, 0.7385918245290755}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4580593022333429, 0.3158563248595523, -0.42846890766306045, -0.17459234912865762, 0.37835414306310466, 0.14551382981854455, 0.03422502415656159, 0.35078786715426247, 0.2881854173573636, 0.1743674820899499, -0.28561344205801487, 0.18589263899958197}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.03567693524916449, -0.44751645623892966, -0.20377115717002536, -0.24868938020840003}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.4352508153249831, -0.1005543339060384, -0.2805546842488523, 0.39071318907488484}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.31189444815304523}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.474517384944673, 0.2546865082903008, -0.338583127854001}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4859877805069116, -0.28365574733479715, 0.1542808853850539}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.19493083824467972, 0.34815624937242207, -0.24181284634971467, -0.3516312544784944, 0.3637663349112348, 0.48584632857130516}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.32465481831803766, 0.42516749361425477}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.042290772092505424, -0.16861002837916683}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.0516363798821553}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.4033756507394775, 0.5966243492605225, 0.40352775114154954, 0.5964722488584504}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.8912042734647518, -0.10165978198288173, -0.19628836007597772, -0.6090667097905387, 0.6449890474128541, -0.4954779687270783}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.1956872647324035, 0.049900271050909106, 0.13782611704989312, -0.2990354061843783, -0.379061874490389, 0.10813230308129074}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.37449582967614026, -0.2788467560416976}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.2399172053672266, -0.21024006000770012, 0.33915343205731874, -0.08295886428113797}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.39865132488106403, -0.007863869122125111}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5331273049702375, 0.4668726950297625, 0.5328862275153754, 0.46711377248462466}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.17262082435895487, 0.44567585029411494, 0.7012795001031913, -0.012405107498551171, 0.17370128386392936, 0.7988749672133557}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3091922920608282, 0.4485671242951321, -0.12987364874061458}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.16235869173629114}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.17461764890140652, 0.29647374678172556, -0.43305397950326463, 0.48397835568087866}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3624113400096338, -0.3918267246191035, 0.35640676065845944, -0.23453521779033548}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.35672783662468477, 0.3492664814294646, 0.12066737347125756, -0.06998035966878613, 0.2672248313070553, -0.16994097305173939, 0.18302684351918408, -0.4729576460517442}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.19460035525166264, -0.31461440471826585}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3951347699990512, 0.6048652300009487, 0.3951347699990512, 0.6048652300009487}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.8779703252711568, -0.6160707075992473, -0.34751109371495126, -0.2232092636917462, -0.5058771728304212, 0.6875180669691909}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.16407088708381945, 0.21092778353750274, 0.060981305694876475}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.1293226768116893}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.05662030822314301, -0.45294507504062875}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2202472658660677, -0.09773943282374464}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4075181002458361, 0.3060890570990741}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.21507865523352931}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.35963073614945573, 0.48689144552233266}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.08591792217757277, 0.3398608541293815}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3917944454031179, 0.6082055545968822, 0.3918021469516849, 0.6081978530483151}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.8579738526797129, -0.4552722294088256, -0.18009832960883565, 0.5526215803806773, -0.080368684392077, -0.9018075981759337}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.08114785209764297, -0.19215362263136748, -0.3795946844399759, -0.2940231351986341, 0.48091126292114483, 0.3999184273601427}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2966506478594778, -0.48929499252287034}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.20590459329363975, -0.4989468226194542}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.14709848269481185}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.16593649312758263, -0.20581470334806062, -0.24203273994032082}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3503191658465957, -0.11164129203022521, -0.4737657066567459}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.1007026125458994, 0.19304718604546178, 0.28885479029976335}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.11313786071618359}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.2288742631230659, -0.34847275233195274}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.29190673718472915, 0.19424011714136935}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3114194410713512, 0.3287268862590365, 0.35985367266961227, 0.3114194410713512, 0.3287268862590365, 0.35985367266961227}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.5659982514129576, -0.3451483663994408, -0.502223315515393, 0.4415227045543617, 0.7526990618292464, 0.9165520375669207}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.470399471186027, 0.25470513746865564, -0.4378201051594226, 0.31608744666952193, 0.1407947209461191, -0.2812045622796514}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.48180771715011084, -0.4489198649821702}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.4805991874427258, -0.19827059612352282, -0.32538194446584623, 0.014529542336355283, -0.41629677191476333, -0.4227540676432636}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.048162340569631645, 0.005924243856067379, 0.09639445480742903}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3479746488447993, 0.28477852582674223, 0.3672468253284585, 0.34018434101255, 0.33010616199089343, 0.3297094969965565}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.38299117398208815, -0.9207895535609487, -0.9049176242146448, 0.9401593513866855, -0.15881067974012208, -0.0592314132987668}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.21164204718014568, -0.08321029047734252, -0.18172023596169617, 0.07688016599881964, 0.49595199491417385, 0.42852643861639383, -0.47750766289949087, -0.4675408963278077, -0.3577425526062995, 0.36586999561572653, 0.147281277763875, 0.2390614655904475}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4173014787977386, -0.16918968578968996, -0.16648617234311536, 0.42025692343040166}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.13017510333175386, -0.08930937285111895, -0.4463979331574356, -0.42160551986062456, -0.3664805547615113, 0.3695301599070199, -0.3676040034274344, -0.1545063792903657, 0.4049911822388689, -0.2615036051541352, -0.3251034658333881, 0.3698368237474666}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4192283980203465, 0.1445963596605211, 0.05858225415046381}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.25317378025901294, 0.2915664268568875, -0.15111064055134793, -0.13574842776229812, -0.19094917662299538, 0.43775117892908444, -0.40896236120184715, -0.4527499615314766, -0.3583786033902865}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.10542862140525844, -0.3259154228053027, -0.027220790103294257}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4328067991709142, 0.17860086257433017, 0.3885923382547557, 0.4354530329430361, 0.1715177757168959, 0.39302919134006803}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.8366887358651969, 0.6294146357963133, -0.9857428120659859, -0.8604175604939994, 0.3115127944995557, 0.7679411175151849}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.04528203396573793, 0.33700586930306453, -0.4618579717393887}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3211231148808463}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.34696175418911035, 0.20304594608089144, -0.48880217973042217}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.492863332029439, 0.11179217366632033, 0.12902289080613827}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.2023310448194885, -0.2469117494180617, -0.45693835894035006, 0.3402305029222329, -0.2650678752605742, -0.06029527497748921, -0.1042518081564725, 0.464178503928557, -0.05123052139508}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.46755265979521754, -0.0819714375916184, -0.059372583239980625}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4893157590871283, 0.18623767211708753, -0.47433479111908927, -0.48475836643424564, -0.1303227878526525, 0.2562383610589706, 0.47752079666505076, 0.0828790313171317, 0.23055213245261819}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.17680042283561115, -0.4512769578885727, 0.08381074618648998}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.360687470250436, 0.32601233130727747, 0.31330019844228646, 0.360686889258643, 0.32601015312687703, 0.3133029576144799}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.49415112019496155, -0.79920061919648, -0.34032942400368493, -0.5339103465522621, 0.5631170851014353, -0.2543679559335519}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3016356969193965, -0.3828674820849526, -0.4264142596936854}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.29208870462560454}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.19356032806583168, 0.27190944697734354, 0.2944678044601068, -0.0026117686513077443}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.20306507135250307, 0.12850394907659635, -0.20277581267464118, 0.2689168943252137}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.39561428898700335, 0.08001590207038445, 0.3145730251236716, -0.49809338151215377}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.33877073252295276}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.049876581821399424, -0.28358463438594317, -0.23565865479092252, -0.22289410729049186}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.30855692808334834, 0.15947053699611946, -0.3378125468559816, -0.05565023369821953}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.09507451189784466, 0.04754580558629917, 0.3478199182611742, -0.42698659714909737, 0.4869899502045504, 0.08106659383405956, 0.15325735381247507, 0.11174223395302618, 0.09971155318943103, -0.021323865148849208, -0.41939303837486075, -0.4179767880278207}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.29507459586784146, -0.40022074845924105, -0.4275636604998503}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.39220819267274476, 0.14174870204360232, 0.23380571060112967, 0.23223739468252333, 0.39935234723848534, 0.13421868449600785, 0.22354152142757275, 0.24288744683793417}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.795121615127854, -0.7666766972937382, -0.20674007708960285, -0.541982658196906, 0.4782688160930457, -0.9233751427194548}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.25687726509988884, 0.42304425326381245, 0.19501782440793158, -0.38668153648335135, 0.01033428501156941, -0.02972202310703198, 0.05527736256945004, -0.1717653354208848, -0.48722853019516144}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.42826835607497826, -0.1244015771256165, 0.3939887892691377}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4697670791635724, 0.14108893841977022, 0.3468203045481183, -0.4335219644537862, 0.11018022060560118, -0.15282070638401035, -0.07006418945857307, 0.45101609368337625, 0.05753144012638289, -0.32265664934918525, -0.39931537713788734, 0.2956072381349537}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3951461329026025, -0.3259695250453717, -0.009841803709955133, -0.0010933504871670774}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.27663019087665164, 0.18546318405391052, 0.19085153596450327, 0.3470550891049346, 0.27703646413683, 0.18466577499134426, 0.19057846382354443, 0.34771929704828125}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.9405143442369535, 0.7544881899104658, -0.5340722294176379, -0.026479648664973876, 0.28463242516993836, 0.8905197210588687}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.48640500057390024, 0.047612420956868684, -0.2361264850841499, 0.3143301959435897, 0.10622157662479392, 0.12151406313847424, -0.3482520625862323, -0.3760869720955673, -0.19472354589680774}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3906508655340505, -0.4116470185816441, 0.10817930796217545}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.08198896727691074, 0.04605731194004037, 0.19242837848188632, 0.27693966873298725, -0.24901923704934104, 0.1074429285959777}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.34302052874708033, -0.09165995063098109}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.358943570416677, -0.04757874999237943, -0.27238236293957996, -0.007936103878165457, 0.0420555654081185, -0.2849055472664236, 0.4075179184303974, -0.4108663364053121}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.20847091434462828, 0.03013181997737313, -0.05154200777989504, 0.4182316922112249}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.25749462842669196, 0.23508352380119976, 0.23884833044930912, 0.2685735173227992, 0.25749462842669196, 0.23508352380119976, 0.23884833044930912, 0.2685735173227992}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.11642030805847114, 0.2534338610767497, -0.3812949768271372, -0.6148838346146295, 0.8560800531545938, 0.7388257837640431}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.056947089076054835, -0.49365098703718613, -0.14681707460690263, -0.30395154478912445, -0.03630498411060834, 0.3331240947464159, -0.3087668497632492, 0.18821783336248654, -0.3574114777116614, 0.3542835518941152, -0.06457335809678244, -0.3476338573053397}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.20874686882531868, -0.07568222222861687, 0.19742304867343896, -0.44017243795112715}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.18905410662874145, 0.4562656750293682, -0.0358199543998694, 0.17603122150215056, 0.267983664863368, -0.3350164940223027, -0.04229807047477252, 0.05533370703623475, -0.06602899124942174, -0.3516365421076565, -0.27240535250919573, 0.10296241599289824}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3979125254458642, 0.20518638082475205, -0.40503487555746587}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.1954171715707672, 0.12660140090211758, 0.3458528993372033}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.48398305235046846}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.23597469207160737, 0.28259328333194345, 0.22055598329688153, -0.4523674411326132}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.29363917597243694, -0.3846971639518618, -0.36880928552298287, -0.25151335137559827}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.15973119078840023, 0.17220704428968292, 0.27864493760779446, 0.38941682731412236, 0.15973119078840023, 0.17220704428968292, 0.27864493760779446, 0.38941682731412236}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.07168633301036809, 0.684174207027785, 0.7857081420947363, -0.5903438083235368, 0.42937946450186026, -0.5349061195115943}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.04028705706966762, -0.3640824025013001, -0.32076543095400867}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.30839866480646394}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.4846865902907307, -0.1714018954701726, -0.009477577291872152, 0.19697068354308067}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.11236601728656304, 0.39735454930359093, 0.3428954323075537, -0.21052020331257237}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.12943797940365576, 0.042269746275155784, 0.46758944068450625, -0.3610990931313991, -0.40571556436802314, 0.0712319594122931, -0.449649875514046, 0.11484159835026819, 0.25833210394793726, -0.42559651299343393, 0.4119814308551132, 0.07925255601371994, 0.11085277136529392, -0.12391796881472472, -0.07333404865566862, -0.49475720697021996}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4186784814945589, 0.4969898589776708, -0.36230259732695336, 0.29006117053267844}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2819733233135957, -0.08282207863417501, 0.350909114978301, 0.259748058274634, 0.35709853194055774, 0.13987625874866838, 0.35638045132274354, -0.25497141329516937}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.30930706992474544, 0.4345959445777535}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.09459432629900766, -0.49400503070416046, 0.4626562122406518, -0.4393223669292279, -0.0632964749033359, 0.48596678838350704, -0.19763384636108394, 0.35090204706593064}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.04830074137982665, 0.003830422523537713, 0.09463467982845186, 0.48633878761241656}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4193824690919849, 0.42234731505396594}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.8029076900520029, -0.08614652070259976, 0.4495849166221628, -0.19917856467022577, 0.2349898154031005, 0.8905695332815033, -0.9698679090354996, 0.9420441487205828}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.07841661333929384, 0.1144382507709314, 0.3325262020519725, 0.3602069857426422, 0.2223677161979799, 0.44724308185376915, 0.36292957001028925, 0.4360858702322984, -0.46805323318275727, 0.40964139753233775, 0.10910638796862726, -0.10998427040267189, -0.46346163161426057, 0.051486858093632515, 0.12437120107457345, -0.4588440287523744}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3388626042270524, -0.32330870687723834, 0.43023091762411514, 0.1315989249422692}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.29086247293870116, 0.07616115084754915, -0.005205257415755171, -0.384926036208214}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.32483994838415786}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.49370094266581477, 0.49370094266581477}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.18510327043270292, -0.8271664461375356, -0.5539916712017832, -0.5488871962396824, 0.28216605700518915, -0.9470242137456655, 0.9379392648268734, 0.41461824809033043}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.2773958024592127, 0.23061280555036634, 0.36228804301484463, -0.4188318677487971}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.08330277505536954}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4993367719792873, 0.011516448199220153, -0.03997259694172961}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4889412412860772, 0.06877059952907993, 0.21902859870058822}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.4241091295940693, 0.40254632926069844, 0.3938596020082131}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.34651187582775234}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.6022101523456759, 0.6022101523456759}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.6547141926870175, 0.5203428504497865, -0.30957454769526715, -0.08419705183936776, 0.668484804801061, 0.8987222937580244, 0.11143528538151837, -0.6913187458543766}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.31548657195144325, -0.04306098197144681, 0.3239239660607318, -0.23449074230419342}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.41582481320114495}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.23866181144310472, -0.06134978745792474, 0.3361131047694794}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.05487475386762297, -0.4353475053772953, 0.37454692354661634}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4677131182515466, -0.13880146246833458, -0.20034760228994164, -0.08162307888553522, 0.40869770171918196, -0.30187075349781056}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.11349847148033576, 0.4448672301345623}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.44031723900492914, -0.2313983428809424}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4914611710858582}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.4984756049131974, 0.49839730324252424}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.7425571927174817, 0.5239285654398753, -0.9721343488792578, -0.030549490798839507, -0.7386448411475839, -0.29739653445650327, -0.6292857206416114, -0.13536510864734086}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.0472449143455731, -0.44403024902958954, -0.0721608875915406, -0.24179726730293694}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.012694280793473789}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.30488071372564374, -0.1441431555871423}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.09176460166746214, 0.22939052390800208}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.46007101146593554, 0.239065217600421, 0.2818446164403411, -0.46066542707732117, 0.14685509572948507, 0.1351861148211625, 0.21617959072534698, -0.24075969047165802}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3717858730434127, -0.10580878002665961, -0.2648549993100453, -0.25945480242210317}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.22442629504077383, 0.29549036670105144, 0.4683857660856967, 0.4653735237823672, 0.19272124787337108, 0.026362323881221283, -0.37085336345971964, -0.22536587527018004}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.397492208862003, 0.41232053476131436}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.2255072536384658, 0.027441128750482435}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.0483776376143259}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5866978356071252, 0.4133021643928748, 0.547731823428967, 0.4522681765710331}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.5349072696499433, 0.8984375827120905, 0.5620617314171621, 0.5067262499536518, 0.599527543002079, -0.31441037304171293, 0.646918048855359, 0.43339126436345743}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.10518298458645348, 0.027348035045440477, 0.2966954377628822, 0.3259504068360545, -0.12066646328779163, -0.31552705402761705, -0.09119120823061633, 0.056801380128125634, -0.1282051825706001, -0.008029148036006406, -0.3973819057959884, 0.4851627494237436, 0.4175998776436688, 0.2897313742335583, 0.34561938142211857, 0.2268580603750443}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.09342059497260036, 0.3328442204942931, 0.004991477369957975, 0.09460174438382973}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.1785304651571178, -0.17639783893823935, 0.20281271632190734, 0.3488920172665505, -0.1415625505531939, 0.048959067254679356, 0.03596710005622039, 0.07000542494992645}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.049064525198767917, -0.06140044640578346}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.55298720144014, 0.44701279855986, 0.5528906527026946, 0.4471093472973054}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.4946198833367972, -0.5227609098073858, -0.6679226063269204, 0.41388014707268983, 0.8976949344740637, 0.2338577357156033, -0.06700166830350929, -0.8377067704875982}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.422665308659954, -0.05816548460120763, -0.4033936096322728, -0.49953826899629905, 0.4562021045712368, -0.042553146605801784, -0.22366825433189097, 0.056108396289163864, 0.021649409920973195, 0.20024541308672572, 0.2848357208154121, 0.3413709034740585}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.07191575870133815, 0.26967601573124034, -0.3651042439059332}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3412289803202857, 0.4354551673591467, 0.10349370927501578, -0.09978747494204565, 0.3916662797420196, -0.02629223693766458}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.21835061360569652, 0.24651067891662548}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.4319943703900767, 0.41554934501054097, -0.034837420379766115, -0.04484542936114855}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.22814843831840192, 0.22070402245088938}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.5145958101559167, 0.4854041898440833, 0.5145958101559167, 0.4854041898440833}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.04553807370568408, 0.5649092250316996, -0.1400762110642999, -0.052505600862540414, 0.840413321939778, -0.9290423245412891, 0.031654241433551444, 0.12140590479224356}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.4818730048503853, -0.18266286670880816, 0.23221519611607744, 0.07450760857510463}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.09622116181277862}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.49994972123865045, 0.21529434087977983, -0.4941452319947981, 0.07257205507832531}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4554134323436503, 0.3705863358626923, -0.2995624111083769, 0.1175194133298656}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.24674389340723946, -0.15849265097656662, -0.14873713875364547, 0.14974813836171286}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.020768870084661772}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.18943540827678496, -0.44314047649978483}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.043130211979376165, -0.015269620901631975}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.4616074731909726, 0.5383925268090274, 0.4616074731909726, 0.5383925268090274}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.08517332545674328, 0.6229314467202993, 0.5467834323488399, 0.06638971546373118, -0.30609058022329605, -0.35517991966563867, -0.4181029309797548, 0.8783606803182393}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.17805860272596075, -0.2056419080014138, 0.22350158371237905, 0.09382263017907388}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.11413459270034121}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.38379676174978394, -0.03938946018709377}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3863905878932221, -0.46059446915875324}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.24259515359154216, 0.08300433940361407, -0.18187745362353802, 0.3317268919108578, -0.23656064701911195, -0.43186291632026297}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2493346043240704, 0.44544631258620215, -0.20418525384104658}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.4964758204057076, 0.3258758617332197, 0.355505009403846, -0.44760435337356186, 0.49745784520740477, 0.11320942566133352}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2898489516566095, -0.20156561271871232}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.27977249015946903, 0.10611673915439601, -0.3317891367824348, -0.21183083136400338}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2037694268486281, -0.020901768609762783}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3919082200795873, 0.27955344658699893, 0.32853833333341376, 0.3872939265820362, 0.30631381874864744, 0.30639225466931636}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.6442842502974457, -0.5345064606573273, 0.5649816408313373, 0.05865284404433013, 0.7618713925065996, 0.7819060774371442, 0.1630185455083839, -0.9994439150570369}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.17262154111732353, -0.16165248918816733, 0.0415985393363143, -0.002162880253097965, 0.08425430956605107, 0.33424759717574437, -0.15158436124795838, -0.16336854945737567, -0.49846505202106006, 0.485527254835589, 0.2224824437212085, 0.04072512696619335, -0.17868143035870476, -0.48875479802120125, 0.16336821325855666, 0.4026737260191944}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.2656240769359305, -0.36547728509336674, 0.15369491400691326, -0.3109889618997629}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.41117451315931874, 0.23441667897852603, -0.23980192306044856, 0.24357819733644248, 0.4303446824312591, 0.44710303277061136, -0.2114255701971488, -0.24069886207000257, 0.25054494016787343, -0.43579759267787865, -0.25543782239514234, 0.21532473748392655}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4873745771900543, 0.22759161984969012, 0.32149222833559477}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.310443833932905, 0.3078784364007162, 0.38167772966637875, 0.3067885368329327, 0.30936642018549854, 0.3838450429815687}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.18070499379149085, -0.088988445474951, 0.8631074246659185, -0.8379699594321672, -0.292760014115248, 0.8165646827016357, -0.4961508904485259, -0.10135961448952568}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.023005456660489698, -0.24833939938538852, -0.20596858771771387, 0.3878738973188952, 0.015856985161485593, -0.4568328713832204, 0.3296902518938092, 0.28154767300432193, -0.2850045858833199, 0.3288869435744294, 0.42918523624790794, 0.013332470158291865}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3525828790555926, 0.4515071098120548, -0.31581592557832017}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.02759118127409632, -0.05958502743854566, -0.19257362322815574, 0.4029257912643971, -0.2376512865192344, 0.4684428137784383}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4474283531711095, -0.46720400638525184}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.22597009774277532, -0.40911777562685236, 0.2052626514046102, 0.34912268364215737, 0.2270224569974707, 0.4345301113967387}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1671543123981074, -0.34912179313552616, -0.14301348126466995}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.26004098258175373, 0.4450873548659503, 0.29487166255229597, 0.26004098258175373, 0.4450873548659503, 0.29487166255229597}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.624564554131676, 0.8904994380241948, 0.44625021335820114, -0.4243680283264595, -0.3628663492378694, 0.537308222664377, 0.40925716913602317, 0.5293551071592884}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3329283870753026, -0.39292497299119866, 0.11843446148162529, -0.029039677220763727, 0.20788352594391157, 0.44099998971085186, 0.33014242351329315, 0.153497928345108, -0.3440901979625466, -0.05699859400114449, 0.28004531606549876, 0.08613544915564098}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.16626920920374, -0.36141761962566954, 0.37449532467928226}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.02916761516583355, -0.057863893341770334, -0.37426760769969347, 0.3555009358640474, 0.08371406198789555, -0.4055518725192979}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.43393354135731, -0.3469320822069454}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.10459785640102559, -0.28089553304184356, -0.3197073188958547, -0.01691004304429622, -0.21396143625560082, -0.20541935599604}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4365976232983084, 0.06952552518362654, 0.08511878675930684}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3085969516298902, 0.1472795394794466, -0.189327091081673, -0.2630300148978191, -0.38468256601651885, 0.4840903905306585, 0.3653293499760645, 0.20139137013898767, -0.32842251866292504}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.0238164052060994, 0.49327938260141035, 0.1099620509656336}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3411314433376335, 0.3306869025780508, 0.32818165408431577, 0.3415585668980729, 0.33011839053368197, 0.3283230425682452}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.40233199784381557, -0.4019135793890649, -0.5807633041209435, 0.8341944463433733, -0.7234702212382336, 0.6022128278032945, 0.9301110970070228, 0.635038049474707}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.4482593088180056, 0.04975815977215692, 0.3147819061063992, 0.047901888908829404, 0.41999596905787284, 0.23904699722195977, 0.08703905399832568, 0.05121266161389493, -0.26627408714112233, 0.47689298909641475, -0.12739139563917679, -0.17563477801400051}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.28783683708280317, -0.15560932792443094, -0.07536509488460252}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.1938639173164991, 0.36970258390142474, -0.47336453173070747, -0.1877673963107126, 0.3708113912521064, 0.27402851989459265, 0.45986874698007874, -0.45843907315018184, 0.12140116495326192, -0.45689055288419445, -0.19394955137811565, 0.4718844486950611}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.17925155083305777, -0.2850529962820091, 0.4005976333453205, 0.4770758498833979}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.28620659002808513, -0.16056015147327118, -0.3381697561402065, 0.08008151089127802, 0.2184290654204245, -0.306947946108172, -0.10469943662678538, -0.2728159227389425}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2707273289559964, 0.38656798727716424}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.3129055754039929, -0.42363584119441755, 0.20006842953295345, 0.31312558297656157, -0.19559636409010972, 0.09549048268010629}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.13063629284081346, -0.3256262385898886, 0.39730043401125203}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.24793132072962232, -0.03987554744191035, -0.019638599572774806, -0.0037271095642575913, 0.3090498158672146, -0.4074241280015799, 0.1578140280331949, -0.13917717190844647, -0.21824744146594544}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.00217391460503058, 0.1403734500252708, 0.049280726758948235}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.320266311939566, 0.19163323980238667, 0.1864626355558023, 0.30163781270224493, 0.2852372015688106, 0.18409228498230623, 0.21725933316464194, 0.31341118028424125}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.2517124932827237, 0.2854570642731693, 0.7011120467691034, -0.12535801284450399, 0.3748552960854199, -0.700066883887394, -0.4877790277160192, 0.26206326166912053}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2262750322411653, -0.2646498357200453, 0.36437129120559864, -0.34256714090748, -0.08305954388485026, -0.4130943601241912, -0.40267205418238794, -0.14090055708799343}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.10915735081052369, -0.1144792189824777}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3625530709287509, -0.4763840915604364, -0.0342096277395455, -0.440464102774489, -0.09323998318306181, 0.16456640294090308, 0.2601406542185868, -0.02303974901378214}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.171071419336695, -0.23336315456763534, -0.24447851662832032, 0.13931547184239845}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2581830094606713, 0.1613986704976611, 0.3456241628952422, 0.23479415714642538, 0.24044367092889893, 0.18215124585983, 0.3349354774063096, 0.24246960580496155}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.9043972449969657, 0.7759040719607788, -0.34538593904874393, -0.8104817422616504, -0.24165679055995803, 0.2646104252971966, -0.30661054755403194, -0.038108414275978664}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.29871171162758803, 0.35815070117221814, 0.013896220376256707, -0.03679347966953672, 0.14014789082166923, 0.06525496083231064, 0.18291365042542196, -0.42731168773009465, 0.34371803993670513, 0.2449023247328651, 0.16371325915564205, 0.3892090908680851, 0.48827527061327713, -0.3308800311562128, -0.055795073235905934, 0.08727824470211865}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.2947569279176938, -0.12849765007900982, -0.037719302612775896, -0.2963571845990479}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.36910657497908583, 0.1254240464039258, -0.33120111351388726, 0.14106215818883516, -0.04546444267708938, 0.05467289802724984, -0.3451970823240089, 0.3214530559947337, 0.3841808197463895, 0.33265889572735163, -0.41035993761571776, 0.2296726248862898}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.44314100238575116, -0.45014089787474076, 0.24898959655050257}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3572248320879512, -0.15285433038931628, 0.3208654900318799, -0.4469515784882051, -0.11180860152746297, -0.4428632554155524, 0.3369459210432174, -0.2460113516314718, 0.03911618912879833, -0.44888186159242793, -0.04709365761504347, 0.22614891604734932}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.282123873980873, -0.01324830352348294, 0.12846725066313924, 0.10706901586403506}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2554517428756058, 0.19119964523981584, 0.25632282718855837, 0.29702578469602003, 0.2554517428756058, 0.19119964523981584, 0.25632282718855837, 0.29702578469602003}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.584347668753129, -0.11334983504304685, -0.873824259929167, -0.21669328949367928, 0.3407536440581711, 0.22700570230427908, -0.22070139386968357, 0.45326936103670645}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.38480130847950644, -0.30453147307907014, -0.08681448750447995, 0.011337185420290607, -0.23743775582397586, 0.36359239482197514, -0.3961727914785773, -0.1211046826345511, -0.4741226985030115, -0.4643015232747768, 0.30928246038219975, -0.025655359465649785}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.0353218982381418, 0.41091680614112525, 0.058105613264823774}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.17782897381225704, -0.2082106675315918, 0.38407057173631687}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.43470752413939695}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.2778979999908553, -0.17522285952894034, 0.43580331752091295}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3177563926417527, -0.4909669855805616, 0.2715584734560308}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3939978382825342, -0.2590242644497557, 0.4317433571228123, -0.037317836773934854, 0.44180460308010905, -0.2408822661332859, -0.4429504681291636, -0.06576696457435394, 0.49037642829828043, -0.29896060053951723, 0.4263628305276995, -0.385193758703551}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3268028776022508, -0.2968077504919955, -0.07337533501427407, 0.2660207259248557}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 2, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.22702921448639768, 0.3586985079654743, 0.18259130793710243, 0.23168096961102555, 0.22719986229202033, 0.3584636836354301, 0.18241913847906893, 0.23191731559348064}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.2636826621473509, 0.8264805269863693, 0.8717713876854098, 0.6630220353398901, -0.2527001597901706, 0.8395327209305885, -0.15825792009199047, -0.270521478778766}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.3666957712798725, -0.3911686627670463, -0.2908139208384608, 0.41251761516757146, 0.08595655245702971, -0.06413468268572264, 0.007986102518628302, 0.12598518540812154}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.29592262607042175, 0.1893457375962142}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.049966016764302235, 0.4967141995241895, -0.09168662030832753, -0.059974026254002166, 0.14524194891802955, -0.37698782803769515, -0.17520756307540852, 0.2301562339885196}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2580269633074138, -0.30021120884368335, 0.24783205477268455, 0.4692367143833832}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.22383552368341297, 0.019298326948121725, -0.3917304182616367, 0.21660860092825973, -0.3647752267660719, 0.4628793335677319, -0.021562969927224285, 0.0015539154804240507, -0.4967817827625366, 0.0062526969820128064, -0.3928634635010442, -0.4166031185084532}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.18479535685178483, -0.2269597660429662, -0.30801271569781374}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.45926971417878937, -0.48288917140556187, 0.013171834648187164, 0.0860367710958464, -0.2487933457129804, 0.007091299602046908, -0.23527797272892403, -0.40293129088618684, 0.3630781102373577, -0.19955513194168206, 0.08950719585955536, -0.16556300939607294}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4017823826285273, 0.23607611812951435, 0.4621937982469617, -0.25591394564525205}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.13889084726960055, -0.46543255535185113, 0.270028618565447, 0.36164584001417777, -0.3803898114800589, 0.0632296784249442, -0.0871742450308034, -0.48014274880090746, -0.4615695932767563, -0.38153920096479954, -0.3627602151900302, -0.20197455165293188, -0.30649720124217583, -0.3481333671699006, 0.4179357652207132, -0.4556227070769636}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.13950608280617827, 0.3388610524353518, -0.10796274853271404, -0.21158981510163466}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5203167655970184, 0.5203167655970184, 0.5203167655970184}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.16131775617233113, -0.019489706107841398, 0.6163762742838867}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.06691320892556263}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.20616438995120256}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.25275263567323414}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.0813118329934106}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5503211179379596, 0.5493887650713978, 0.5511799383424323}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.6490375021235966, 0.9098017161563112, -0.9376413462976196}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.372278703490023}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.30493401966442113}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.2905770075577433, -0.48529379010745743}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.038361414326554266, -0.235518839793595}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.18867671881020776, -0.4153091946113372}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.19820136304970604}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4824195686689698, 0.4824195686689698, 0.4824195686689698}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.39338656467258093, -0.8368767146362164, -0.10686424712400044}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4962144032839153, 0.4645818680851508, 0.22469252031634968, -0.3512781841936877}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.23670822359757293, -0.06477708013600447, -0.11171762199630064, 0.15235673759945523}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.007150260589147139, -0.3150825673317016, -0.3819015530435582, -0.2694589568247112}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3236086975183582}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.18135216371179808, 0.4824146643559828, 0.4606769563716566}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3747329635944896, 0.25545218768779865, 0.44864325093185475}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.14466721923085546, -0.17062477104895957, -0.0721764707646898}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.0056172314227201925}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.42730755239973384, 0.42730755239973384, 0.42730755239973384}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.208900271987982, -0.6771169667019237, 0.17756357276981283}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.17803277514468152, -0.20452112890219432, -0.30473715120602074, 0.1293866367846438}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.011595665880626882, -0.01036630908298497, 0.19455863070104673, -0.06404128367901674}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.250963907199904, -0.10243858095078817, 0.3753833316931827, 0.44975456091274835}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.19481043061857806}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.09876852411892789, 0.2344054572561406, 0.06607810660904712, 0.25689229640286104}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.28529786698066995, -0.240872022909977, 0.33026612292962465, -0.46135254365036515}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.48151796609422903, 0.229513177027604, 0.42684570514649256, 0.40776688745541756}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.36547426236535596}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.371340783273571}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2928448147604188}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4992167305720752, 0.5007832694279248, 0.5818563880485352, 0.4181436119514647, 0.5166847572934514, 0.4833152427065485}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.9432144657292751, 0.8051187779782674, -0.07252459668506939}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.03558865884332163, -0.4875957534451235, 0.4701975402774894}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3763682165763865, 0.09229192798337726, 0.057162770535571505}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.18272588556520453, -0.3413932836050432, 0.4351400738834752, -0.21688333980701024, -0.20923657021156294, -0.16283657730263779}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.22683108444482192, 0.1569873206138156}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4709509316572023, 0.5290490683427976, 0.46807091438696896, 0.5319290856130311, 0.4709509316572023, 0.5290490683427976}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.9032236319334468, -0.8721659297285094, 0.3669119338970708}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.3511591438230508, -0.08141443501738088, 0.34177727027879434}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.270123259362395, 0.15201344405416517, 0.18896368053939638}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.1890980138716123, 0.17667321671987557, -0.19804333053232737, 0.09204763106399827, 0.3283740055694895, -0.3004767793679042}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3535914125763834, -0.046836539081035244}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.29496897304355874, -0.397176386016324, 0.2180650235234517, 0.040860472434723794}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.0843871623843917, 0.031940112446296465}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.5808026787567779, 0.4191973212432221, 0.580922976428551, 0.4190770235714491, 0.5806345892035004, 0.4193654107964996}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.12973701119503822, 0.9995087194993957, -0.08924296319200842}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.3860262033070184, 0.37344634634495255}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.23559701669444377, -0.2555591620448805}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.15069434293593087, 0.16005078132632045, 0.35728688639149486, 0.48418918427532287}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.1554781831047477, -0.2543327680309104}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.15391924935779056, 0.27483853150670856, -0.05868252721573297, -0.0841041491185095, -0.4224727802049105, 0.38276804303590506}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.12704645655239932, 0.15533069231058305, -0.2561245853609603}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.34827626242079546, 0.4180927204014102, -0.142528146967003, -0.007964961548280525, 0.4289711553301597, -0.04237344995714898}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.45547790118467313, 0.16303696076392205}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.6321673044604474, 0.3678326955395526, 0.6321673044604474, 0.3678326955395526, 0.6321673044604474, 0.3678326955395526}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.6269613838255972, -0.2021530759855228, 0.5481709396165761}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.011481963969382836, -0.1008769809418889, 0.49193756486843854}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.199307432842591, -0.2574295242462541, 0.4458435936514381}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3663470744768843, 0.10669716765394066, 0.15714985918257296, 0.46290225571892374, 0.42391974188595105, -0.021890411964236023}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4911080377781041, 0.3760857547525206}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.1689233399199659, -0.32954276311226527, -0.06872637498365486, 0.04523245581026947}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.22768487763203127, -0.052336386351520714}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.013304080075083102, 0.08339429164645018, -0.06746923668745608, -0.24439452166565345}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1219971128392684, -0.33230401296541867}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.026032488614525895, -0.2864338860158647, 0.3965988869523154, 0.10700961963961075}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.07079333787689013, -0.4707325403781447}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2766299051072486, 0.28588596572865715, 0.4374841291640943, 0.26534877836725956, 0.2932591692474462, 0.4413920523852941, 0.26836575355886727, 0.29127040372461044, 0.44036384271652235}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.9108322903086692, -0.4986799148543297, -0.6099218527900778}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.2835000982641961, -0.05610242174844016, -0.22005185574015873}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.14047519802739394, -0.13729289286346424, 0.1782820543389776}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4415812647659424, 0.3228642646404667, 0.3524248275605707, 0.307496316235617, -0.044137335362924635, -0.38740919919954997, -0.0349105102679782, 0.3127759795558651, -0.20470117152055545}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.36644481556844366, -0.05334802313146347, 0.3029056018800732}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.45459023335465626, 0.26890750486513537, 0.2765022617802085, 0.45351688092412773, 0.27152453301807616, 0.2749585860577961, 0.45198455890717437, 0.27254940180586484, 0.2754660392869607}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.9108104934108425, 0.4084032443408807, -0.28858120420398214}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.08151628285349477, -0.13790014431793962, 0.45687327661583654}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.32829804086297976, -0.2916670131880271, 0.2586334532607275}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2897439227210321, -0.20723373711405613, 0.2540184193001316, -0.46944293294997164, -0.2533469970363088, 0.4224946531007029}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.0877650013272675, -0.1204587909528334}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.38850769406417385, 0.3374049526019477, -0.47016179818224935, 0.2622538804437953, 0.0993713210023417, 0.07742892801108958}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.07793988819019815, -0.4278882406459549, -0.4172437777298653}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.45318736259666287, 0.3276231120692738, 0.21918952533406322, 0.45318736259666287, 0.3276231120692738, 0.21918952533406322, 0.45318736259666287, 0.3276231120692738, 0.21918952533406322}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.31910857491413114, -0.319164139641019, 0.5242270639771396}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.1931489020252204, -0.4756711329179746, -0.050816863746118934, -0.4590998180724606}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.30371206491154523, -0.07760122732903951, 0.17955537311077263, -0.4873339514509074}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.016962856185400277, 0.10811202364629147, 0.4935772889775003, 0.37228664742807593, 0.13201573447816295, -0.49490693181773704, -0.23985659367885037, 0.35604611729455193, 0.4373324966292428, -0.09849204153386248, 0.1981427211626704, -0.059991964524999886, 0.16175623779877557, -0.4354032055531385, 0.27781683980451954, 0.48066428444717024}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3906411034099083, 0.32214870503217574, 0.014450380802486174, -0.21287852317621003}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.1571600983777779, 0.36961297799588977, -0.3593619787462716, -0.3132437305454556}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2180571557448031}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.23566859421639774, -0.38347236643027416, 0.4971749862830155}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.41545024792235086, 0.09100850313612852, -0.31091862796895287}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.38449434619510275, 0.22683016725609653, 0.3886754865488008, 0.38449434619510275, 0.22683016725609653, 0.3886754865488008, 0.38449434619510275, 0.22683016725609653, 0.3886754865488008}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.7784235757885472, 0.7398269417208871, 0.6033806624785201}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.40156911316959254, -0.36299611525685815}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.39983158247732553, -0.32715104210335777}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.08565350599398946, -0.4601409889559004, 0.39206234660931016, 0.2166441582608405, -0.32875316728029347, 0.16466023545361697, -0.2222170618843542, 0.1488286269500676}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.12125861495579304, -0.27684577105363073, 0.20424348431375194, -0.1343298558574515}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.2237453900099866, -0.36513859233424617, 0.0034865487135348205, 0.004689667053157098, 0.11361239902905873, 0.10131589766113136, -0.1529087608921773, 0.08268994243064987, 0.364637800306051, -0.4180721183884203, 0.4497354540803711, -0.09034544023199731}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.028769095556119284, 0.4277152378865152, 0.07430634888946186}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.45170192426419453, 0.1869954055747458, -0.11978352660429825, 0.09345009979047103, -0.23029173366310196, -0.009932033646201988}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.07330005686912466, -0.4896258868097988}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.17479006541566444, 0.08799758235094601, -0.25409669625134734, -0.2086369779207865, 0.27794866652137573, 0.18645154309540546}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.486540590171329, -0.031372271841618726, 0.4413272815624548}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.18635181480071059, 0.2404963668917221, 0.3077526362412979, 0.26539918206626945, 0.17981867341323882, 0.240837792092864, 0.3112488540939031, 0.2680946803999941, 0.18320621983785648, 0.24066855542516102, 0.30943078002312535, 0.2666944447138572}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5019862756169726, -0.393571808825385, 0.07383750305421732}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.09184585072042817}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.25511734942083186}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.10369692541313247, 0.3474224344260676, 0.467512127719627, 0.45302916067710763}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.37530199196046976, -0.21452272998336264, 0.006968432149731862, -0.13806574524884152}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.23512429832579634, 0.1825157317470691, 0.22064194482485935, 0.3617180251022753, 0.23512429832579634, 0.1825157317470691, 0.22064194482485935, 0.3617180251022753, 0.23512429832579634, 0.1825157317470691, 0.22064194482485935, 0.3617180251022753}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.4645262727712023, 0.8403590399743712, -0.9329109108436748}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.24476902207559414}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.45811339733773726}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4654937918974571, -0.3570065131909578, -0.1984059980798477}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.15219297730837866, 0.13298377579157294, 0.06458475139862463}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.35230445240298025, 0.35361801666468096, -0.192305670010687, -0.45324114580648034, 0.060688703271937205, 0.3311450335404721, -0.46436726235605197, 0.18925890384974686, 0.33797866947834687, 0.42615237945532847, -0.40152278614796055, -0.13179422555894615}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.04299457218062275, -0.18977359204913502, -0.015914516835070946, 0.4517829366090311}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.24097860617279718, 0.18362591522754432, 0.42064164405777366, 0.154753834541885, 0.24097860617279718, 0.18362591522754432, 0.42064164405777366, 0.154753834541885, 0.24097860617279718, 0.18362591522754432, 0.42064164405777366, 0.154753834541885}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.8822334503404285, 0.5175697971205591, -0.07539147974119009}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.4128567474606707, -0.015940705876657413, -0.18400129684166466, 0.179358790919238}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4032708956666583, -0.2276980062507975, 0.44221052426243257, 0.14371653440169152}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.10377338120456603, -0.2748792089507016, -0.47630606780690377, 0.15824141555215798, 0.15443761361481056, 0.17548736489011085, -0.3488978264343877, 0.2232082557013252, -0.08065700998993153, 0.10260872494524342, -0.04039999796682725, -0.11487220539982956}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.047271654572127786, -0.0075893401597671994, -0.053424967760344}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.059797909892259304, 0.030100159113878977, 0.2932214487657885, 0.3088146618476546, 0.15255675738109642, 0.07870434561882389}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3642205776090799, 0.2582766846837017}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.4508968580787929, 0.09105068964431218, -0.23650978136084266, -0.36532619226130003, -0.3986848036101224, 0.3320371820548329, -0.05894022575273605, -0.4574867241485202}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.14091300875831825, -0.2948490405140709, 0.3539189098867429, -0.4421110523783155}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.1673942667346495, 0.284659361488583, 0.26457374078676976, 0.2833726309899978, 0.16742250533687994, 0.2846615849069456, 0.26455003242216896, 0.2833658773340056, 0.1673530839473305, 0.2846561148051406, 0.2646083225852985, 0.2833824786622305}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4655092307121982, 0.10406535324449173, 0.9927161583249966}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.23150193136003827, 0.12556833895002928, -0.1691770205050579, -0.38620424827668676}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.320342373133791, -0.4600016505600545, -0.22355217910560965, 0.4396626780729139}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.05925846023315118, 0.12567590920643112, 0.2177416433047007, 0.14850019928867064, 0.2857252114959562, -0.07932536325158179, 0.38175868721665907, -0.0886789273488564, -0.2757651461901677, 0.28944644541484654, 0.4374623079803619, 0.09499452558950394}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.05830439895735706, 0.26737093368384623, 0.0767922559619264}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.407358424820758, -0.4474929924602107, -0.34534378804967203, 0.03487311279737282, 0.12128345973141119, 0.22914773669855937, -0.45332143633550304, -0.015409672891309012, 0.3437055603126429, -0.3420922631200811, 0.39419930013285054, 0.43989951151665996}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.05761001475956595, -0.018254336213164968, -0.03916874426330963, -0.32670261048848415}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2997567588044129, -0.1460363255910534, 0.12738350561124068, -0.49211846251180347, 0.35500002342609815, 0.18081321246638016, -0.39689610844084444, 0.1600904605351221}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.20247140174976674, 0.301204008253936}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.30712198750462105, 0.14747058363617616, -0.02692753193783548, -0.019875755218580538, -0.04402682551258441, -0.2720839060101078, 0.16500943292291714, 0.05771149704259815}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.09742052569101634, 0.4299003508467536, 0.43779382486333207, 0.36367071214646074}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5618758753431758, 0.5629345774656962, 0.5531720859574436}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.235826284403875, -0.013160903665822232, 0.24163596575773627, -0.5587065943836238, 0.39174397417835727, 0.8099844972739703}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.2841065830407712, 0.34076062001887886, 0.12387731007521052, -0.029328334023853153, -0.22349887626354215, 0.08871076217031282, -0.03380246162442857, 0.4511336931848027}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4437223444672186, 0.2560706198415811, -0.48612952637180484, -0.23200718616652782}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.40316168855020085, 0.2572916665165246, 0.40528411745767967, -0.28329378185655507}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.17527815867693552}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.6094566706948484, 0.6261125082750194, 0.6316921410036216}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.09483274911338646, -0.4153976747324064, 0.7687529756259246, -0.711529240920588, 0.9528093525964341, -0.9083348552252724}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.434176775044673, -0.29859228374920166, -0.22808120425075562, 0.25838003705094603, -0.3450447426531219, 0.10301019138986423}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1039899625615881, 0.35404005169490804, 0.11911550426897977}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.41362733681649144, -0.3396419906523578, -0.21693039791089752, -0.1943759102968856, -0.19031691678696172, -0.052847682366909954, -0.11454531532408396, 0.4750813246284661, 0.2861606834102888, -0.2401289408814108, -0.10780059017828525, 0.09649357049905438}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.008010103109319155, -0.19977672629732768, 0.05457140383638959, 0.22316060334629872}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.46438891900092993, 0.24993249272378315, 0.03119950513943881, 0.07831024394630848}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4250656554067983}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5911444343282548, 0.5913358961304314, 0.5913802388915828}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.6150756511541169, -0.7258329180151102, -0.8380531342707231, 0.13984381655556377, -0.8716403820254919, -0.0528622810353796}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.4875267107388638, -0.23923757768241605, -0.39617230785140567, 0.003986890242695718}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1189378992663962, -0.18941032427626536}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3071105766399257, 0.34567108390883294, 0.1126922327010933, 0.18160168905843455, 0.252188631645506, -0.0026546781333937064, -0.1754541764647891, 0.4455798652350724}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.35178955098249387, -0.022515675079303965, -0.24972235173565505, -0.0012099074113262054}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.017622569193684212, -0.1490475773187575, -0.1551863249924772, -0.18798760102370704, 0.3863860447502808, 0.12437024414154818, 0.23997133916662716, -0.08927462104086814, -0.14735894139612382, -0.27263661105171955, 0.47840116043889847, -0.2309484745560405}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11757817380512448, 0.14701884426074296, -0.35505558927093384}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.15530820120675615, 0.14992596204954545, -0.26819621581162}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.36457453966254283}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.36601047997700675, 0.36598033264678764, 0.36598033264678764}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.045720982503692165, -0.15016577916222706, -0.7681817736426113, -0.6672012697891754, -0.3182232391045998, -0.9130573423414097}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.2505218593648756, 0.10516660848808179}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.03374906853567439}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.49238931425793897}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.31165322694234354}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.2935684438805073}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4853022315142813}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.16612348056127269, 0.03617882985704224, -0.49217453597539496, -0.4204899168324586}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4708189295060434, -0.367394373337229, 0.14966839793814457, 0.09009607645789008}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.18396098726461452, 0.3757616006502612, 0.20006354438435714, 0.26003639389495414}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.48051502009135616}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.4837248832800048, 0.5162751167199952, 0.4951203702664797, 0.5048796297335203, 0.5235647890851777, 0.47643521091482227}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.09919693123276807, -0.9988863130725458, 0.6117603909663967, -0.9803013074956313, -0.214733220253696, 0.16925907311220234}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.13401450322080533, -0.31723840345138}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.023570854572266264}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.318086180659784, 0.13266324890376802}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2877696538285244, 0.193440614940949}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.47788798372919195, 0.522112016270808, 0.486159482026175, 0.513840517973825, 0.47547529252678705, 0.524524707473213}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.7735664166481864, -0.915990845320872, 0.6894152195714591, 0.9957474773371071, 0.11507533068837184, -0.8104870802761805}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.31323095414683, -0.13060582841816493, -0.1619954683863848, 0.09754492307177764, -0.08847654379749614, -0.40270874792884104, 0.27622362039403103, 0.24631237096887726}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4622864295100051, -0.2542208635869211, -0.48547683150485743, -0.22614298514457376}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.4401861873902516, 0.30291526470688834, -0.13574419916968128, -0.4142580772373785, 0.11578102414017899, 0.11562694477709112, 0.44372027413547066, -0.24088951717015217, -0.3042454909004968, -0.2228816025484336, 0.10301211742035776, 0.44358607186617693}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.06419722728714927, 0.2594059869651647, -0.267072656052874}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3797400963465366, -0.2723997221482839, -0.22704814348334212, 0.21845652830041018, 0.1615948837481307, -0.01603687309969104}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.28745041250122616, -0.32859051884947243}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.3779131324859567, 0.6220868675140432, 0.3779131324859567, 0.6220868675140432, 0.3779131324859567, 0.6220868675140432}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.6901724637483029, 0.18148414133759472, -0.5317171538233272, -0.6188302224237225, -0.6899475706527838, -0.2245576647647265}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.1167373164788229, 0.34675366644038275}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.319205871906745}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.48891220651176015, -0.11963026714401026, -0.044867690418609385, 0.1810580056314669}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.48544521866791523, 0.03038893786658725, 0.27236293305460313, 0.4376061691873394}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.14568702865260907, -0.360508147747163, 0.4910254027451123, -0.4203838105138453, 0.35805011850067925, 0.25468347972059313, -0.3163241845161686, 0.061152318182394194, -0.31671021660596754, -0.08893417854561625, 0.19128020458181005, -0.39534116480486536, -0.10462962082991711, -0.20898734109493022, -0.26741752862517965, 0.43498170159417604}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.31526553405043967, -0.21088402903455816, -0.14682286755507523, 0.15985263436019692}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.15807419416664392, -0.3403552305497559, 0.1931508815295666, -0.300876148816846, 0.43707787479476856, 0.19275612573871437, -0.4625388006786053, 0.4734582193281712}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.009359953194775339, 0.2791970421392821}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.2536328521588363, 0.7463671478411636, 0.2536328521588363, 0.7463671478411636, 0.2536328521588363, 0.7463671478411636}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.7575843161968638, 0.6506084239521752, -0.2891229798172785, 0.23290295659188076, 0.2550585198147366, 0.9694012633834386}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.35343807564959107, 0.10802235079098066, -0.42127975595647826, 0.42749929629698347}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.29253432749496067, 0.34542839631783306}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.08388973049399118, 0.060855049912531656, -0.4664761635776894, 0.08374925534043753, -0.03991966623776755, -0.058799483434155864, 0.15556733219577812, 0.3443152321720876}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3083919794996658, -0.015019802638767565, -0.4617752869328545, -0.367217892240275}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3381249665467839, 0.12582221007652217, 0.26350501426637307, -0.041762439512068705, 0.3164099705746266, -0.21968640735352796, -0.4671775919422113, 0.15301203393949547, 0.08817408704425822, 0.24178521473161274, 0.4495657267345161, 0.2579430184330973}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2664203626517412, -0.3293602674550915, -0.45031323721070915}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.16998803324903478, 0.22579289362227428, 0.26717523658593867, -0.4035606940063522, -0.1088163712108049, 0.22919189587827604}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3841325111052608, 0.47328897010683046}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.4006853870220509, -0.23594140051997303, 0.3748404657199955, 0.18134881548365767}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.10710290776107045, 0.4768234194620452}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.306278754957002, 0.315832621797432, 0.37788862324556594, 0.3071120021258795, 0.3191028408933103, 0.3737851569808102, 0.3158234225776712, 0.33676828818536303, 0.3474082892369659}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.8183017697895443, -0.4175875609481179, 0.49602709828417946, 0.2483082797226599, -0.6459939785486564, 0.7378808890336084}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.48629563196596515, 0.03483363316644561, 0.06957346901122663, -0.14538455399268446, 0.13978501895162365, -0.34252441119878396, 0.4421116785938489, -0.1818155915665085}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.26718751473173774, 0.28060610263493935, 0.3177097325423871, -0.4682279642369055}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.36108035252740345, 0.04550626137473557, -0.16860226589294225, -0.21331399229945724, -0.2726864559300216, 0.270940138404561, -0.3668443981966589, 0.3380577502993648, -0.4130470008870245, 0.1185196907354158, 0.12992286539937092, 0.06325123605423366}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3763519300328848, 0.4116213253584834, 0.46229550501557615}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.5666196452179989, 0.21652375208055233, 0.21685660270144871, 0.540246248771685, 0.2327214755985902, 0.22703227562972475, 0.5022293350076819, 0.2598865252971749, 0.2378841396951433}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.6448334992825144, -0.7502717311938927, 0.16617957634273584, 0.6620575586668704, 0.7787845836734104, -0.9270759097355581}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.41763386889259746, 0.18144758298035646, 0.4922568886540244, -0.0581820336578841}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3249855039061351, 0.26286763785765177}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.3323352397822137, 0.2983884116732225, 0.18713627157123147, -0.4303851794578837}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.04597532134767768, 0.330907078658232}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.32930511488822156, 0.315676005378405, 0.16385826284190008, -0.42373816722986, -0.34113361257914, -0.3981509034707186}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4688506590272915, -0.24845996529869563, -0.25539090474337045}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.24711415841424933, 0.3100180046612881, 0.4428678369244625, 0.24711415841424933, 0.3100180046612881, 0.4428678369244625, 0.24711415841424933, 0.3100180046612881, 0.4428678369244625}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.7953005552439707, 0.9656742935358098, 0.19674549721941603, -0.03053377046884087, -0.453116144628686, 0.6436217617891935}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.11581383898878705, -0.013616063438226522}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3453025345404064}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.26457432355254773, 0.16168995458101187, 0.3692003433010571, 0.18546679445305803}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.12111396002215302, 0.3695641558671733, -0.44253529759007926, 0.05521875939259302}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.43945639749234944, -0.09909376418886529, -0.12542906999711934, -0.4383493973155994, 0.34480982505133906, -0.120843256930662, 0.09857025892932936, 0.4002962380915709, 0.3143032503324916, 0.45751556553953077, 0.40659357057072176, 0.4100255239861984}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2991819213251259, 0.03081239513157097, -0.07208659751112467}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3399062794544149, 0.010424997602200503, 0.485961234426201, 0.10181547389093404, -0.27893430491618754, -0.039782745283020504, 0.3162199375305582, 0.22856224352315768, 0.12740116594315587}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4423683325442309, -0.09355111119602666, 0.1877939113097109}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.43587024736031793, 0.1776671686527137, 0.3864625839869683, 0.43587024736031793, 0.1776671686527137, 0.3864625839869683, 0.43587024736031793, 0.1776671686527137, 0.3864625839869683}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.7197972032834188, -0.06034004154011274, 0.7562455559045012, -0.9193196628446096, -0.1268271801096097, -0.18308445625836778}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.08041234699147726, 0.43750894780464566}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.12497476106621852}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.17359073211280096, 0.24879772729230487}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2705071659425159, -0.23762367934751327}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.3744321483161329, -0.27894926269961984, -0.061682896316618274, 0.21433380455570872, -0.4104859282242047, -0.08152103001647104}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.42405097758524735, -0.45325004131573643, -0.44345217243075385}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.25371297161706075, -0.4492065794915995, -0.23516572864811391, 0.25607461393324105, 0.10818444244953906, 0.457131879659484, -0.49057536903885357, 0.42338965392714556, -0.2725149360697178, -0.36621727548801963, -0.17593215102371595, 0.3413890162421226}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.17895145795574374, 0.08119457817777309, 0.22868674249010024, 0.12760669213773934}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.16000751673770108, -0.09112746447751763, 0.287118445178314, 0.34276583645602543, -0.31425381686981346, -0.3532128720295875, 0.0035776404049333577, 0.2610149824975022, -0.03500336108786084, 0.47210192132424755, -0.22475434518668946, -0.25133820599465995}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4018154615243742, -0.3990632856325875, 0.4286449165700993}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.36270247366109826, 0.17035285025535854, 0.17057951927219528, 0.29636515681134795, 0.36270247366109826, 0.17035285025535854, 0.17057951927219528, 0.29636515681134795, 0.35341656309480146, 0.16451211792390855, 0.17593676344250492, 0.3061345555387851}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.5009770573697034, -0.7456358434101764, 0.5905999975732714, -0.9679264432641648, 0.6687679205384487, 0.9668598722492312}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.0302393499213629, 0.393471471938603, -0.20901935303155417, 0.1837196490825901, -0.3403307856594623, -0.1753495455597084, 0.11821153653339811, 0.3261346108472932}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.46895758038761637, -0.4807696554000097, -0.41409282833412353, -0.27105534228762396}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.3558881650972875, -0.28929702230683085, 0.2748066590986732, -0.38002822369660283, 0.020752592901998268, 0.042380762349479295, -0.3922685158624688, -0.4526172599891046, -0.30654211128857867, -0.10982037535354872, -0.20676897950988504, 0.08100949233251509, -0.41272138613991893, -0.4101336063633333, -0.09799409994838904, 0.09324800998974037}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4595550886997827, -0.29615590196842057, -0.2948262010042749, 0.25756455419859015}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.21644000123167428, 0.33588378554237364, 0.19666473203618914, 0.2510114811897629, 0.20253365631569684, 0.3544855116445662, 0.17860581558892213, 0.26437501645081485, 0.21378661888701211, 0.3344984099902636, 0.20014705873422958, 0.2515679123884947}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.5855359083800913, -0.409146576502448, -0.7154614574624674, -0.9592890572508279, -0.6987485731581378, -0.14230462555885315}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.08579553530812878, -0.3127197928706863, -0.4534330050631453, -0.2356069036942242, -0.277226092551779, 0.3689051649351045}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.116011525107523, 0.34312018063087035, 0.0233389248850302}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.07707778955868894, 0.20737335855941652, -0.2701551824786448, 0.4939402777771986, 0.017950265446958547, -0.3504922876390417}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.06789651115200035, 0.15671756112171054}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.39643078901062934, 0.006171534218376906, 0.030825716695850103, 0.36184530209408305, -0.12196210326786694, -0.4658644441607088, 0.10094837621055175, 0.27790551088709103}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.317273193742138, 0.031293692372578064, -0.2924672836423632, -0.23852380133199313}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3437539764491548, 0.1426692870380017, 0.13234898962099292, 0.38122774689185074, 0.3327548675037472, 0.14927173043928516, 0.1405670679318068, 0.37740633412516084, 0.33405457786259685, 0.14848647815159877, 0.13958035215421144, 0.3778785918315929}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.2933876126528623, -0.2026104160645117, 0.0769579913361742, 0.762625287455102, -0.3031398274936361, 0.4287210296867543}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.44808697414482057, 0.14961080709369656, -0.2778722437460851, -0.40472859018381124, 0.20063524510761888, -0.3973068445753887}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.14930131079699394, 0.20962664506253048, 0.3899983978871856}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.35837150066036516, 0.003492626410241062, 0.4924316122374447, 0.08287353310599754, 0.4730501494516749, 0.17708077738879713, -0.49052139581164766, 0.47169574865870534, -0.13428034982767556}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.1968461104590019, -0.38858413875329356, 0.24011303339360768}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.42205950378489376, -0.32193633778142094, 0.40258043394470966, -0.37665104865765076, -0.09505852182883623, 0.3680757679416936, 0.1204958813486734, -0.27447896305009456, -0.29809160580609706, -0.36863728381503835, 0.49364808605889854, -0.4919629888087327}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.25701238562932294, -0.3485248526338657, -0.4906941540192825, -0.23262062692833074}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.4070567953678369, 0.45790520067775886, -0.3300263618226936, -0.4791114595735475, -0.2466209744353718, 0.48825035721990795, 0.12315178119762482, 0.13800670064720288, -0.37274582817956714, 0.4710382067326363, 0.470046432219124, 0.1258372882905554, 0.21836935909792954, 0.07875859070608149, 0.1959934900321061, -0.27454577149371084}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.12563498553486863, -0.38020620438726305, -0.3832168995182087, 0.3369345075683188}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.11450299155258299, 0.27946012373207074, 0.26809345047343885, 0.33794343424190737, 0.11450299155258299, 0.27946012373207074, 0.26809345047343885, 0.33794343424190737, 0.11450299155258299, 0.27946012373207074, 0.26809345047343885, 0.33794343424190737}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.8819002411578605, 0.4785086721535381, -0.4205060863007668, -0.9575963516706436, -0.7283654143893699, -0.43532748791156317}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.0612142917746068, -0.4315097935155773, -0.06352435451583327, -0.045385325811683974, -0.4282410510233421, -0.02639098854509081}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4595305541497987, 0.06770436315544548, -0.43332954541526136}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.3220880838752628, -0.3136914646848872, 0.28527759355292825, 0.20597752311455764, 0.23759091826028633, -0.28113952519710517}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.33784245242437194, 0.02945822042699342}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.1785079891410205, -0.4962816748696858}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.32742393084204424}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.2206272923873165, -0.4387918152198287, 0.2436902053593193}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4213525858347733, 0.30179569487161884, -0.3039669436255965}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.24754039196072197, -0.2690363014824766, 0.14514384791324997, 0.159776093629872, 0.4972154297050839, 0.25915355099738235, -0.39737282974050914, 0.275161686145293, -0.09012367703403124, 0.3812655463456006, 0.2681940084267924, 0.1423975533010735}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4531361236020238, 0.2078710653942023, 0.23336193235135405, 0.46700765912687003}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5279040515938033, 0.5146584509439467, 0.573387144007787}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.2419372488926521, -0.7941400692206473, 0.6341147564191056, -0.04588408348832096, 0.8977933779340603, -0.936243628872472, 0.9041912664130427, -0.4123124155579023, 0.3943767563584897}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.24460824860488506, 0.4527368805399915, -0.23330279338834048, 0.47261365402517075, 0.33977584123297266, 0.27227876302722787, 0.47711524865682076, -0.19362124420328597, 0.0938133330549461}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2787882561582987, -0.07048906503463226, 0.07119252856041691}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.10163170060495408, 0.42967522231266797, 0.09919958356282843}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.09496644226808859}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.6429221791236006, 0.6461697223002689, 0.634497939056124}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.684839927162465, 0.6018401614359838, 0.26884761509721056, -0.7434876766829963, -0.500878993288089, 0.9520788494148509, 0.7354000883711467, 0.43727277066658443, 0.7319831005982114}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.13972406090068812, -0.10970218150603939, -0.025022303401308954, -0.19520246414597353, 0.322331097980344, 0.24650627000662018, -0.27530659155248827, 0.3530028986498055, 0.4774649852836601, -0.4785628708127857, 0.01665786724189, 0.03206645309898326}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.23567156107220966, -0.28657572310028756, 0.29155115325341685, 0.06779562573922293}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.04872461647082782, -0.4437044078419823, 0.2022071517435342, 0.26260460389109264, 0.059007716108838815, -0.058123168010239534, 0.24523939120615845, -0.08706508356447351, -0.2895288884863305, -0.24458543831725554, -0.007223565265816245, -0.09217661106401587}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.10210296343613678, 0.12884873943040398, 0.3468868331027185}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.3775570820233394, 0.3982181300495041, 0.08523843509646789}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3306294122523158}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4633474637342554, 0.4597363642637461, 0.4544298890916855}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.6820273189807955, -0.7386699595537649, -0.5438373271830144, -0.08716195804640314, -0.5951570464085845, 0.18059994115092692, -0.8927585063822185, -0.19710253755482032, -0.11294979033331631}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.3601567609708328, 0.12222179127855892, 0.45550088237597286, 0.3864204735347012, 0.17127031561228034, 0.4389217430424319, 0.29351769527063054, 0.1430173041998194, -0.18605866591398446, 0.12058222770448745, -0.18827959492295798, 0.3804178870259193}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.28333972050491063, -0.21799735081586158, 0.14747398586704008, -0.2856779821596368}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.1192009629304952, -0.40894462017804556, 0.17738430686560203, 0.30419649285981976, 0.11736661013387562, 0.3842533442267866, 0.20136110034829158, 0.005938294412686451, 0.3661171961497026, -0.2344223437568722, 0.43999436375477596, -0.04213679270808668, -0.3761446907399262, -0.34360999130268655, -0.14882871699678235, 0.412033391745974}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.059097154566082444, -0.2505307448664841, 0.4817721117910839, -0.44289645546278156}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.2871934857895654, -0.38371660687975995, -0.4205017940822048, 0.0700354846317468, -0.4464351859924741, -0.3416853562665655, 0.37264579209637616, -0.1706290420453307, -0.01153623368555412, 0.36080742713271907, 0.3911751581256273, -0.31824867609901486, 0.1012351377010745, -0.07918359229550398, -0.16730218886784798, 0.4631020606795927}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.1947396110108054, 0.16286717641829584, -0.04006563223009452, 0.09916611014718602}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2304658873372768, -0.44797336396057896, -0.4845138034176508, 0.0031225056802953732}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.08645663865291253}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5262932524544508, 0.527218084742029, 0.5274757130265901}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.24639518049039166, -0.8485639347159415, -0.8738768371329899, -0.5006442963662401, 0.4471035802264698, -0.14177654834455633, 0.2811818094230232, 0.6336076347214108, -0.7688195646122311}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4758180239072548, 0.24349630746585016, 0.3506595498033358, 0.3601735161086398, 0.1750066008538511, -0.35349562681042046, 0.15277557622018223, -0.3989127694374409, -0.38063025924852345}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.11335652593686285, 0.26516812824291114, 0.34985448696939536}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.28602098238718443, 0.2870495169225131, 0.4197015818500873, -0.29952061215976666, 0.1941234117709283, -0.3398456284514425, 0.011274949754444874, 0.2505405561751607, -0.21197653747512724, 0.4581287697250198, -0.21778165189820675, -0.05105063470656479}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.40095346739065063, -0.249239620038878, -0.040920925771819494, -0.476210792810309}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.33930411190322063, 0.4383785653719866, -0.32803109883740356, -0.4035768921223504, -0.3190657766393574, -0.3255279602979272, 0.11012648734208519, -0.3056921675940196, -0.10800337318519271, -0.28473442796987347, 0.37418342372754065, -0.44355417363315996}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2722651601981334, -0.4332613093941574, -0.1003417904329752}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.26319906185272024, -0.20826555304664618, 0.38605788666236607, -0.3244511524007344, -0.27362637474014484, 0.42074132814990206}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.14147720114174467, -0.17454972305374983}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.21751439668933326, 0.414340289278598}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.15534046644346367}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.5430638753810098, 0.4569361246189902, 0.6787287995807106, 0.3212712004192893, 0.5420260190789483, 0.4579739809210517}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4225201190757868, -0.8507777428846139, 0.6391133519812853, -0.9565422706562909, -0.8091445820749532, -0.8909172453961454, 0.5517932422465377, -0.9027764505982994, -0.5983190521377988}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4737896026550795, 0.03384724436933095, -0.44133041332354805, 0.43611271141165886, 0.012849536411000173, 0.0553128888761909, -0.17660339890889687, 0.043492226388693656, -0.346161698677495}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.005254200156534661, 0.2263598551969347, -0.48130477024676643}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3746908219594447, 0.16401235483283816, 0.2592923856659203, -0.4965062629785316, -0.16431285043265464, -0.416993305118464}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.15510346644755435, 0.12525648513315124}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.6567863255261966, 0.3432136744738033, 0.6567863255261966, 0.3432136744738033, 0.6567863255261966, 0.3432136744738033}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3518382256202941, -0.6405863212365006, -0.7048815485719524, -0.5961674038182951, -0.9851269887912915, 0.9571941544400204, 0.7636318949484016, -0.4212969075594224, 0.9765693457139784}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4130712290313563, 0.4447062521912314, -0.20270899488972982, 0.11114632647262412, 0.42251728957345314, 0.08613748217316619, -0.146778632884226, 0.41974751442943514, 0.2770913966142178}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.010355956519317866, 0.23778101314166666, 0.05624720934615812}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.15524487019177458, 0.47592261835502436, -0.36692481377160957, 0.3213422436460991, -0.21856872776764513, 0.07231743408753999, -0.185974147207714, 0.3170813460439972, -0.1156994323549756}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.21346653774132063, -0.20892693431886156, -0.25304692799505824}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.12686591073908893, 0.029545921318570922, -0.4930770966683521, 0.165209010326975, -0.16552585324227476, -0.30127821001469834}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.47178788676575323, -0.17721764045338406}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.43342853301512513, 0.5665714669848749, 0.43342544775355607, 0.5665745522464439, 0.43343339221855937, 0.5665666077814406}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.37431557770583, -0.1705913124532321, 0.4132351823819691, -0.05545381483552303, -0.3559195490801734, 0.6455839255019462, -0.3533438292231106, -0.1328660827245367, 0.7354736236321342}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.1796954025604901, -0.1515867331597731, 0.08062370087101112}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.12804370017261069}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3018579306176218, 0.20670084670041844, -0.14561537926355228}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.44410982747952665, 0.17638707978693235, -0.47192550728497384}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.27119801894124473, -0.2496495136043293, 0.19800727681937758, 0.48354926466235426, 0.24696385759678208, 0.382475944091899}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.24307980259908368, -0.12701171999214889}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.4122713774311978, -0.43359770164771105, 0.4355213643380301, 0.2529052261136969}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.22539004853658362, 0.03816378556356992}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.7465837764593459, 0.25341622354065396, 0.7470324477243835, 0.25296755227561657, 0.7465837764593459, 0.25341622354065396}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.9430440160724587, -0.6799143952892586, 0.8417169617017912, 0.6773162555396679, 0.41592471856263513, 0.1824606265601223, 0.3926334145442576, -0.28414921193610354, -0.6165534944101743}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2926596614710427, 0.4351180132316059, 0.22705692349972195, 0.2897267903597611, -0.23935961730700628, 0.40327608371550905, -0.2473967319715964, 0.06410327506208591, 0.025323790824266945}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.26956830842993884, -0.291319328243805, -0.22411125936285092}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.21930912307153327, 0.38543773631109524, -0.2915160036255837, -0.026401994284700137, 0.05455089294696891, -0.4433215074700383, -0.1910850629557923, -0.2833644663580458, -0.3548173239249761, 0.22032803812149349, 0.0998208632585238, -0.011162270976642907}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.06182788595055222, -0.037804410150998, 0.20738415433810342, -0.47370344618722915}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.49473287715224923, -0.42164868365533525, -0.25964959827818457, -0.31514347538866194, 0.1431358182265381, -0.1367184973798654, 0.33524880895653286, -0.021094545449156232, 0.00679925864500508, 0.3490597716606396, -0.07285152953457463, -0.4976149105328188, -0.3593887279598703, 0.3492319749147458, -0.14265987513588374, 0.4164024936622428}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.21785267472523617, 0.3611476627860982, 0.010065465560708309, -0.21002693805552886}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.1398344754937909, -0.11179770637349884, 0.39440731891892056, 0.060413392922754605, -0.31870142206428753, -0.31123236223333517, 0.22233881851134596, 0.3488639798631499, 0.3668260545023466, -0.1081954804643821, 0.20165295565038954, 0.3021171460819465}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.006023840227934785, -0.027676938587284594, 0.34117855106635353}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.045603670015430864, -0.15088410956679021, 0.30504474327914033, 0.18142053248009116, -0.3757572591018161, -0.31999212383256337}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4193526237865015, -0.43939436954192046}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3058135984189109, 0.3566253061068859, 0.3375610954742033, 0.2828978248657772, 0.3615766276420054, 0.35552554749221754, 0.267512477520076, 0.36447574434816515, 0.3680117781317588}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.02941637331094893, -0.08201270436490882, 0.40925041279479757, -0.5102526945379413, 0.935949262932396, 0.2593004682323927, -0.567506295649604, 0.8893917072859303, -0.5502242098021204}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.47265123985076607, 0.28710537432321226, -0.32062217518262814, 0.4050804691043314, -0.004786335196222513, 0.45496137929520875, 0.11614554588247872, 0.0416789319858929, 0.32018628728066545}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.034754844459318424, -0.4995216064742076, -0.46599018678107074}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.20116360015660228, 0.4225389800571244, 0.14524405614339808, 0.03271239811762905, 0.383687851187669, 0.47644712366425523, 0.12981118810925685, -0.09993385901598384, 0.04285516241062248}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.40749352862036814, -0.25378362159123014, -0.3087227719113512}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3902031148487647, 0.2597007845576256, 0.35009610059360974, 0.3902783537532962, 0.25938815817687333, 0.35033348806983045, 0.3900761890116767, 0.26022682056264496, 0.3496969904256784}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.8164932240419556, 0.785673694260977, -0.5562612955661301, -0.14767715384054902, 0.6100009725450892, 0.9420338591207931, -0.16737398161151296, 0.48122858528705814, 0.7433383612094051}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.07468185752629664, -0.3613897792645999, 0.2725728350795338, -0.17858780462169288, -0.2712497773542666, 0.4657301654654328, 0.1794555423829347, 0.4043031931611817, 0.18592351964118914}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.06422558182656712, -0.3022416734618101, 0.12349078547929893}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4563426812983765, 0.29492308491530794, 0.04068100021029608, 0.006669202667212049, 0.3911190332866763, 0.17447916969934973, -0.37388925195963874, 0.030927873383630566, 0.2205860599980627}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.48861960352046996, 0.11900510385045948, 0.028514403977142888}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4699025964550655, 0.42738511160313475, -0.2141229476523221, 0.1215791453109194, 0.09403029593023637, -0.13396372807838852, -0.08316573831792318, 0.14030058632633047, 0.07665717471721734}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.019382591032893637, -0.3307665680022708, -0.07000850507574452}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2626885362504158, 0.2901277047977509, 0.44718375895183327, 0.2627713212979707, 0.2888663314682629, 0.4483623472337664, 0.26273456904777914, 0.2894301631241458, 0.44783526782807503}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.12185591000311469, -0.8733089314524407, 0.08266503618596532, -0.016882511073128548, 0.2490091348705996, 0.47641129739125954, -0.10309956148181887, -0.8458098591208845, -0.3743466849032555}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.22607476049108755, -0.22810652374831686, 0.16442120806379712, 0.1688633889738107, 0.43458537102921757, -0.16851428944655156, -0.26448340207523624, 0.09450060580718112, 0.314004047959654}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2903191695650482, -0.292558750000516, -0.02369960278566341}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.37009857078659625, -0.2193536642700208, 0.14435648347800278}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4320243479595909}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.03281300224486183, -0.28915620993745716, 0.287761186776458, -0.04156420246328696}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3838630063468572, 0.017612958079970542, 0.06341898737092122, 0.03266879756142771}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.0031653277039600525, 0.36487351453328254, -0.00632547291816854, 0.3805120915210468, -0.3594565243995287, -0.48677505298835044, 0.16414352048430136, -0.1128774767201669, -0.06120026782348653, 0.3331431181930051, -0.20188247180956898, 0.04935224284683937}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2839163983877975, -0.09125131816212873, 0.32139894552676584}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.4736367847994057, 0.2795727986053743, 0.24679041659521997, 0.4739705837480785, 0.2792563673816752, 0.24677304887024631, 0.47386135932801793, 0.2793598925130732, 0.2467787481589089}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.11687014629959225, -0.594221578246408, -0.47405207496898916, 0.7458808289345125, 0.1434200857948551, -0.2730161996867535, 0.7600322878560317, -0.41009370844213255, -0.8874273142546387}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.36292835211115027, 0.0764707049836163, -0.041364958259035634, -0.2278675584419385, 0.4193233210378644, -0.26167298544285633, -3.313743020427751e-05, 0.18222350750225325, -0.1679533583327807}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3499693632056594, 0.1528287238882684, -0.4120620399721485}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.21329755488716617, -0.4182648152359919, 0.25486082736170357, 0.2684653007833194, 0.44469312165933494, -0.4371923999218009, -0.1982367348935209, -0.48117103471504363, -0.46655510872942096}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.12921578934228573, 0.4335389053283075, 0.45147474684619404}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.017063553278826915, -0.4334532876182662, 0.14767431881239945, -0.18744749117245085, 0.29952526515193756, -0.23497037025900602, 0.47047658519488245, 0.03531752020001411, -0.24677251603410844, 0.015373683137822947, -0.41083505947652454, -0.4586926967450189}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.03582891241635011, 0.17958172343153933, -0.011780675298079024, 0.14408506819795408}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.33776450241018363, -0.08343333728726277, -0.04615837369659026, -0.46017936748894206, -0.035884104168866005, -0.44185145245679247, 0.3047441891262477, 0.4256243564129878}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.059078371113406636, -0.379657849496832}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.018423189484454094, -0.21634278812102947, 0.3813065963653448, 0.2775282853243841, 0.17149613497769756, 0.3411957396327142}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.17563242266186907, -0.36533899175396556, -0.4820872480485683}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3634670319298321, 0.19880826358817116, 0.18159169369101566, 0.256133010790981, 0.3634670319298321, 0.19880826358817116, 0.18159169369101566, 0.256133010790981, 0.36215178846630064, 0.19595758826817902, 0.18175692107014635, 0.2601337021953739}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.725775017722893, 0.5821630999895067, -0.3717090227905131, -0.6830693489081223, 0.5202344953446425, 0.3363389474830998, -0.18115579907465862, 0.9370969753727341, 0.07289401972128284}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.34836645396702914, 0.3550332873335922, 0.428501312327196}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.25933221569517695}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.07402604989773054, -0.334718854828699, 0.03525554186584989, 0.38684948041745537}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.45390235200276763, -0.14944538395011786, -0.2400255191194307, 0.1039106382966889}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.35207018932011214, 0.16235220345026077, 0.2965982889000953, 0.18897931832953185, 0.3464620669319996, 0.17015399761332906, 0.2955748378268027, 0.1878090976278687, 0.3497963823387456, 0.16549289752889762, 0.296197971150341, 0.1885127489820157}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.9561277115523781, 0.5432199530581256, 0.7198334003999012, -0.8452755311937723, 0.28487751681754525, -0.3577450353759184, 0.5761582387184003, -0.19425547636242135, -0.41558867532999777}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.001019432736420467, 0.12317619784691958, -0.18740029953269577, -0.10408527959927805, -0.025095615090730217, -0.19936679456878592}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.387735543343414, 0.33054811313183063}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.06309733914094828, 0.13516418269150077, -0.460451737895907, 0.25473349276377955, 0.09199868806196076, -0.2534979278370819}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.20588783594201232, 0.13850730112238796, 0.16984011075704997}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.2732145984855644, -0.46716418685650185, 0.17027766194810767, -0.20350637305522412, 0.0842189601628015, -0.46021187553352727, -0.028690105867733906, 0.05038088725422907, 0.453395395403722, 0.4486102626104558, -0.3851953049186282, 0.06750244821298679}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.49373693077359093, -0.3315682059340501, 0.18612300220260025, -0.1351632460404486}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.18618237595320605, 0.2729021758799756, 0.3404633426469493, 0.20045210551986903, 0.18600960371169298, 0.27289446639342474, 0.3409855173576002, 0.20011041253728196, 0.18626013343767683, 0.2729055099449261, 0.34022829811765865, 0.2006060584997386}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.5958017183591073, 0.3185546589285704, 0.9657063926465843, -0.9965948364074242, 0.062355438757575765, 0.8348872055136016, -0.8958095125583723, 0.20660720724488946, 0.535684993183241}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.07441365341777206, 0.3392112339271979, -0.230834838440222}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4077602496585132}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.20225612332633358, -0.4441423783849151}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.433735828705781, 0.35848539931906287}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.15540334630255115, -0.1702010117376609, 0.4180443086649305, -0.16827603661923185}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.14699794107718245, 0.0037633020214066226}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.31995343305858515, -0.05876977389479532, 0.3413705573150424, -0.13001265831515652, -0.48920072325623765, -0.012976309042219025, -0.14382125121943223, 0.12622707733969252}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.19190167995972673, 0.20156100379063768, 0.4280684955217906, -0.13475036032807286}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3373855629381556, 0.24000918081818792, 0.1578251677850055, 0.264780088458651, 0.3373855629381556, 0.24000918081818792, 0.1578251677850055, 0.264780088458651, 0.3374166376612508, 0.23995192282009553, 0.15780044905744217, 0.2648309904612114}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.8230572316507954, -0.5352131972037566, 0.44948366004233753, 0.5991661966859791, -0.14452617845587157, -0.24127296596590964, -0.9953717951312311, 0.7616178177679438, -0.7713476650676008}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.397296690253219, -0.45867730758342595, -0.18093688430777666, 0.018031816265066225, 0.16658903558329807, -0.2730170060285144, 0.16621921492201208, -0.027157302935800987, 0.22937723244020314}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.287935963373136, 0.3362917908828992, 0.31192448581362264}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.003442247358199535, -0.1665778230000603, -0.41723030068905165}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.11291227870216469}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.26714524859966104, 0.14520208726664652, 0.38732114245063665, 0.4065488248172059}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.222974550334617, -0.38191592273967434, -0.31036832353814225, 0.46551247812378493}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.09777807395139915, -0.3006662968981839, 0.16517968229859037, 0.3918926304098046, 0.36514236866219285, 0.3167071632406292, -0.13827379413539853, 0.10483689200023216, 0.11057627109650203, 0.18405392698625134, 0.289924839766165, -0.007079534786962216, 0.40978979919944547, 0.439432286196048, -0.2954117581581206, -0.4045798873893114}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.16299749250562978, 0.20354729519279235, -0.05461512724412121, -0.18174395420454614}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.27282662260077994, 0.4041373640763545, -0.24665258263788858, 0.41499824797811613, -0.47881970750752356, 0.22244515236707352, 0.07069034165154453, 0.08053371345075311, -0.4575672543858048, -0.1327745311079983, 0.19621273282498308, -0.43193651924715293, 0.3920508209523774, 0.19637818332175094, 0.2314182735659437, 0.3589539962999527}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.05103674342880504, -0.19787501485166614, -0.49937982513664414, -0.1268629823913905}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4070081634476551, 0.4070081634476551, 0.4070081634476551}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.05977350066481968, -0.23961133984491068, 0.28621966674249677, -0.9343788001662836, 0.8773777263852371, -0.08372365887009137, -0.504348807241128, -0.6096989180306862, -0.6231999823978134, -0.8637164904299488, -0.18870296232655837, -0.774847985941689}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.38937510780414053, -0.4838765248663739, -0.2830652549457069, 0.37016804852740703}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.46933966623378454}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.17500388206942208}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3763473896970285}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4703131118514169, 0.41909210805709524, 0.41909210805709524}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.6395638353525874, 0.05319438473132765, -0.8298378190766815, 0.9130875983105256, 0.05884799650325312, 0.7375822627112238, 0.826382315132703, -0.9673799468645383, 0.0050753458577152966, -0.8376164985564429, 0.49208640778347457, 0.4738348021410037}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.48213100277742604, 0.368693831245153, -0.10046920471201948, 0.4595375210788706}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.1005621947630907}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.16787235976396542, -0.2956980054948616, 0.45988335847851003, -0.39809462951074104}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.07420643007013672, -0.21449534521432678, -0.07940364900975905, 0.37514467258544626}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.333132535683924, -0.3552376608659603, 0.4434999882468087, -0.4078444730152522}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.19822138147926027}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4690086534076885, 0.46891511334906616, 0.46889751164936017}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.65477090018111, 0.2609280712602704, -0.20804681231912703, -0.6945601666437677, -0.10690266891150157, -0.9466701938323312, 0.6175014529270788, -0.6941472300591467, -0.5089417999208081, -0.9555028145722126, 0.9328833498157163, 0.8910798419388268}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.1703297152489558, 0.4702909722262152, -0.4069664628736521, -0.002110912003019938, -0.07615978546250823, 0.2672217383999659, 0.2913868005749247, 0.20669884401879235, 0.0030636399742846043, 0.4424707667796284, -0.13563159242241973, -0.3548929846936134, 0.3303023671508074, 0.2483882890470377, 0.3802491567590405, 0.4208918654641436}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.27485337088094497, -0.18630707372687316, 0.05107502009693021, -0.3957004798087006}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.4185097746000612, -0.4680730891332582, 0.4328712724573863, -0.1143838761421655, -0.2222089910564522, -0.24764237732315653, 0.1822380747236786, 0.22178634573257572}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4089476462470768, 0.4758278180507378}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.06392983152357046, -0.17019073239650706, 0.1781174538187964, -0.1432040853088875, -0.38825309902498606, 0.03466509373562621}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2293236737861113, -0.07490832724486984, 0.4576566034282721}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.20589152269527466, 0.4546746309171229, 0.15494470035298846}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.197967331861287}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.5505052969990253, 0.5523061943701832, 0.5523061943701832}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.8158716996766611, 0.8445985125671207, -0.24974986692854872, -0.9735872943993349, 0.8823903041985663, -0.2416464700387726, -0.5799199418630374, 0.8935083176724326, 0.7850276619899128, 0.1829062551614169, 0.01832597413768222, 0.6200934415020365}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.04881195014696338, 0.43287809226571994, 0.3198667796754947, -0.36722613206188404}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.390970918836262}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.37781031128477993, 0.48684960990237325, -0.19453961073751336}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3754405741680623, -0.4006763034970462, -0.25067302948950154}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3367277277455222, 0.32377985626369665, 0.465563453615665, -0.49930923057936727, 0.04545598191520139, 0.3514389562836733, -0.1910054605402125, -0.025587649845455807, -0.23125556303712058}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.21079180534686293, 0.32013623870022867, 0.47762806716952166}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.35516791027486483, 0.428533175998973, 0.28869489750071586, 0.4887954042057827, -0.39140503165866336, -0.2017097792974889}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.12037524640496922, 0.33806730979903}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.013336073710698115, -0.2405919743306315}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.30112189522861}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.3941482691039273, 0.6058517308960727, 0.3941482691039273, 0.6058517308960727, 0.3941482691039273, 0.6058517308960727}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.18341371164829612, 0.2599879333975508, -0.6457272474988196, -0.886156035118064, -0.32078183685192685, 0.9860897172234648, 0.41560129793230605, 0.32155005078709453, 0.7133139340271635, -0.9076620089824161, -0.3538397396173947, -0.023506359320266013}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.43035476581397525, 0.07398527713018488, 0.4127460937375492, 0.05249715783406428}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.1913542169773741}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.3426669069909708, 0.13423140343109663}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.02855967130323256, 0.4013484603106231}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.479951538210875, 0.520048461789125, 0.48602066096616847, 0.5139793390338315, 0.4832763949564446, 0.5167236050435554}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.5889863656760703, 0.361271344268868, -0.697788138843672, 0.5708666227120625, -0.8025798876516681, 0.01111484892779524, -0.16061576152672807, -0.6342184061602736, 0.20258760917073038, 0.13084452306212624, -0.5012843877043336, 0.2506994809315868}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.43157414404512784, -0.22454170943245044, 0.06342467251982287, -0.4903095245043815, 0.3834441389741482, 0.1043669041208739, 0.21147014754742122, -0.3241662643637835}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.36246497697687696, 0.48959807313688664}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.4005622987228885, 0.08448867560587958, 0.4825092464366515, -0.06945988848585605, -0.1566000982618777, 0.161680936884261, 0.2625865332641757, 0.2036776172194643}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.38543713430092885, -0.35769200777582466, -0.10971227523253302, 0.37585815082815444}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.30392557083902483, -0.254394070844572, -0.29560305015381594, 0.2724026794865685, -0.17963699697528623, -0.38270223617820986, -0.4176954621850212, 0.10630726156877224}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4982194333530723, -0.3555542504763711}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.5763783334847762, 0.4236216665152238, 0.5763783334847762, 0.4236216665152238, 0.5763783334847762, 0.4236216665152238}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.9025061992889161, 0.19328609590335133, -0.7068078868075021, -0.3621298243628557, 0.42084782722516256, -0.4359057875902117, 0.0510248453105977, -0.18571126990191988, -0.02830089446402506, 0.1028917603887507, -0.5169396393484207, 0.05819977217125105}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.39623022606222136, -0.22362441324265359, 0.39238252816654173, 0.41075147016444546, 0.3584881327497472, -0.4586938087971061, -0.009994899545871516, 0.32295889813028067, -0.3114604696139205, -0.07820247854247964, -0.006217888590797749, -0.25277227331585594, -0.0009898377430997973, 0.17177816676614144, -0.019448091010139335, 0.38356038284184857}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4141512740493073, -0.18463803457651495, -0.34086341502595885, 0.2802846789122756}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.17649372502513372, -0.4525440122393084, 0.48670321184799503, -0.3752565756084566}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.34901352058938206}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.16714150009971906, -0.3984125959843686, 0.3361921482610458}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.43702731155633834, 0.12670841565912072, -0.44506454008044927}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.3213172085573269, 0.35622316338050086, 0.19385883726860853, -0.20313945154792545, -0.43406461029282295, -0.41020105308930066}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.14542575939212932, -0.12401127658208566}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.2956944857577806, 0.7043055142422194, 0.2956944857577806, 0.7043055142422194, 0.2956944857577806, 0.7043055142422194}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.1471986410663002, 0.3223900482951627, -0.3871115288361715, 0.36128426236680067, 0.17107938924217025, -0.24843227878732677, -0.9462475768333407, -0.6683601078288006, -0.15689088963151732, 0.3863596359317958, -0.9854117874396386, -0.6637648951516011}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.18758953872206663, 0.4031294408504744, -0.32567279628283763, -0.11954330983592354, 0.12677376887127456, -0.42206487014544825, 0.09874196501566324, -0.41852061901647253, 0.39190177556621275, 0.15907084899155732, 0.20691214395415625, -0.12773171660018234}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4575197227955804, 0.447561940405506, -0.4065386452877515}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.24607685990571848, 0.0024526362601802187, -0.10779852839049442}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.338725911779562}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.22283532410809792, 0.2726751916577762}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3294139943201878, -0.2427847336346669}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.33789088994211103, 0.12445789020178899, -0.2624820420736501, 0.05542212362233356, 0.019676173509535433, 0.034430815186815455, -0.49513807708947266, 0.4046762717083787}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.10658070879024029, 0.31127678024225003, 0.4747582119264041, 0.4585288208786996}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.23212740101520912, 0.058839586857196036, -0.2574521687379293, -0.031180606818376866, 0.05413802620898289, 0.3864349985709006, 0.4894716275639317, 0.3006362872396381}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.165470630910315, 0.1699389639395682}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.3457159519052604, 0.364555059721324, 0.28972898837341554, 0.3522618047481353, 0.3598291648748646, 0.2879090303770002, 0.34865451981768697, 0.36242979733730957, 0.28891568284500346}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.29454769049233276, 0.8065652895247644, 0.5948828253014375, 0.8158491056199522, 0.11992377814439581, -0.41295101908759513, 0.387023655629688, 0.22688293072217514, 0.5450628801887412, 0.3676549321265743, 0.05948976029266695, 0.5979464477793135}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.39396846108649985, -0.10879062053843258, 0.23876890400199857, -0.15217534922372355, 0.4370989064401787, -0.2147672487713873, -0.4771129228541481, -0.3201877102341145}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.05533081951104846, -0.06033720884895888}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.38780592699228167, -0.19836373637229654, 0.05203608566930362, -0.4746646708015988, 0.12326232212533539, 0.0967495819238593}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3380263350878031, 0.39108644096119427, 0.16135480863483675}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.39166002470554206, 0.426804499619415, 0.18153547567504288, 0.3866151830832698, 0.43161446728903546, 0.18177034962769467, 0.3724530655682878, 0.44522954287732514, 0.18231739155438703}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.7997409257340817, -0.44762979727419894, -0.242671689953728, 0.928593391398306, 0.8153418593122863, -0.747231297800145, 0.5987708887089076, 0.6748855841074206, -0.48970610265843506, -0.7973383303213857, 0.7466099257519838, 0.41822260443121984}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.3448866203061157, 0.0957679295615591, -0.26076825784115076, -0.371417288557521, -0.29815673087811756, 0.14576677103307423, 0.2126943890352042, -0.08519206291767811}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3405674703585081, 0.4764419091925477}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.4159930059149679, -0.3070408377275513, 0.09411146353830957, -0.24192414174658095, -0.09798589100191168, 0.019692304548270756, -0.26778273588755286, 0.08588342334805577}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.36931667548972624, 0.010799412093334015, -0.12758159517555556, 0.3616235807742695}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.01146500816374696, -0.10600370378372459, -0.054384554810949615, -0.3650900988656973, -0.38086722904018677, -0.4912321147830767, 0.25802074680033094, 0.1440085995993846, -0.30637828237212783, -0.33759608754187764, 0.26226811085199364, -0.3403649485410726}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.45982608107510103, 0.49172305947658257, -0.21288927452760686}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.34554522072331534, 0.44799897891257395, 0.20645580036411065, 0.3517066030839652, 0.44757679178428433, 0.20071660513175038, 0.3422199754512913, 0.44737538981121233, 0.2104046347374963}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.7006036347244877, 0.3947896193189684, 0.33370704485784053, -0.3352216035194193, 0.24835200999047502, 0.49485797556152233, -0.7746682272008463, 0.7785084369369848, 0.45857785814393237, -0.8576493071622493, -0.2610738037827125, -0.6515532192383278}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.4929041443878971, 0.2604931529046436, -0.49853586135617256, -0.47968811551503376, 0.2990868438952211, -0.05872001025067264, -0.4965311128447555, -0.08918495560758, 0.17094034102411604, 0.3575271268793798, -0.48949401967377415, 0.46756581036974365}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.07053116441585972, 0.29237293207928927, 0.1514651382272183}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.48462706442885606, 0.2163853731479366, 0.09104048052590863, 0.12287017274391321, -0.21041783383554724, 0.41813351112663943}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.29533776389941424, 0.4417154527212025}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.15502122122949036, -0.012972316712451248, -0.38458119948513936, 0.03150844539041364, -0.29318174694396393, 0.3031661246557463, -0.07660845634714608, 0.28263659620684023}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.15489958230378187, -0.20019037757633595, 0.060053460167712625, 0.23680534585836766}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.2414764037148628, -0.13068986496164214, -0.004457966987693074, 0.10676453711586298, 0.4976533062262293, -0.1838812341411996, 0.13409946709679876, -0.296548078517441, -0.064392881383877, 0.49515655646972645, -0.04041798721526302, -0.4731442578623938}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.08515291970162053, 0.30164718655864975, -0.2732725246653269}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.24439434053470707, 0.3733474829844204, 0.3822581764808724, 0.24439434053470707, 0.3733474829844204, 0.3822581764808724, 0.24439434053470707, 0.3733474829844204, 0.3822581764808724}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.9428188005528291, -0.7378105632152863, 0.11314619736001785, -0.9653982082956738, -0.45576820426045717, -0.0520784712202329, 0.5599514794089784, -0.3940597491905835, 0.8303039666212002, 0.02939667549033964, 0.6432277212515998, 0.7581000450049138}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.3575516546631702, 0.13570451757667634, -0.3130078857633163, -0.4572933534607154, 0.49926350345721204, -0.11796401560243486, -0.13206478163488544, -0.036803677304119375, 0.10462597062853962, 0.009358323294726634, -0.32118435958563574, 0.3035899060904441}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.44646842762935457, 0.19279328991473876, -0.03486629122903584}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.027168558390127107, 0.11785701739593635, -0.04977355542579165, -0.2474714262056561, 0.07428820832728489, 0.012345199950660413}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4141481284399017, -0.11337009569354517}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.28715568045285855, -0.37686958900003753, 0.4623149253748251, 0.28275880159269473, 0.2507459639586217, 0.24908765471724092, 0.18415390705075085, -0.20773249456331}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1547147039639709, 0.03953389918420158, -0.3023125570266998, -0.13024939889122833}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.03660269984394093, -0.40910717246100337, 0.09346472774924042, -0.06593260735621853}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3281861534558468}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.09086269580212292, -0.16303933050642994, 0.03597816616194949}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.028386967220739745, 0.4521134725136561, 0.47570013174135484}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.21373246460012418, 0.306216258402999, 0.2316112980539085, 0.24843997894296824, 0.18561987773331107, 0.4059553826949597, 0.2430983941229221, 0.16532634544880714, 0.2083753987004369, 0.3148011581879883, 0.22828728604770032, 0.24853615706387452}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.16349344116778552, 0.7390121277925767, -0.2966764625383127, 0.47576260391792546, -0.6507521819014987, 0.7672014099663405, 0.4916578827937652, -0.9683440981728617, 0.6670602207992902, 0.18891491543220917, 0.15399341800710697, 0.06220709096148669}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.28573644242586127, -0.4953914631962152, 0.34471978838632855, 0.4852753751901835, -0.27639842933629555, 0.00983435149761791, -0.016043225502517244, -0.4643126644265797, 0.4998355265868223, -0.296464502859504, -0.16067348342791465, -0.20444072160328586}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.02725773523978403, 0.2749364036897679, 0.019220052186742387}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.36424765507957346, -0.04750813800099396, -0.15684762587138357, -0.10122942520186351, 0.4859969406732577, -0.004219060633859906, 0.14798622567437525, 0.1914223318814815, -0.3708696604296765, -0.32562213617201907, -0.3833400893065666, -0.14524792926364039}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.06350817308537093, 0.23670564024627194, -0.009753843915800253, 0.12432950954515853}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2427076675026225, 0.2663480799762555, 0.24867040058759698, 0.2422738519335251, 0.2410464526357705, 0.26887245254326675, 0.24984925492211446, 0.24023183989884836, 0.2500141894729036, 0.2552943695388017, 0.24335724757223887, 0.25133419341605584}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.917554122621129, -0.5014205346904586, 0.18343572124170393, 0.21531699721498865, -0.33262704312727887, -0.9987960559190387, -0.6375203268920657, -0.5621175977169983, 0.15283813521946654, 0.5459683653088474, -0.41706188142702305, 0.27759685147977087}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.37248622214777916, 0.15829460321237743, 0.08312730917140132, 0.2755139422914853, 0.1808154534007098, 0.032187691765277915, -0.11370163960553448, 0.32746131498627984}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4684587462242569, 0.2559580858062728}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.30791379566637656, -0.07696068667621525, 0.09980716938027501, 0.4495728008574488}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4254869154098603, 0.04006169636395274}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.07808144112388982, 0.07660844788273014, 0.39542162062174946, -0.37632151199090325, 0.20149409066276447, -0.26315198902818104, -0.4000883580408945, 0.04442275941119844}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3420371270481132, -0.33779181976738615, -0.33661834480584973, -0.14184090772961977}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.17169935796458444, 0.34140387790070514, 0.25365933993175804, 0.23323742420295243, 0.17486595321528292, 0.3396460859465044, 0.251660274098324, 0.23382768673988866, 0.17220626780782666, 0.3411221936246749, 0.25333785486882465, 0.23333368369867388}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.7420016325044454, -0.4514424674132902, 0.6143949234937065, 0.9914254064244896, 0.8842938283948643, -0.1666631386740245, -0.5772406848758644, -0.8882809920480443, 0.09808721178744251, -0.6613662792504422, -0.8001131591530399, 0.9140427378949447}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3672331555582573, -0.02641449892889902, -0.3511180702625386, 0.21006806219913965, -0.0318678417456697, 0.0706452493478893, 0.010910996579012622, -0.23034704326429456, -0.2283526659631835, 0.433264003728153, 0.3060087350048166, -0.43650451289761416, -0.14145918100325872, -0.08888401746632146, -0.11080411021576475, -0.07121042383765308}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.24966676452478398, 0.31434931298906554, -0.48473694012797186, 0.0902994485887827}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.07188847717649904, -0.3582463052490643, 0.2650132815734264, -0.38712458814788386}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3016627872850006}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.3580585355347651, 0.35169637464846704, 0.026629884619614907}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.31680527584063656, 0.42120151277135565, 0.09950295644319973}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.2773311566365868, -0.10211840262384986, 0.07930204873307545, -0.29118054966125684, 0.3963404166703397, -0.2713247768725766, -0.10101656568692563, 0.4667394832037167, -0.46974673832931013, 0.35704513540254923, 0.1928278929394489, 0.3715742378162714}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.018136969528895652, 0.4918878632698521, 0.1803867628718674, 0.145262175403723}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 3, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.13674033124513882, 0.1781773624470309, 0.27559966790508167, 0.40948263840274857, 0.13674033124513882, 0.1781773624470309, 0.27559966790508167, 0.40948263840274857, 0.13674033124513882, 0.1781773624470309, 0.27559966790508167, 0.40948263840274857}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.3100414369570397, 0.55918200872566, 0.42741761286026314, 0.8939712489023455, -0.24396840597885405, -0.5878214086032363, -0.07738310874824794, -0.540771629594089, -0.3646104389654876, -0.700088493267597, -0.6373977187416964, 0.478540647677808}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.41649707488647836, 0.24210605860912748, 0.09212044100144134, 0.2519780882479188, -0.28053985466099285, 0.3198135937131307, 0.48294504610931177, 0.24244085633678414, 0.4115036252061871, -0.31916504918868593, 0.10992279713846442, -0.4943336039032632}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3286664269091606, 0.18490389971888765, -0.17763659468713877}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.1460795236154161, 0.16520255039254406, -0.4616904226058768}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.19759061378196696}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.15407967062789807}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.24925581030653765}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.22287605810485855, 0.4026547657122086}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.37770218025330893, 0.3233066938058783}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.44195321870258875, -0.4429759033723669, -0.1530440907249927, 0.07714079637782234, -0.23578908963936251, -0.16392763583029613, -0.16615219140599513, 0.28804942315674564}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3943451509177218, -0.4751790575694669, 0.09897415572415036, 0.2732593171924781}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.46009837594932596, 0.459891777324507, 0.45989614063760637, 0.459860480279755}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.6961508204318383, -0.9375254243225626, -0.9324274847618059, -0.9740919869018612}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.06415032193986347}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.4550678924076613}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.053713829419032466}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.18199128877925763}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.45486918185767616, 0.4588077109886696, 0.45434561572536214, 0.4530694292399673}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.20741980531288018, 0.7099081113213652, -0.3294607979019659, -0.6270334891414515}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.33563339767907907, 0.26582013140125826, 0.13596505849678275}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4733389451359725, -0.4471215904989043, -0.34218107931317954}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.23009486261183631, 0.44279493813681226, 0.36979378936320817, 0.24288302197597622, -0.21502814883344368, -0.21709479651222774}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3823874093981364, 0.45427708135178213}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.46793614121187177, -0.2122549303795025}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.056602310532829714}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.34427675729583107, 0.34427675729583107, 0.34427675729583107, 0.34427675729583107}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.21961365793567866, -0.49420213261597024, 0.061858765827880635, 0.0663808452267105}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.005449486006652182, 0.47490469830021975}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.031911843786901484, 0.21847579090245983}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.2470593868190376, -0.08548278864584669, -0.2632552775812601, -0.24412396362764266}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4405224820357403, -0.09647942720945402}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3692577052925945, -0.4749498041372251, 0.1207524654858656, -0.29431328520218336, 0.11697856210317381, 0.20056655662156075, 0.2106276900110401, 0.20727285272366724}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.37798290416825553, 0.31188320682790294, -0.18201026145655452, 0.08106936078426807}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.35374657986336666, -0.24404931769438665, -0.1835670197827275, -0.10681140812492507}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.42580877686144836}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4157071316834169, 0.4157071316834169, 0.4157071316834169, 0.4157071316834169}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.32918072749449845, -0.9581614654904722, 0.45834424186442413, -0.6868185929563573}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4216819974388619, -0.28513015208598225, -0.21152421338681038, 0.025914210001902305}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.24617815096022022, -0.12515812743604093, 0.2700810492828932, 0.09823370715979951}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2333367119001727, 0.35530950186009747, -0.31769495314541696, -0.08898165698198246}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.32449052381276333}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.1478708660722925, -0.2775026684968418}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.08676637702214707, 0.4718296777220432}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.07844493971271371, -0.4666459346809172, 0.47971604202713136, -0.29381750431462617, 0.1442111212867051, 0.3259765899074112}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2760222484552616, 0.32036505498890844, 0.42345319008942417}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.07072611176116428, 0.3141167701405505, -0.3223487295991906}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2114282166999557}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5774612235687226, 0.42253877643127746, 0.5447149266313636, 0.45528507336863644, 0.5986637649697405, 0.4013362350302595, 0.5985870397380003, 0.4014129602619998}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.37079999709400746, -0.47127639815456157, 0.980146883318556, 0.9377411377478826}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.4068748734504569, 0.2732021569575994}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.36576223231946625, -0.07355344343693382}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.1597170646739826, 0.31056744087567667, 0.22629800219155616, 0.28300457590094696}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4059421833621185, 0.011395029344367757}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.386924112252726, 0.613075887747274, 0.39248460717859524, 0.6075153928214048, 0.38988623573392367, 0.6101137642660763, 0.39921556968442123, 0.6007844303155787}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.8367959964515643, 0.392432218579571, 0.20987661501258925, 0.8633772476824404}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.28785560263593657, -0.39826627462672437, 0.38506144652483987, 0.36898696295947353}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.36017195751868314, -0.18449964290700804, -0.03179777276615248, 0.1746849191103873}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.03974167589388866, 0.32755051323319473, 0.17374963883723915, -0.32530248644173787, 0.1555370365867096, -0.3315683941964449, -0.014035021969958206, -0.28232449910374025, 0.13845296579001198, 0.21696430050478233, 0.4925915676197984, -0.38933754311653146, 0.079560846497712, -0.19276606232712246, 0.342545929557034, -0.12004537568018625}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.2047518744011363, 0.4011750321689538, -0.11163320653740649, 0.19941746309387276}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.24687370971958222, -0.3600356163127082, 0.4210982339508377, -0.15705955785363457, -0.10853028825921252, 0.23493356941303978, -0.09558145156400855, -0.09505717997316754}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.18152981361292064, 0.42186478935132177}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.4679809964808506, 0.5320190035191493, 0.4679809964808506, 0.5320190035191493, 0.4679809964808506, 0.5320190035191493, 0.4679809964808506, 0.5320190035191493}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.23240209369115905, -0.39682258932957515, 0.8153666465913019, 0.03021642372532618}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.3129686763832493, 0.06162685586768213}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2688681946939949, -0.12090421600122825}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.15286360971936108, 0.09919644013828866, 0.3521235692621618, 0.01871662975412436, -0.3400129561559918, 0.24764045906241594}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.24877391940187044, -0.323837320779514, 0.11292429995849984}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.4855344113223965, 0.3360608033972716, -0.03710182424795416, -0.481252929455418, -0.4267198822977959, -0.335238825608552}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3126171888926834, -0.1795269283817167}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.3933030143840047, 0.3597437428329068, -0.3696860764029696, 0.36046030237139204}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.35090792989767317, 0.4791594502189376}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.49453760211846365, 0.5054623978815365, 0.49453760211846365, 0.5054623978815365, 0.49453760211846365, 0.5054623978815365, 0.49453760211846365, 0.5054623978815365}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.08697294310537806, -0.627740066703294, 0.13751129177171495, 0.9402761835703903}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.23081677710998316}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3984510449094365}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.21527351432056008, -0.129092683787015, -0.2559675684180386}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.2613221622561167, 0.17461848257731893, 0.4830675630790886}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.2790927743454691, 0.13776271404862006, -0.3787594308219068, -0.03466019333351833, -0.08484246866443068, -0.4265581451891487, -0.3892333471654865, -0.47046197838230774, 0.21393067165640867, 0.3270858774686016, -0.11016939011241556, 0.18097386032786145}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3562726117423408, -0.4857072421380031, 0.13993322012111964, -0.031824250533752596}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.4851406468098657, -0.38821817508478706, -0.0645056741908252, -0.07194257593636944, 0.04864713497238071, 0.4516263614509881, -0.12597140372171856, -0.27907858431983334, 0.27200292177825913, -0.4659450813239272, 0.4736758193425623, -0.4032966877971559, 0.2750624879412005, 0.390610640184461, 0.031025946959763684, -0.46302967244135484}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3063973929461592, 0.07366399113333266, -0.026546965082804963, -0.007103511789254946}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.27422417099157825, 0.3627515139182035, 0.10706341818297294, 0.04265168660578833, 0.09264091835614974, 0.32930755816840285, 0.4978492665595521, -0.15029989140670652}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.023960285729627162, -0.0010336518201295997}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3990010482777788, 0.30814067828639186, 0.2928582734358293, 0.36174199067410967, 0.30919967306779805, 0.32905833625809233, 0.3797846645187166, 0.30898795379508376, 0.3112273816861996, 0.35839079196082363, 0.309174962784463, 0.3324342452547134}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.7555562048947198, -0.38541455251519374, 0.1696238183005343, -0.48917681059882323}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.26735209184114805, -0.23770792207844404}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.30553606729556804, 0.46367860113075554}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.09982347124149848, -0.18439482859674472, -0.13103946820339307, -0.06994433675832212, -0.004725709039387849, 0.48918675362273145}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.042868108518935744, -0.21661730756144404, -0.49042990980919776}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3021338329590658, 0.265030147372142, 0.4328360196687921, 0.3021338329590658, 0.265030147372142, 0.4328360196687921, 0.3021338329590658, 0.265030147372142, 0.4328360196687921, 0.3021338329590658, 0.265030147372142, 0.4328360196687921}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.10486938511355026, 0.7761030658598338, 0.43118797048190993, -0.4477482652929732}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.12823741627634444, -0.13794901499970758}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.481433892628495, -0.25421372435147427}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.3602291555585453, 0.3689116767291335}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.11087987597577575}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.2528766575568768, -0.37315101314674937, 0.3769137892902954}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1467805384517067, -0.2644710243408176, 0.142877249019416}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3064171113453563, 0.3323487904621425, 0.3612340981925013, 0.3051588443034699, 0.33457916129234005, 0.36026199440419, 0.30642589567972006, 0.33233323438807416, 0.3612408699322058, 0.30551340684534445, 0.33395024737677986, 0.3605363457778757}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.7232907289469019, 0.7287616297595512, -0.9631739961024939, 0.3197991012042076}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.1790668044182634, 0.2614742451117833}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.23694211720860925, 0.31305718269550953}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.2693701955579887, 0.022486431785149752, -0.06868292505547202, -0.47229716121483967, 0.01214241681887418, -0.05629516392159062}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.1362291020527322, 0.08149087002960487, 0.26185950474397623}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.288921650109377, -0.11392275469755098, -0.20748982802545712}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.21984794248913964}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.2105618730392429, -0.4028176111569879, 0.12993036682838566}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.07249426679806903, 0.10344605338949009, 0.10453375653970265}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4091289964564927, 0.21053798034760982, 0.38033302319589757, 0.4091289964564927, 0.21053798034760982, 0.38033302319589757, 0.4091289964564927, 0.21053798034760982, 0.38033302319589757, 0.4091289964564927, 0.21053798034760982, 0.38033302319589757}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.6084330834077327, -0.12409820908143154, 0.6078157523400622, 0.7990980072241021}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.3180181046152415, -0.24116751067959574, -0.00673853139493974}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.11230241902169025, -0.4148940810170564, 0.3609118459797448}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.05134711159137295, 0.41971317087064053, 0.44295358663336204, -0.23557339705839642, -0.21950454846129375, -0.0416226996751774, -0.3856543002948444, 0.11178007410514568, -0.1080644307748061, 0.15905374014246598, 0.18078293797077682, -0.33776250037347877}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4577961647922748, -0.2445375253819133, -0.19272969293136255, 0.028639048932376898}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.09182417937806919, 0.4607969866611772, -0.2935712934796352, -0.289503997349042, 0.03851497167709517, -0.19412542543413014, 0.4990617120956413, 0.203223186755348, -0.06860532858034663, 0.11680095326811446, -0.28625587175321077, 0.22181883360796484, 0.29143396924057996, 0.028712050137576273, -0.15414463706645942, -0.318925027516029}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3539507247676814, -0.485031032832827, -0.2618796520027439, -0.055033053804605214}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.07296226915943815, 0.44255532418674914, -0.3308356450369041, 0.27499059828913386, 0.13745370823462466, 0.09524000384138676, 0.14334043033014965, 0.3799523662289508, -0.3933062695256174, -0.40294046205301104, 0.23470319824012364, 0.21444091470496018, -0.36163236342993765, 0.45239954073990707, -0.19308720649839162, 0.1513516112900083}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.10099816051053012, -0.03359732004741811, 0.10174332361288807, 0.3502121743093468}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.2989606951180568, -0.33954451124622276, 0.06520702844456072, -0.2520921171660495, -0.08607416266323586, 0.2746541991716327, -0.4728825156944264, 0.37885625368831055, -0.39990624921192075, 0.24991339267449675, -0.39530793450904356, 0.4178182231905486}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4838934630035131, -0.3299218244809251, 0.25317399366985416}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.2546114251764164, 0.2664168984447294, 0.23105393235277136, 0.24791774402608288, 0.2546114251764164, 0.2664168984447294, 0.23105393235277136, 0.24791774402608288, 0.25351933884470956, 0.26635713166414593, 0.23159418963778935, 0.24852933985335504, 0.2546114251764164, 0.2664168984447294, 0.23105393235277136, 0.24791774402608288}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.055554698326475194, -0.1618264062270478, -0.9011074377620414, 0.31738830107503957}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.28710835821433056, -0.15667390897042854}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.483394479308874, -0.13093464515928577}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.0998248033058381, -0.4669073109167172, -0.24127229497552516, -0.06925567448426173, -0.07768143998115395, 0.18059954211476648, 0.056804199740139616, 0.19313121543980838}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.07835807380067383, 0.1236818829334646, -0.01872932966159857, 0.05171652751237166}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.31115670150001223, 0.19834853951745743, 0.2785255067779559, 0.21196925220457452, 0.3056157071245832, 0.2015505981657745, 0.2772398391078175, 0.21559385560182487, 0.318201967953951, 0.1943149496734161, 0.2800709989904242, 0.20741208338220865, 0.30634472838809196, 0.2011278043880812, 0.27741255022213546, 0.2151149170016915}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.2845930343777032, -0.678203760226143, 0.21270848046768176, -0.626284815822141}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.4748828615323588}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.18742733356021857}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.1394454858926638, 0.09182645639180487, 0.41803949690465725}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.11580137970896909, 0.44466523473928965, -0.027314470039616512}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.16175784192679088, -0.48947305814202857, 0.1415255589256872, -0.4788941076235622, -0.0051207786505138575, 0.47003274398937456, -0.011043534355596574, 0.39232208852385175, 0.11857050200353902, -0.22151393647763096, 0.16826404546647455, 0.44398245169786166}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.39263668893890524, -0.32268177632542905, -0.13390513266154935, -0.3356990492563612}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.3411622202837145, 0.2172487350325395, 0.2070400868597848, 0.23454895782396115, 0.3420641571633157, 0.21576551785838946, 0.2073727335331344, 0.23479759144516033, 0.34107176633837594, 0.2173976884240954, 0.20700664751345296, 0.23452389772407567, 0.3415164106699815, 0.2166658354923238, 0.20717088733147762, 0.23464686650621702}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.12926141310722405, 0.854642550870697, -0.1963005891780567, 0.13339938901360027}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.3823663440736079, 0.1345681965004969}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.24732111794549672, 0.3203479093957785}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.11612169335715705, 0.15739128746408249, 0.02436931080589866, 0.09029213387165091, 0.16424158556850244, 0.06629161494809821}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1944198669068683, 0.06465108826611443, 0.4667212233787421}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.45342873556305907, 0.49697762675081336, 0.360620998241829}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.2043030084418037}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.3824027809053706, 0.4043542637785078, -0.2966187762602761, -0.2513659953305092}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4245671337310335, -0.05675760770681493, -0.07815061367762244, 0.04487520139762846}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.2077060107452912, 0.1822052250314303, 0.29713333913056544, 0.3129554250927131, 0.20486464583839128, 0.1824457178635811, 0.3001691520534858, 0.3125204842445418, 0.2069190049404481, 0.18227289036090852, 0.29797061810048864, 0.3128374865981547, 0.2014418603907605, 0.182721218581999, 0.30387439875423705, 0.3119625222730034}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.9942441685123669, 0.4641736848240303, 0.8478811690183932, -0.18054158466574277}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.2979704748166452}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3629643742667359}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.000594195261587438, -0.3798126000169517, 0.15419392443874425}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.11333179318771858, 0.3714311984171871, 0.4172063641463696}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.39798849807656045, 0.0007336281066194772, -0.3610918783406847, 0.4390582537209957, -0.40112850858874927, 0.4048043753374544, -0.33482457624707407, -0.16350574495632175, 0.3254216862625351, 0.17525176899584793, 0.36251545861339485, 0.19079163015727563}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.31635822498462274, 0.49602806496326557, 0.459806656793624, -0.28658763194610204}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.4301317239479745, -0.3272414081539301, 0.018041946698259204, -0.28162466714869416, 0.2298245302097719, -0.43160741129743896, -0.39776218161014665, 0.07383725879583058, 0.44898264556763723, -0.2596153217058479, 0.17230871558178418, -0.06543265922931951, -0.3061470784258028, 0.469757751333554, 0.4562710788804013, 0.002598251043701927}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2032172942726601, 0.4881713467383082, -0.4053561414340675, 0.4144750263691228}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.2834146830170464, -0.35700894829683827, -0.15079226258447265, -0.48200173082191233, 0.23968521917247532, -0.33180965261564965, -0.2176888832068471, 0.10496431646271953, -0.32332286165818025, -0.42828073584159965, 0.06602945989829156, 0.3502548937459269, 0.349325457564743, -0.10040485679512501, -0.09447898603116778, 0.20897927198521737}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2538013724528849, -0.3848062703565741, -0.09923585079055741, 0.047812175741032026}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.573393241678147, 0.5487622442913328, 0.5728115749314016, 0.5605087798647705}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.7223316017414236, 0.3890854702199309, 0.5129562428033609, 0.09649888999126266, -0.7254254557238307, -0.5516946606471451, -0.0482129745285087, 0.9855840771636781}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.19882813819582623, 0.006909486988420421}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.33677510059219085}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.403980002936691}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.10055311405899181}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.6278842776293065, 0.6278842776293065, 0.6278842776293065, 0.6278842776293065}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.048368795355389294, -0.31332537896746593, -0.20373785384167786, 0.7743744989260588, 0.9442065558968957, 0.7617723822749154, 0.2033912437775809, -0.4516534083378472}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.0759507306428906, -0.12735518953964986}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.49537377755477197}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.306690744892985, -0.2244988633435021, -0.317769393280963, -0.038249332918413814}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2870043341863503, 0.4227544665693048, 0.4792024090268946, -0.05599760644189411}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.1416474883356662, 0.17800161862487307, 0.2562766406781618, 0.2699434470324462}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3657450708167317}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.5846136235536707, 0.5846136235536707, 0.5846136235536707, 0.5846136235536707}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.07052425065493262, 0.3360793037674621, -0.35630608409824505, -0.905990778616516, -0.25293429465054484, -0.6418120853277183, -0.40474839868379164, 0.9676672707212903}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.31368533599986936, 0.11905799769308012}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3155708618025569}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.41521184962853563, -0.2823646623921977}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4280424685926367, 0.25465558148399925}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.10725468308232167, -0.3542673285719855, 0.11969821641848732, -0.16188975240690218}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4012323872693804, -0.25863665730481544}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.43298130976726656, -0.21164151999103897}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3417420417910866}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.430386939424384, 0.43040171665823734, 0.430386939424384, 0.4304377319620418}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.37313055598428857, 0.3900529215881099, -0.6901236216139115, 0.08002243757370398, 0.49048689222502095, -0.591964111301245, -0.9310815062982631, -0.44040716623839726}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.36931139970618454, -0.43314945892717194}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.09120226993999347}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.34079021914281604, -0.24198338309418488}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.37072329869986753, 0.33092009827484037}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.40051380231350764, -0.4700345248479786, 0.44361305130801754, -0.24000429218063513}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4591087224186049, 0.15902366129630108}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.3857669730877593, 0.43098963862369455, 0.4556416600235833, -0.07607298564550558}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.08420820590206213, 0.11090298415953159}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3902904997814931, -0.10575610358913834}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.26918436648531086}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.28198220522801415, 0.7180177947719859, 0.3060211541893425, 0.6939788458106575, 0.29319901052840763, 0.7068009894715923, 0.30312799928819956, 0.6968720007118004}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.5532947321103583, 0.7020460279825822, -0.8856790719222516, -0.4056170257458407, -0.028773416983833178, 0.2883406898568579, -0.9788881514060843, -0.37682477583926777}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.42821996863763656, 0.08011279692190176, 0.24297059184986358, 0.25328325909774874}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.0943330476691655, 0.2717657892467401}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.21316366825348387, 0.024654018182383663, 0.11035948163369047, 0.4473207854862191}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.3660635616846706, 0.3710543747202527}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5841594718072182, 0.4158405281927818, 0.5774090386254973, 0.4225909613745027, 0.5899989922268507, 0.41000100777314935, 0.5880455405853915, 0.41195445941460856}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.7592465829838488, 0.07340389201552666, 0.03027201689512915, -0.29042807224184464, 0.8926828592677793, 0.4994594863938655, -0.8895087763244509, 0.7743981859496092}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.2683513965552534, 0.08864626899637329, 0.08828473352771826, 0.38426545017525204, 0.2326590353448491, 0.21198578402065682}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.15684526964568613, 0.370620409245325, -0.3790750479319549}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2902861624732116, -0.19096382670754553, -0.3463118372045485, 0.028884767668563627, 0.41634279202771096, -0.485735500467649}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.14540011778365192, 0.40289478945500745}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.0932305779273801, -0.11207010403343942, -0.2984754212426277, -0.43243330824425186}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.27372656218712055, 0.1255576732136865}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.43132217766102277, 0.5686778223389772, 0.43146925008337944, 0.5685307499166206, 0.4315847003252462, 0.5684152996747538, 0.4315036410386105, 0.5684963589613895}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.008437534561116067, 0.28427028109469865, -0.18475217303651603, -0.5770712045340145, 0.43351463526439593, -0.5652937072491893, 0.6096711020360248, -0.028339980804934717}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.26241519172196726, -0.06445189573772003, 0.24821718248146563, -0.08723925770410901, 0.10080076100667412, -0.11282231688604816}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2615420351097679, -0.4024966939641236, 0.36080623507993637}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.47109636504556696, -0.11262421834332159, -0.1659343059581294, 0.3655885683950476, -0.38200034764045954, -0.10556927694684459, -0.38191763664211487, 0.45096039691618106, 0.0690517768055654}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4887067299809299, 0.278784538638442, 0.3440993094989301}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.026009706639086527, -0.15395026005307166, 0.22884506898966972, 0.13065354001137186, -0.2454490392628893, 0.4562325949249172, -0.48094560772802764, -0.010403042122818285, 0.32465976378960726}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4475492900065249, 0.15514674083012758, -0.38361735189872725}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.07831237140656433, -0.09969981737649036, -0.22829731788208563, 0.31957232671706026, -0.31562108617787743, -0.11820481313311892}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.12370613237593497, 0.4691166999372324}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.4245781070777943, 0.5754218929222057, 0.4245781070777943, 0.5754218929222057, 0.4246083411284877, 0.5753916588715122, 0.4245781070777943, 0.5754218929222057}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5674685887384336, -0.5574780980901299, 0.356900734212968, -0.759546755164572, -0.864118411519853, 0.5687792945960211, -0.49834285091091357, 0.40269047773248867}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.3456966770657387, 0.2673018045074371}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3114691112763205}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.061135646698432855, 0.171047242688673, -0.07083094322785555, 0.4411109728763607}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.36904551541502606, 0.15919580977582604, -0.10434301454208905, 0.14607623518800983}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.08560079372479368, 0.1716490189056572, 0.012256713771039096, -0.28357207930020256}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.37130722291521523}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.3643421839125438, -0.18332973307887024, 0.24280435996663763, 0.13733622793851452}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.12256659062760822, -0.348844141621788, -0.1766047764708626, 0.24352880780302366}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){-0.24449192615730964, -0.45287174426887766, 0.40852819002369933, 0.24561652210437768, -0.30405254953466654, 0.043387077045530686, -0.368522217221264, 0.31710366404964196}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.07189627576213509, 0.2115052009039441}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.31208846267220147, 0.3771838702780791, 0.31072766704971944, 0.3129412133390865, 0.37778653671256923, 0.3092722499483444, 0.2973320287490162, 0.3664011449002284, 0.33626682635075544, 0.34072262279456167, 0.3567306393757863, 0.302546737829652}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.9589838364648839, 0.8631326576083402, -0.04944020800134297, 0.8577365529828973, 0.00905879295748857, 0.2118176631005224, 0.8855174349654966, -0.49932845672966386}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.3948081697656952, -0.06912904803831854, 0.11212672830991555, -0.07783140599237726, 0.35884024295204875, -0.3512718083562264, 0.017836798410229338, 0.3975322825812989}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.04374453726208649, -0.42744187579449655, -0.008971975329000403, 0.2814686700622646}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.13756404225877494, -0.22374231784021947, 0.2566580583124549, 0.4785387545534805, 0.08397586141253455, -0.47365073075223085, -0.08660541094541763, 0.3981206386566494, -0.015260276119837934, -0.068842813906552, -0.42633861910940685, -0.04877059983132925}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1560106049518677, 0.08228842627206956, 0.15995292111609405}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.2764215717250862, 0.3015904648313894, 0.42198796344352435, 0.2805535069391945, 0.29063461627281595, 0.42881187678798954, 0.2761758633342075, 0.3022410871754407, 0.4215830494903517, 0.2737876711751137, 0.30855995031309125, 0.41765237851179493}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.8971226869930089, 0.4265958194942927, 0.7817335823617833, 0.9758576959627594, -0.33775162275911264, 0.01302155135583627, -0.6215876733081094, -0.5541397701200119}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.12231534458010629, 0.39828245565733356}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.08546346205311128}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.4266031951818632, 0.15930750637777158, 0.4490331313788445, -0.17416066416140086}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2208534955696535, -0.4035201713354931, -0.29946168325751366, 0.320059395235205}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.22356621004471355, -0.1471996992527529, 0.38443857250652436, -0.3549321346753348, 0.3550670355603862, 0.18012981205086787, -0.07661373860541265, -0.4940923315938609, -0.31430055060001316, -0.16253555373584616, 0.3105555233094711, -0.16237084594092654}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.20418496237627404, -0.16787533924450482, 0.17651955719766754}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.2879778299692804, 0.2618696258466608, 0.4501525441840588, 0.28960102806860055, 0.26131176762428593, 0.44908720430711363, 0.2907364256059163, 0.26092137408827953, 0.44834220030580413, 0.2879778299692804, 0.2618696258466608, 0.4501525441840588}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.44983217479181214, 0.47921056083105573, -0.0024303634836635446, -0.6778616366930779, 0.64794954805097, 0.43097081987566965, -0.3617262895175366, -0.6771522591051267}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.3701599938420187, 0.4331348275689192, 0.2242482411894613, -0.14412625585685757}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.33038066909635777, -0.04769807634641554}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.12664930505122718, -0.2718112508034257, 0.0681216786350658, 0.15899173415870493, -0.13043525586605187, -0.25874968689682354}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.43604643182269576, -0.3793385846516465, 0.42259897886413555}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.29710027122411664, 0.4803758540077875, 0.28941823965071845, 0.31176612547024074, 0.45903672995714817, 0.24424704114123041, -0.34992105356273784, -0.34690674227418883, 0.3122715750259658, 0.032392183854118795, 0.4025577816299052, 0.4168133304421979}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3561273590606807, 0.12462374953513222, 0.44737439634432996, 0.13026498024833488}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.27722999671901205, -0.34625303783364736, -0.4693142636626134, -0.20072088652770304, 0.44390924222589967, 0.17480782044118814, 0.03480480955164178, 0.06917587868756414, 0.2080248987557688, 0.018655892247661954, 0.2563539651955812, 0.20289404531187605}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.45267032518043104, -0.48085991152116425, 0.03998835883043539}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.40002838726817574, 0.38533637628696427, 0.21463523644486004, 0.40002838726817574, 0.38533637628696427, 0.21463523644486004, 0.40002838726817574, 0.38533637628696427, 0.21463523644486004, 0.40002838726817574, 0.38533637628696427, 0.21463523644486004}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.035551612113206676, -0.5916791417426996, 0.45505755532049785, -0.49951659027545303, -0.6302893589390992, 0.28957503678450913, 0.5074878169113044, -0.6270670388173059}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.45611580544857333, 0.0044402554010967155, 0.1346899749687146, 0.2705425262698784, 0.16973026568245264, 0.49968613768182024, -0.2715741459295201, 0.2686655705444948}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3515611028034701, -0.34089142959281926, 0.42103949061681367, -0.12056219344015262}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.18262747536282298, 0.23264245723262855, -0.3267888638585451, -0.2379073021356094, -0.09846612031192226, 0.30094032342787236, 0.23065243715541417, -0.0074356977749875375, 0.44195410684682845, -0.06953097340855563, 0.44259250545816264, -0.08539210794256524}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.07149378281037477, -0.4798706398682615, 0.06596203470881867}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.36960662399558997, -0.2838059467826296, 0.4357050272382632}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.46618282018413315}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.12315167706634278}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3982176183670685}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.023774304383427092, -0.03609763956606504, 0.31527446893194944}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.29700232422297, 0.25958346893419104, -0.3255931758974122}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.3497859922984004, 0.2700189470884849, 0.16886007041692333, 0.2113349901961914, 0.362651492463025, 0.27183287665546113, 0.19429220337382383, 0.17122342750769007, 0.3076094355534571, 0.30180219539250924, 0.15229316398819553, 0.2382952050658382, 0.3731086779665698, 0.2618228897169243, 0.20735938055602263, 0.15770905176048336}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.2312289476332483, 0.5784537758481134, 0.2335117724181921, -0.23253751516547516, -0.8204966322563674, 0.37624466605302587, 0.754257557289497, -0.26136470043933335}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.43176552797006496, -0.4048091744882494, 0.4039237792622715, -0.24226355968572943, 0.08807674027235723, 0.3817356939184201, 0.4183872285368606, -0.017906921474890147}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4683572976614643, 0.46285210867990656, 0.49133960826440315, -0.24666953895330845}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.281201871871014, 0.33091247982372807, -0.15566784676784573, -0.3262306921647259, 0.0031100068409345427, -0.19765445080269084, -0.39779922237192067, 0.45337654994140897, -0.42558201717051214, 0.3969069934221028, -0.4502701713596561, 0.11668308094338797, -0.27674821031934427, -0.4620033031757097, 0.13548495756008372, 0.3740171198742994}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3268083752193871, 0.4652889545691169, -0.21310124081313675, -0.06040212309513682}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.16897290405971283, 0.2823441665927823, 0.18697564929279242, 0.36170728005471237, 0.16386397821664356, 0.28207320813380077, 0.18308913671236055, 0.3709736769371951, 0.16880281115000734, 0.2823373422195636, 0.18684730342061975, 0.3620125432098094, 0.1586090430969964, 0.28164792779127085, 0.1790228311658108, 0.380720197945922}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.25583717082173685, 0.5700960843606402, -0.006203887998215363, -0.32953488041027335, -0.12482852713481707, 0.27457131315008443, 0.7693946722827514, -0.4264243298380106}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.08392297782426827, -0.4386418511257856, 0.29788933590456135, -0.005263185267277759, 0.34787572942278955, 0.14625206371307542}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.10353614643062259, 0.3605094383500649, -0.49792760946614945}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.25247480853453497, -0.4836885186859655, 0.3266477229085768, 0.16369982218668877, 0.3419771471670605, -0.045424746890912804, 0.4669241289760949, 0.39337581149229883, -0.139243724816131, 0.056808058854913024, 0.3275446029202209, -0.4253105180986715}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4927596865687537, -0.361458114770594, -0.12215066647820128, -0.3520488517746374}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3913737958741136, 0.24921935966512432, -0.48038995806598095, -0.20787697983483666, -0.06578690038136126, -0.31835116540646413, -0.2604301550344291, -0.012766659921917056, 0.3106582889748276, 0.4189045681621911, -0.4086780958412666, -0.08503975086650617, 0.2829253598341276, -0.2890098249685046, -0.06624864837904343, -0.27402492425780167}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.3150252705861608, 0.19836313405908657, -0.21378525095730205, 0.44607162443675563}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.21076187042847694, 0.28781957914587997, 0.22420829493818056, 0.2772102554874624, 0.21076187042847694, 0.28781957914587997, 0.22420829493818056, 0.2772102554874624, 0.21076187042847694, 0.28781957914587997, 0.22420829493818056, 0.2772102554874624, 0.21076187042847694, 0.28781957914587997, 0.22420829493818056, 0.2772102554874624}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.10293776072694949, 0.8672657130718258, -0.8677816625805321, 0.1379788021904753, 0.663795675847483, -0.7404601498042198, 0.8277296769459166, 0.33295368831300776}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.20935077677761849, 0.3809707405099224, -0.10051374465260643, 0.14731210232347447, 0.23366232712560597, 0.0789480221564891, -0.3908336864914883, -0.21422946649579355}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.29684990909425457, -0.1814661532079921, -0.17141356956369647, 0.21220603990638054}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.2548525881261958, -0.35337418198863324, -0.054975863727590446, 0.12436187979453472}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4773779539909512}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.17753342309848064, 0.05545390125514027, 0.4422875981458124, -0.15156416849166598}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4494086545345328, -0.22668445766296075, 0.03546400022870466, 0.05991935098995538}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.15522611533469854, -0.23198511101853037, -0.41981507903310455, -0.41143337914613276, -0.45805905669448843, 0.2395946278873079, -0.05209774769614772, -0.05185595616304883, -0.4486323290801243, -0.2859004776517021, -0.28372862420998246, -0.06705769093184166, 0.18062147242615645, -0.17703205645274311, 0.28264176423349263, 0.46353908437464286}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.2375783201088686, 0.03944020909468826, -0.20119267000063212, -0.04087068855404441}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.35018081761915715, 0.22763318642379005, 0.2197435061425769, 0.20244248981447605, 0.35018081761915715, 0.22763318642379005, 0.2197435061425769, 0.20244248981447605, 0.35018081761915715, 0.22763318642379005, 0.2197435061425769, 0.20244248981447605, 0.35018081761915715, 0.22763318642379005, 0.2197435061425769, 0.20244248981447605}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.7173518264130556, -0.8679608993746533, -0.5623647881487848, -0.7830493905942177, 0.532754868651169, -0.728811286100643, 0.45501128481505493, 0.13692327501801738}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.49966110968281197, -0.0990619816136229, 0.021804925014707877, -0.2296240593751121, -0.0035853654217983255, 0.3900186995564404, -0.3789092443305079, 0.10472228549516072}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1338038565871883, 0.4249636293239748, -0.06344386858173556, -0.11036367737343444}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.18613929226191128, -0.11064560652135547, -0.028909135783605322, 0.45015443432722224, -0.03994351986202627, 0.23926776302176678, -0.20484975004634953, 0.17301020067939077, 0.22042295475481744, 0.018515206096947012, 0.02167962917406585, 0.09931046809885957}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.30871840445837173, 0.43187203061146107, 0.01964725460404082}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.4754082543239513, -0.2323548974086168, -0.05889277368705281, -0.2970164042554396, 0.35887709150507596, -0.00938674362938463, 0.25054089669577495, 0.010887679859571286, -0.06811300208913884}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2242595156558853, -0.27595600722378244, 0.41607798055345757}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.1998900275677684, 0.09331891750104115, -0.015336640244122068, -0.22202553697595073, 0.12307939460577433, -0.49138052476308847}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.04707300050258012, -0.3150020158410318}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.46078756441223057, -0.41005101891571694, 0.25838202090110407, 0.4327376369392406, 0.4183435372488131, 0.41310831594444375, -0.32419405578267, 0.40412313260152755}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.27962978974242636, -0.1510843511862363, -0.18635886809288105, -0.2683640078124425}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4799807403455187, 0.4868211244158053, 0.4829995028342176, 0.48413073319215955}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.6979551502415169, -0.875374096462342, -0.4021893452872549, -0.932194658043382, 0.37874848159624785, -0.11452359047080263, -0.0266714564361501, -0.26809696792403903, -0.4333924730269947, -0.15045317103009026, 0.7230661182750278, -0.09504565260963038}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.3834769606800076, 0.059337347385949646, 0.03233458208762152, 0.4796750438345212, 0.27826055668524974, 0.2623108227353368}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.36879417109755175, -0.4436891199290868}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.03864348563662823, -0.0542505740732967}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.08151866551437692}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4053427901774603, 0.4053427901774603, 0.4098566294048419, 0.4053427901774603}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.3748903927044398, -0.3983326109312375, -0.5363609554163984, -0.27559169754575485, -0.7405701529529249, -0.012441621585237428, -0.9622390369597675, 0.8749514845355539, -0.0260881109787372, -0.4581361518410456, 0.6689371573570113, 0.055538185735012124}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.44998546095665615, 0.27377749931336026, 0.011628227414849257}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4663825907673663}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.3374174303253419}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2780548111391228}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.26914281015527286}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3084155637176734}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.4195070123262301, 0.4195070123262301, 0.4195070123262301, 0.4195070123262301}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4436360129227126, 0.21918506931200255, 0.5623044537102242, -0.6116833555755048, 0.4818053050470017, 0.3457966931815506, -0.2353621053145154, 0.20288162279569377, 0.34939864011125654, 0.2307052259618596, 0.2211891416340006, -0.15343687233253456}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.36462039436710325, -0.08281511464665359, 0.029746055333887522, 0.11091373840901442, 0.06416339066193588, -0.3077269449186504, 0.38130690731286576, 0.056722260397850555, 0.22356821825721385, 0.061426925223631246, 0.25141254094955434, -0.11450651997170447}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4360312255869777, 0.11920204009038293, 0.09596285228352308, 0.06455492311138211}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.3301070544158011, 0.45879877272827274, -0.3921825793774687, -0.4589934375104999}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.25391711312455856}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.2524308850820858}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.07131446109621309}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){0.4152882270939301}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.35441353569349265}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.5812148205607915, 0.5808234918116899, 0.5812148205607915, 0.5811408063941178}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.5748737411819749, 0.03648148631952575, -0.5394486074860654, 0.3892234416952798, -0.5048801189447867, 0.1928958943131598, 0.704661315964231, 0.5980215398601989, -0.15845036135217727, 0.9123386620944931, -0.8941242382475498, -0.9747345488946391}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.15548195682083998, -0.41648605651953097, 0.2529296062184122, 0.3705761376555661, 0.33649838662433584, -0.21217459911692094, 0.13635028852756903, -0.09264368556666946, 0.15432647671010413}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.24771569704149166, -0.15964310884789756, 0.1161211577994713}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.2754088310579118, -0.06728368067864554, 0.21793971921819688}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.07701508807407864}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.14515511885569243, 0.2999227252480492, 0.42310339022017507, 0.3854033020677652}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.2949088927262349, 0.12498442680874011, 0.24347933764864915, 0.2676458971942338}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.2973841429451639, -0.24884542141691446, -0.3023085889659758, -0.3139779886170151, 0.2174526205355345, 0.09795077859332546, 0.08205625180757947, 0.4966019963737186, -0.13916520312985026, -0.3933406299712965, 0.3125563021867003, -0.15413462976448922}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.006366294315411802, -0.03605161199716389, -0.27355733196281873}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.15584593502268673, -0.05631353123828353, 0.4809662390669379}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3386427860309097}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.514937618009655, 0.48506238199034496, 0.514937618009655, 0.48506238199034496, 0.514937618009655, 0.48506238199034496, 0.514937618009655, 0.48506238199034496}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.36946463949511554, -0.8520139807632465, -0.9920460871592875, 0.5807439346562635, 0.41749770770438954, 0.5992810834592657, -0.5443274856961335, -0.6530202746514013, 0.650220681247303, -0.5458510941916137, 0.147996417541304, 0.4596817761477425}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.29413255989282105, -0.171903357298122, 0.35945785333113145, 0.2919469716223122, 0.12117044528590726, -0.4300202095396979, -0.1702374234956655, -0.08922221809154773, 0.16451134755902364}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.42698281361867363, -0.4843625396423725, -0.2654195965073918}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.044194001489222146, -0.4975873852557585, -0.06622102257108198, -0.4294683088745527, -0.03265710999762561, -0.3201801553042527}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3015462340012205, 0.24177797607946772}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.2758080059182547, 0.7241919940817452, 0.2589580898774046, 0.7410419101225955, 0.26681881273693187, 0.7331811872630681, 0.2577685437400662, 0.7422314562599337}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.7808185054377463, 0.24647968866785153, 0.24464253944724224, 0.8268091863069587, -0.6093995835499793, -0.38448324496693687, 0.1837135809187207, -0.36433124140241624, -0.29319071717613876, 0.7337886532163886, -0.9468635507562972, 0.8099489267419471}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.07394548608447582, 0.3483777162774845, -0.24698776227009234, 0.4944284617708522, -0.36224058298644524, 0.06589586311808227}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.14968621545594063, 0.15689740159378163}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.43693447975682875, -0.1113549615456908, -0.27457712216847885, 0.16718654940642197, 0.08004991811434825, 0.4728987354605908, 0.07393391304256891, -0.38029860605611154}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3518924216805387, 0.329198078864395, -0.3050487575756198, 0.48490297914772595}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.07915730063526949, -0.2647486047578318, 0.33628673397278774, 0.2581638048903315, -0.4118794713171744, 0.43969535921695424, 0.15419392661188713, 0.37985394941006356}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.35340100502783434, 0.49383315007330186}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.4808235393974409, 0.5191764606025591, 0.48078043004295545, 0.5192195699570447, 0.4808426775564536, 0.5191573224435464, 0.48083802149995925, 0.5191619785000408}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.5537783766902797, -0.010598782430915277, -0.12800553388437708, -0.9588057555694198, 0.04099416702504688, 0.6416876354268706, -0.4328492998896636, -0.8486791577885846, -0.5147608984979655, 0.8634573068556961, 0.27495579028333106, 0.6326674012184785}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.12166401760963885, 0.3892048620689019, -0.03103600935687323, -0.3719832785195958, 0.001041553849745691, 0.46726808753612514}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.23390015577729262, 0.3566751043786853}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.26058798936925887, 0.10350335554014789, 0.16744464542041926, -0.20240681342071642, 0.3165473419589584, 0.4701401027158021}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.1860821059489356, -0.26028916532239166, 0.15953648902722317}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.21313936528502597, -0.4335098835791614, 0.006845226459100684}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.2898541067880167}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.10952372523649623, 0.21466465528559764}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.2296552265272468, 0.2756382147355454}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5583329695797691, 0.4416670304202309, 0.5567124170159813, 0.44328758298401877, 0.5568603795242618, 0.4431396204757383, 0.5595062633247831, 0.4404937366752169}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.129469481541856, -0.8584957650197684, 0.12991024520877903, 0.5217549237430752, 0.8137391271516294, 0.46984509386792284, -0.41621454180712636, 0.08864304622912811, -0.10339488360952709, 0.5684024166046167, 0.5850099358318266, -0.770724209709573}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.31869404864266426, -0.22086432541215406, -0.3860815170580373, 0.30395846564689366, 0.3893571267536341, 0.2292663616381383, -0.302606960639362, 0.4162248238564299, 0.06578533304532685, -0.1626746050385388, 0.33021173294020245, 0.3348122943012187}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3096656981406357, -0.3112172482813076, 0.38018660235433344, 0.14413563628865522}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.3782784238839766, 0.09643830361651429, 0.36440452626522046, -0.0398096448528219, -0.4756261117393944, -0.1505140637996375, -0.2743126643759448, -0.13856334918950852, -0.43972873393626644, -0.1300379738073446, -0.2647833509602464, -0.3906597826007775, 0.31351924809077236, 0.13635741794919465, -0.37851851195037733, -0.05941016260102561}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.37743775493525644, -0.13537444179908198, -0.42316567112535697, 0.4861459044936155}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.3019824813152766, -0.4439413316937242, -0.13752969171829532, -0.18839185611333786, -0.24693646828415394, 0.3487788753318539, -0.18881254981004503, -0.22558177328687723, 0.3497543733898456, -0.018021784876955826, 0.4686263602190046, 0.2755964613747738}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4208617948332687, 0.21745614670032687, -0.23437238868376364}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.0205317090931304, -0.43720811319466213, 0.36418941815294525}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.45043632954650703}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.09830140149226085, -0.3812165705003573}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.060498926630124794, -0.03215667312267967}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3564299082633419, 0.23646665808381886, 0.40710343365283924, 0.35350530150569365, 0.26782833282899093, 0.37866636566531536, 0.3631878398580871, 0.2466046346927735, 0.39020752544913945, 0.356763212697796, 0.2478549007233341, 0.39538188657886986}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.09194259570202767, -0.45443957378846767, -0.6072435580635631, -0.4851646941753245, 0.35491067512336505, -0.3607931412714769, 0.37021333170560555, 0.8753228688000108, -0.6113865312174707, 0.46279321810174934, 0.3416187516885614, -0.35267869360694526}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.4594919599607724, -0.16980611850965532, 0.22268456090353572, -0.08882561222809238, -0.1781434563141795, -0.04953002784584193, -0.12120186045361447, 0.10557406649641154, -0.2032560883816158, 0.3346915644579421, -0.22121607845682112, -0.2606392173117439}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.307323326637858, -0.34484714513209236, -0.05514610873629733, 0.19268397959893435}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.08353881355815596, -0.3269190768950929, 0.4593332923488317, -0.05222302180692917, -0.15527779017638677, 0.3239203703344625, -0.13375871869063305, -0.451642217215935, -0.2543258393300034, -0.2376251015774018, 0.02320861215504988, 0.103667729452529}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.198577327452093, 0.007214818453201044, 0.31010876773023266}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.27593007620056337, 0.3400166583285388, 0.3840532654708978, 0.27593007620056337, 0.3400166583285388, 0.3840532654708978, 0.27593007620056337, 0.3400166583285388, 0.3840532654708978, 0.27593007620056337, 0.3400166583285388, 0.3840532654708978}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.8336970017710463, 0.5125795165031226, 0.08020372453593727, 0.29659273820645504, 0.6903029505102876, -0.15031723993813895, -0.3772395753078046, 0.17608163909296382, 0.37804314474509937, 0.892705803280984, -0.6400346037207323, -0.4012812724135557}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.125060119536746, 0.1862385824659759, 0.29420350827063757, -0.31825267996923845, -0.36219365631426426, -0.45730073694521256}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.1926812289279466, 0.48043262496568107}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.4942583142296886, 0.32408198776792163}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3156514092375031}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4560050530944677, 0.441880475317985, 0.20918257997630407}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.445342003050032, -0.2364948780760513, -0.11470823443809564}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.2706321667702951, 0.2797690606689573, 0.4495987725607476, 0.2706321667702951, 0.2797690606689573, 0.4495987725607476, 0.2706321667702951, 0.2797690606689573, 0.4495987725607476, 0.2706321667702951, 0.2797690606689573, 0.4495987725607476}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.16946561005125838, 0.5438337038268557, 0.43022787140640495, -0.11502544837605333, 0.44309180921156255, -0.19649102343797153, -0.7664819293191241, -0.40155666151085345, -0.25360604051702307, -0.15165200561883307, 0.6902059977575119, -0.7427883542276121}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.38397523421210367, 0.495993337949987, 0.10528598758420005, -0.09130070356860709, -0.29731009161182287, -0.062605089166338, -0.2861599547650462, 0.36357669942815307, 0.019644000826764874, 0.30035275169742326, -0.42516462742910877, -0.04836571226323494}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.27923829178673243, -0.3191380235556416, 0.02725322900167282, -0.08772439234113738}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.30453329084915537, -0.15041910065828068, -0.0852687487260857, -0.14399310107297925}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.25894222051535054}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.12825365352981677, 0.025425278421055575}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.12661847039025453, -0.3364572747140969}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.2568080160132684, -0.18693137756007072, -0.2964365898074529, -0.2007708526639317, -0.150371003182436, 0.2960989824821607}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4908368246746817, -0.3875819401090006, 0.06831454771893741}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3981307419105442, 0.2478392593897124, 0.35402999869974344, 0.3981307419105442, 0.2478392593897124, 0.35402999869974344, 0.3981307419105442, 0.2478392593897124, 0.35402999869974344, 0.3981307419105442, 0.2478392593897124, 0.35402999869974344}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.8480097736917627, 0.28644943826096125, 0.37395354421658866, 0.435636015721538, 0.9224210888606903, -0.3574819555437385, -0.0219524236828319, 0.9974699754097991, -0.9191119126499385, 0.37511369884684753, 0.1768976951545378, -0.22197417145744724}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2768161491626977, -0.09926500859074072, 0.12175041078602955, -0.08797089857317453, -0.061497210723662765, -0.18304652366387253, -0.07911874824516374, 0.23814565216358785, -0.041158160516712394}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2868732595500967, 0.2891703996502969, 0.44875905168336905}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.45066021099028775, -0.48490623385283693, 0.2500450160922286, 0.1714167507901373, -0.1050159365793416, 0.21367009324638442, -0.38839001557192565, 0.10896682819269388, 0.1653909172882082}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.2605703326421186, 0.010878591780864921, 0.49679158405382895}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.0402668009349596, 0.30917984504543783, 0.2472719470695226}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.1623476585617285}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.20713351959588366, -0.380678658797036}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.43321535095751684, -0.1621026316564279}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){-0.3487338681199047, 0.4316785401838431, 0.00971536183448396, 0.36790068012386323, 0.32290787617301175, -0.2394084695591281}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.48939297458911013, 0.015392914389790402, 0.3719941776184482}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.35580766867550506, 0.18252267011323925, 0.12248426849464898, 0.3391853927166067, 0.3511769675200306, 0.18096235195621774, 0.12374689803030213, 0.34411378249344954, 0.39384640936528437, 0.15774521581010195, 0.10236630434465467, 0.34604207047995894, 0.2845258320804855, 0.19184014606467734, 0.15537442139775404, 0.3682596004570833}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.6575999044200382, -0.2986673033012863, 0.3835928322808191, -0.7746495267969584, -0.29559091142929383, -0.9888605682825731, -0.3135899362800245, 0.6789609669402361, -0.5105667040236144, 0.860904644296292, -0.3969348632088887, -0.9854164749655785}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.15371262166746325, 0.42653935281417965, 0.14953003232934747, 0.1804109627921916, 0.07731252615895401, -0.3015324373996845}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4661381434689059, -0.08820791119883564}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.31033684629541525, -0.38084371394898864, -0.30542797164819036, -0.07429934297840846, -0.4465558103657101, 0.37195734874725106, 0.024996384113015857, 0.29826026641950254}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.46068347020615197, -0.02516828734544363, -0.3824242499082604, 0.49702170290846426}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.22308242352526803, 0.2902721553873264, 0.14189527396257076, 0.34475014712483487, 0.2228058431089315, 0.290389237449341, 0.14198272209407375, 0.3448221973476538, 0.22066830516875358, 0.29129463470041944, 0.1426607599240918, 0.34537630020673515, 0.22374529951691582, 0.2899916107743789, 0.14168595157456518, 0.3445771381341401}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.419370987731956, -0.30413985925223286, 0.29365347539587705, -0.5979467020292277, -0.8766253328594353, 0.9607692903724299, -0.8196146412117111, -0.43941037657097803, 0.2949006784015997, 0.15781946591693385, -0.6271630522920473, 0.7524735803256688}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.25945788138576853, -0.03146408636666631, 0.3144341450315403}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.1893168104689943}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.08066417964519046, -0.3929705888187206, 0.26712833184902085, -0.0703782242490667}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.05030296042839222, -0.37141525223149097, -0.27807189432968227, -0.46131048859980084}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.17536570091828274, -0.37224937877662023, -0.15946160120965625, 0.127662332722713, 0.38798827256574653, 0.4721955244741848, 0.08918431333172938, -0.11204867315405154, 0.4609241789901525, 0.10353158851038813, -0.4307097019415026, -0.07768894857250697, 0.32140079607561867, 0.06186275155975707, 0.3534325537862323, -0.39639217122631043}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.01935061676405414, 0.27246823987768876, -0.44457682068475446, 0.4456701295186537}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.27541060502418796, 0.2949333172531317, 0.21384327799966935, 0.21581279972301096, 0.27541060502418796, 0.2949333172531317, 0.21384327799966935, 0.21581279972301096, 0.27541060502418796, 0.2949333172531317, 0.21384327799966935, 0.21581279972301096, 0.27541060502418796, 0.2949333172531317, 0.21384327799966935, 0.21581279972301096}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.8315682519144769, -0.14291963209212422, -0.42810771363148237, -0.1524581631189137, 0.9442828758089163, -0.47130363113308893, 0.12016976743093921, 0.2638088033312844, -0.6545115251424014, 0.9564851886557761, -0.863519761578915, -0.9094450602630686}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.2944678796978156, -0.029834486828390072, -0.4125831945112258, -0.47368614524693753, 0.24133451168662035, -0.44809192604499404, 0.12406974450423547, -0.21190856443233075, -0.03659872336810799}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.22342183746320632, -0.3887360739805742, 0.04926793830840792}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.17345888501583495, -0.2115941398511728, 0.08055354374392754}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.13831928578620611}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.03338176488913358}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4030396636832402}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.4464846902837234, 0.22913757246846922, 0.35568627992072255, -0.46491672932850636}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.15002597067311774, -0.08153977636089005, -0.40304566300963696, -0.39387769997802513}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.15734973083746584, 0.2396550783609633, 0.38027530661459263, 0.22271988418697836, 0.15734973083746584, 0.2396550783609633, 0.38027530661459263, 0.22271988418697836, 0.15734973083746584, 0.2396550783609633, 0.38027530661459263, 0.22271988418697836, 0.15734973083746584, 0.2396550783609633, 0.38027530661459263, 0.22271988418697836}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.32722953912626696, 0.2867252010790413, 0.11774987103706214, 0.6957239206715466, 0.5627212403809783, -0.4360687290812939, 0.7581471982737851, 0.9963110986640076, 0.9539429096613885, -0.1264517167654553, -0.1065550597731093, 0.22603264545419566}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.41669347351064345, -0.2552281317951016, -0.2060400698211965, 0.05283596676905178, 0.4150373256705081, -0.1604191897502667, -0.0967566436241325, -0.49953891729087474, 0.44848156225250113, 0.26770081526268097, -0.25117240178148337, 0.31827877160925655}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4004137894803008, 0.04407531189166869, -0.1975680235971753, -0.035289509938685515}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.07847680865909024, -0.041709034716475135, 0.41264522886593313, -0.004564230796420765}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3559922901192577}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.057382854399135375, -0.45737819344348984, -0.4130454147544864, 0.29833196803598505}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.0892064611795852, 0.03128263852435864, -0.39925373447095736, -0.379955740447094}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.4690621594272534, 0.000555075221778556, 0.06257028932671105, -0.014077718459455046}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3647250200210247}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.13117197820919813, -0.37055710191252844, -0.01883265114598265, -0.39758032057747006}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.4784200333863333, 0.14630566895572839, 0.464994281359847, 0.0840070658726938}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.377194940827937, 0.3822641486475619, 0.3822641486475619, 0.3822641486475619}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.725337176480386, -0.9233761085845527, 0.14204679461523018, -0.22872855697353622, 0.5034673445590263, 0.9137166463013617, -0.428531104032954, -0.20009960571026908, -0.6498615705109791, -0.7142848098498555, 0.3491414217646489, 0.2384027123558865, 0.7495119292424262, -0.4376223614180508, 0.058604443731028244, 0.6923543850521301}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.10731218406974019, -0.21366282206534837, 0.1601495893347059, -0.2048951725738991}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.15938193784329469}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.1161105143835226}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.4799490828448667}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.3924895472587175, 0.3924895472587175, 0.3924895472587175, 0.3924895472587175}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.533585463666647, 0.9175694807540322, 0.7484133527444401, 0.9097552296258546, 0.07152166978743746, -0.22139276196079627, 0.9205902738723737, 0.15126016413797494, 0.12177364136774105, 0.582135612504864, -0.634277419535604, 0.8013872169144345, 0.30992890498079717, 0.27578488117430355, -0.3650105065996534, -0.7981597837720773}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.11438228764147096, -0.16333544235846764, -0.3874343132699998, 0.4067588405072242, -0.24119016377817049, -0.15875098567251666, -0.17376478478219548, 0.21546982478214605, 0.4378781037458952, 0.0687567186956144, -0.30785522049567315, 0.18466133701929, 0.4092638904962228, -0.4941651420165305, 0.4476433778323269, 0.30861228229960513}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.2682580589292506, 0.24124970057711714, 0.4024177103143799, -0.48768949710029463}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.049922653804219896, -0.40747082948762714, 0.19299372451833685, -0.1219715120008591, 0.23699198174242397, -0.28908953400701465, 0.026212820065918296, 0.2978639971915009}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.449410531371526, -0.3374277552899567}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.4213317431265856, 0.22421368695069366}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.43685947554530324}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.43463894585678325, 0.4347687547275531, 0.43405128503917273, 0.43466241147004486}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.5719132849077406, 0.0005080292277641618, -0.6613360652878624, 0.47732773081352775, -0.3650861170181272, 0.04946144496073934, 0.1163609282520317, 0.3874159771157799, 0.05990830604784847, 0.09706154801503741, -0.6620796741195953, -0.7011441953290467, -0.6259792010144363, 0.572977459008281, 0.37683673632340886, 0.6487803283156743}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.0720554219385039, 0.15707173291307097, 0.05926181028789301, 0.06513254483663555, -0.11069103396738245, 0.477273077822595, 0.29118142442903205, -0.4942533668997934, 0.25805237529303404, -0.1299131213321233, -0.18602897728133028, -0.48077698671117597, -0.35146984039868234, 0.16225192581247816, -0.2772395741836432, 0.4301732680468151}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.3156838976428771, 0.012557088766751101, 0.10087761424116248, -0.2517418986084875}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){-0.048746738462167816, -0.23629240495488602, -0.14349596952907884, 0.09174247075831143}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.3874008419254795}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.0378096001477668, -0.2523642952500261, 0.07128835035437286}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3962581157577637, -0.05874332723555342, 0.4617026132164569}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.1643575747510475, 0.022680978199872137, 0.32126438277377944}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.41929396111077133}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.515100764031499, 0.5150985580585372, 0.5150982070673684, 0.5151000147822372}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.06648480029275028, -0.363252682891652, -0.2212344035411311, -0.1282351764262304, 0.812267760186653, 0.9565973559547285, 0.048256519862911906, 0.371732572184327, 0.3784208015953354, -0.8215084705630715, 0.8871024830197434, -0.930237015370516, 0.6747765831067087, 0.8961661883998848, -0.6953688355717991, 0.015067097576380917}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.4642320609159861, -0.1783759934428496, 0.24552209407545567, 0.3838350571891589, 0.36912499207033633, -0.42727209871508853, 0.102792696490275, 0.11121701085173785, 0.15599312497415152, 0.4399275434562322, 0.21925197629328286, -0.0020198597478834346, -0.18733172674328835, 0.028888528562460936, -0.4357011181489373, -0.1642666733898549}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.09910042693752652, -0.004171987726058646, -0.14964505416854323, -0.21291326769409225}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.1573982995290084, -0.016931986218570283, 0.21026851451266904, -0.37270394295738984, 0.4747782202223638, -0.34059070920706147, 0.49268031603823503, -0.01064143974439824, -0.19286186005957595, -0.44699559030896185, -0.16328303449783532, 0.4403368394634328, -0.49753245681075176, 0.23577784035966676, 0.2304787069258456, 0.25216161257155945}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.07343673714360144, -0.19423885315096756, -0.4855735140924474, 0.11986807100849062}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.2831065900959837, -0.22963269054149904, 0.3090127800749656, 0.393825483066348}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.18445130589292402}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.3011331275323831, -0.06561822168102416, -0.4966292827522204, -0.23656325371977138}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.40843829037902457, 0.06946804707667642, -0.32640036046817456, -0.05862810219233783}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_sigmoid}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.16796023811206107, 0.004222448748221086, 0.23512149932415505, -0.15891048698999777}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.06019425561707248}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5779862740456441, 0.42201372595435604, 0.581943300038035, 0.41805669996196504, 0.5633899009204895, 0.4366100990795106, 0.581943300038035, 0.41805669996196504}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.8696026694592691, 0.7107765001009216, 0.6864434120893945, 0.8883395318978222, -0.4734347107108541, -0.42577036515674305, -0.5673879800392612, 0.7553880519791643, -0.6605997546299338, 0.5957314222214729, 0.7789836091271134, -0.752586303966063, 0.9738248705256973, -0.13019490435313963, -0.7948850819576676, 0.5836019668218424}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.16013035174767554, 0.09301208195131683, 0.2720369485028368, 0.04531163538055649, -0.4345348838385734, 0.1851639017029385, 0.21651206422441172, -0.21877626592496635}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.4074820774636203, -0.3909901805859659}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){0.1514056055451357, 0.02831133382728379, -0.1465909952554475, 0.2515357452118582}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.06437479268636737, -0.26638115851640665}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.455862885179227, 0.544137114820773, 0.45275394645882405, 0.547246053541176, 0.4613260032617048, 0.5386739967382952, 0.4529503329777438, 0.5470496670222562}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.9682064087104165, -0.006480640583824249, 0.5038764676238658, 0.11692173048193277, -0.759386764922297, 0.15119178837323366, 0.1518245223692425, 0.722244012468094, 0.27125416829519233, -0.5649748518972859, 0.7789760849850569, 0.7528667183777487, -0.5072680435242838, 0.3367813038516869, -0.3368371540341335, -0.14978426503989617}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.24194316317917552, -0.35871036061248385, 0.28791436636771983, -0.11297204787035331, 0.08058734979561022, -0.08668552853053346, 0.2474168728492947, -0.30601436785307035}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.49807363619817424, 0.28373222817763555}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){0.4540254619359302, 0.20068782571964394}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.0643151230513832}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){-0.07290516154399707, -0.16660961741028268}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.30427282644030895, -0.09875340449115966}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.320620128513626, 0.679379871486374, 0.320620128513626, 0.679379871486374, 0.320620128513626, 0.679379871486374, 0.320620128513626, 0.679379871486374}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.9321524065224456, 0.3126331305454788, -0.5717266841930888, -0.21660319655221927, -0.3232843322219541, -0.1421506357995055, -0.10145213502395478, 0.8939829384301683, -0.34291815975960405, 0.9850893899163686, -0.2686987547476869, -0.3306100977353492, 0.9430168512384829, 0.4942621787491941, 0.2615164421370335, 0.04121373506645787}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.4522070670115613, 0.1496292400524547, -0.21207081206638478, -0.1693331311063293, 0.23176949039467576, -0.06330887714666467, -0.10347188363524384, 0.11900265242063313, -0.4777681886451841, -0.35713657348053196, 0.13375765424085628, -0.05779100336073628}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.45189630843539064, 0.4612290489978209, 0.21765936726586943}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.4826445846589329, -0.015690059473312812, -0.38119394714098953}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.21090042476745163}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){0.4239203863863348, -0.1718537684252176, 0.2049383341139338}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.09007299020207171, -0.33987249061707325, -0.2621009438565005}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){-0.11219942285874296, -0.3919903098565005, 0.3542799587935447, 0.13368404895699393, -0.22357564183336087, -0.4259415086609888}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.30498325977254437, 0.44594014652841907}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){0.5160239067100256, 0.4839760932899743, 0.5160239067100256, 0.4839760932899743, 0.5160239067100256, 0.4839760932899743, 0.5160239067100256, 0.4839760932899743}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.9333260549227382, 0.08192852122811622, 0.12114893408028538, 0.9885460945565168, -0.6396275739908304, -0.04301303889656993, -0.2076778416834022, 0.08834978120613401, 0.7932231941616623, -0.710577641025969, 0.3536903000025222, 0.20094080388127988, 0.9222229990643946, -0.673084512112895, -0.47228426654340283, 0.5492459708970105}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.09241037131860907, -0.2727867840077973, 0.47078389944557886, 0.3156009963307468, -0.38113306284619586, -0.2580519250009906, 0.4888238463191136, -0.30681787458073106}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.2866215234140711, -0.31342096621536486}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 2}, false, (const NNTensorUnit[]){-0.06783947383516575, 0.057935114808431054}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.35664730670943323}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.4483023414508167}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.33061807454335124}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.011667688988349356, 0.20324796226423936, -0.12684543656070757}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.14897598001365497, -0.22952280294243554, 0.04473802873398469}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2595384720344428, 0.17021872573930985, 0.4644705290438138, 0.09989650960336327, -0.0077001020742102355, 0.17988159579349894}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.45570161326598113, 0.4043159773651297}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.303484388492463, 0.42361136211644945, 0.2729042493910875, 0.303484388492463, 0.42361136211644945, 0.2729042493910875, 0.303484388492463, 0.42361136211644945, 0.2729042493910875, 0.2220188241562217, 0.5692884437356354, 0.20869273210814288}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.9460607401843173, 0.8807256664403649, 0.4320065444738619, -0.7578568704786444, -0.5265021801322969, 0.3793359150285276, -0.754339289518404, 0.06217326007556445, -0.25246321401735106, 0.003897186074751424, -0.9205189818473691, -0.8918955792647179, 0.4204851957942939, -0.6113302640024341, 0.6559437219953803, 0.7896292523594841}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.10427478353051522, -0.4884163319618863, 0.399152842737604, 0.15666107373085603}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){0.13529427355277823}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 1, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 1}, false, (const NNTensorUnit[]){-0.269809539034096, 0.43466639436737897, -0.21848026844014046}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.303482741417071, 0.030003523768423745, -0.4096919135161088}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.37926655872293064, 0.2361090023246496, 0.3846244389524199, 0.37942508098637934, 0.2362132611936997, 0.38436165781992093, 0.38038635465970805, 0.23886679439304664, 0.38074685094724536, 0.37224340264415257, 0.23688274822955152, 0.3908738491262959}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.3370914394746021, 0.20900850586740938, 0.5427924103754382, -0.671636962824226, 0.1816798029100708, 0.4650048345546982, -0.14066429694056626, -0.9010404652781021, 0.615083854934938, -0.013704514669297119, 0.39119557263505156, -0.5247646931207179, -0.9116534548804436, -0.34128215482365376, -0.9375500001762391, 0.8500586871013638}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.24494057438945283, 0.45174145236687957, 0.3730270470498268, -0.39013772988060413, -0.36163659118018854, 0.11528554473690733, -0.038132828466698965, 0.13962557737616077, 0.48898757072715626, -0.21659126134834883, -0.20901694881913413, 0.1741506108490346, -0.22448387644388168, 0.4876097813517004, 0.11003224745167006, 0.4464785496408531}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.08454851402930474, -0.3798412104232205, -0.05062420831732761, -0.038539146183381834}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.0037253575721627463, -0.24729823756219615, -0.30521403548934356, -0.4698012169934108, 0.1840669209219281, 0.16410536493708294, 0.13915517508989717, 0.43340908766986663}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.06407230288125387, 0.19454761063920611}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.38910439571649036, -0.08914105758612556, 0.05544127630702522, -0.09330637097041705, 0.07411698077889717, 0.4269688395191785}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3397579220837371, -0.11087160898111148, 0.22093284425727855}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3120059151507495, 0.3767511795331345, 0.31124290531611604, 0.3120634380914, 0.37678684786529637, 0.31114971404330355, 0.3120059151507495, 0.3767511795331345, 0.31124290531611604, 0.3120130013382698, 0.3767555740629531, 0.3112314245987771}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.18266650875135437, -0.2392685680250397, 0.4106116351719866, -0.9183267786540066, -0.6426517403664262, -0.2677804584379657, -0.2709697618831952, 0.5592789387574544, 0.4360473755686525, -0.5635572332024601, 0.5669396243549587, 0.9995473623598237, -0.5942214427596344, 0.22395532074326407, 0.3319530059690108, 0.7445815516494552}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.27157089583396055, 0.008424514471689015, 0.20623347703495087, 0.09137875578254806, -0.1261352250479506, -0.47569602369127884, 0.3342463497403064, -0.10363640535503138, -0.14702364104038068, -0.05144220403196442, -0.24029745363837374, 0.3206233554582921}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.4804987890459841, -0.45646778475464833, -0.21824456647666013}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 3, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 3}, false, (const NNTensorUnit[]){0.2201059210875419, -0.4186136603516116, 0.3367645843443696, 0.2215796992033331, -0.2232227501489994, -0.36658850838926627}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.11350523299458481, 0.3531859262916952}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 2, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 2}, false, (const NNTensorUnit[]){-0.44558381563013794, -0.356368066550097, 0.1197073979804395, 0.0952991729447421}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){-0.39313118537087777, 0.35133919353349585}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.38432520190718467, 0.19140645772755904, -0.48641589705937405, 0.06737015653126255, 0.46077906315257744, -0.477757440524633}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3707910216585173, -0.1327891985801649, -0.10652086498912372}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){0.3320896560751358, 0.24606021041027262, 0.4218501335145916, 0.3320896560751358, 0.24606021041027262, 0.4218501335145916, 0.3320896560751358, 0.24606021041027262, 0.4218501335145916, 0.3320896560751358, 0.24606021041027262, 0.4218501335145916}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.912788076938496, -0.15519051595513145, -0.5307280421484195, -0.21867029353307244, 0.8786963762541231, -0.998012407935136, -0.6107941370351198, 0.9749681569895146, 0.22382730938311957, -0.033748953810171844, 0.42241823294107306, 0.5729892414449436, 0.8874990464867665, 0.32465059640649496, -0.12368233530566908, -0.7700194267826226}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 4}, false, (const NNTensorUnit[]){0.4937382403664905, 0.009984414762899796, 0.17023459720389433, 0.4937647677584359}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.23342379486205722}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 1, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 1}, false, (const NNTensorUnit[]){-0.026792861155112146}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.37670437409562507}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 1, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 1}, false, (const NNTensorUnit[]){0.3541726315988387, -0.05603197311588093}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.43957528947409696, 0.15550975086341112}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.26850701719321257, 0.38842000435113266, -0.23866960727073372, -0.4552462357618231, 0.23275779089002036, -0.13734679227991653}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.3475349183986264, 0.2637049006266502, -0.30886793085243436}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){-0.34913223391023196, 0.010207923184356926, -0.05942639290718954, 0.024802722086349815, 0.22740841766090025, 0.4316152291087375, 0.47042579732566037, 0.18464885804727293, 0.09510846119495575}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.04410410128587938, -0.47151495145293776, -0.1630614719100223}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.17413166796244134, 0.23874174441944387, 0.2350246063322404, 0.35210198128587444, 0.17067731772320413, 0.2384738718825982, 0.2329765095348722, 0.3578723008593254, 0.15278974489894356, 0.23630714708334083, 0.2215906189313742, 0.3893124890863415, 0.16987219718546265, 0.23840479375294485, 0.2324923661249139, 0.3592306429366786}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 3, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.9409939338464184, -0.3525792589993073, 0.7535299865954341, 0.9528936330165909, -0.1378761574605989, 0.17727390753837513, -0.75810068052242, -0.9432865978803235, 0.05632235394731411, -0.8349957126055605, -0.5947090411863547, -0.19225129512367634, 0.13309437717042227, 0.8730915278074654, -0.8771088001234768, 0.3780026656365023}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.2549359518015616, -0.2697867472285418, -0.39497618137973, 0.06434979714107025, -0.2516115298918792, 0.0988587454341584, 0.15024805431796073, 0.21133232372750477}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.4747559126871387, -0.23716696835229167}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 2, + .inputs_size = 2, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 2}, false, (const NNTensorUnit[]){-0.25281168285604216, 0.23868750398463723, 0.07873280897912927, 0.35724253611744905, -0.05501039695283383, 0.13228940691807167, 0.38334756875864284, 0.4856762591722963}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.18983200564508662, -0.06438963852835611, -0.0033851194704477283, 0.14946369584912744}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.1775692683420393, 0.26583384268066884, 0.360656227855458, 0.1959406611218339, 0.1775692683420393, 0.26583384268066884, 0.360656227855458, 0.1959406611218339, 0.17140379161402852, 0.2599943103905025, 0.37441354752904327, 0.19418835046642563, 0.17503908130063625, 0.26345706367699184, 0.36626127585178886, 0.1952425791705831}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 4, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.07879903653828202, 0.734293973830239, 0.664952392816301, 0.008533282581654644, 0.23608571671228717, 0.8644268571071576, -0.5457214760419027, 0.028841862368671478, 0.3357043646989346, 0.22033489987830945, 0.6257414387329401, -0.16323025907557054, -0.4219716946600722, 0.6402255831202801, 0.3614234828645053, 0.8253315435763013}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.3559802165680096, -0.05282163595233669, 0.21222492129685888, -0.3228705464531584, -0.4853716925211782, -0.36873700609049687, 0.00019370746106672776, -0.046842832557559944, 0.19772643651858668, 0.3251191569685814, -0.2302403022456775, 0.2036994218178979, 0.44845000047675, -0.2957900173138218, 0.4334518691437965, 0.49689027262348406}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.08991467182802948, 0.4703235009924607, 0.12175338501368493, -0.30665119451529943}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){-0.18626960271093362, 0.16359420179189987, 0.04889685838328239, 0.3539815012776796, -0.09550256013453251, 0.3365700046697788, -0.4249327000906925, -0.3350312220446421, 0.011875433294819437, -0.3136425193612643, -0.25019991143231035, -0.4974832552366002}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.32687260148192854, 0.040447494407938045, -0.12169040366812878}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 2, + .inputs_size = 3, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 3}, false, (const NNTensorUnit[]){-0.2327731174101021, -0.4622410655134458, -0.24734512105455597, 0.02746715599641658, -0.30622584238399353, -0.02461380833932958, 0.332696127149287, 0.4026909533538151, 0.3206498994631869, 0.10628661100278336, -0.14900449498423995, -0.03325709007426059}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.447285978559245, -0.04377529350057496, 0.2612784716902252, -0.3488348915154891}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.25475021655459984, 0.19946836600286424, 0.32354639133604884, 0.2222350261064869, 0.25475021655459984, 0.19946836600286424, 0.32354639133604884, 0.2222350261064869, 0.25475021655459984, 0.19946836600286424, 0.32354639133604884, 0.2222350261064869, 0.25475021655459984, 0.19946836600286424, 0.32354639133604884, 0.2222350261064869}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 5, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.444869963968761, -0.4165456628208821, -0.9787897367081724, -0.4222850917593144, -0.1182747447173429, 0.538872645130837, 0.06815321307217426, -0.8718611189462004, 0.7093919863768561, -0.3995676791464209, 0.19214363346492047, -0.277857613093647, 0.4699496027505359, -0.5939458037190095, -0.9266884620691911, -0.7492194610532799}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.40687922240810825, -0.2282670217277073, -0.46152957332147504, 0.47328443166240375, 0.48823364582189055, -0.15214569736409844, -0.4116636743633143, 0.22489550813927595, 0.08396091934133598, -0.3654906062794041, -0.360638943977726, 0.46053829983347894, -0.4213751162631484, 0.45593264767300634, 0.17865752645647193, -0.40712151878931513}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.1793551260833547, -0.27972809574103763, -0.27728106769984073, 0.02993142023399553}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 4, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 4}, false, (const NNTensorUnit[]){0.14262213467801255, -0.205547136153041, 0.4657043360444656, -0.12349924859370043, 0.19938507561096286, 0.13900056702294228, -0.2828444509561424, 0.48078419076604484, 0.1999698947700751, -0.31936764596271117, 0.15513886529152265, 0.11243095039279805}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.35926387204652277, 0.1514546002278767, 0.3064456988452834}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){-0.08603044752041034, 0.3278317729682805, -0.14622254677606417}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.3179812152321715}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){-0.3772406008878143, 0.40071950222342434, -0.43787722373595206, 0.467826958693084}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){-0.11656975804238923, -0.36119762285673196, 0.12248922788663541, -0.2531177821867553}, NULL), + .inputs = NULL, + }, + }, + }, + { + .batch_size = 4, + .expected_outputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){0.3146950686387167, 0.2806303793166588, 0.17289883106037865, 0.23177572098424593, 0.3168066994836559, 0.2797408339577173, 0.17199896992437697, 0.23145349663424997, 0.31612782129142886, 0.28002685669469196, 0.172287841975004, 0.2315574800388752, 0.3136361750100084, 0.28107631411240735, 0.17335155897151486, 0.2319359519060693}, NULL), + .output_tolerance = default_output_tolerance, + .n_layers = 6, + .layers = (TestCaseLayer[]){ + { + .layer_idx = 0, + .layer_type = 0, + .inputs_size = 4, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_identity}, + .weights = NULL, + .biases = NULL, + .inputs = nn_tensor_init_NNTensor(2, (const size_t[]){4, 4}, false, (const NNTensorUnit[]){-0.40562941337095215, 0.0769617478785789, 0.07182925678098218, 0.1813006968158748, 0.5753875750172128, -0.48765445795439644, -0.5059775984748767, -0.07878669970724661, 0.35518927913266785, 0.6015500619245124, -0.8619801849553366, -0.7613699778509511, -0.01905886280345781, -0.19077147485871726, 0.4675397788831308, 0.5028617076132735}, NULL), + }, + { + .layer_idx = 1, + .layer_type = 1, + .inputs_size = 4, + .output_size = 2, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){2, 4}, false, (const NNTensorUnit[]){0.13143205077839581, -0.1350286245361697, 0.11179380040072295, -0.2146313740091117, -0.2716563277555524, -0.36335023199309235, -0.32738275148863916, -0.2388027858640085}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){2}, false, (const NNTensorUnit[]){0.3670076496921637, 0.24757696315467803}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 2, + .layer_type = 1, + .inputs_size = 2, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 2}, false, (const NNTensorUnit[]){0.3053818575088062, 0.4143955883835452, -0.09051102344516293, -0.17606462711294635, 0.41811502531959355, 0.2607953010556485}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){0.4227373908464874, -0.14404148426706564, -0.360522236736029}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 3, + .layer_type = 1, + .inputs_size = 3, + .output_size = 3, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){3, 3}, false, (const NNTensorUnit[]){0.13602231155256994, -0.33182858300197515, 0.2365988765248095, 0.22651719976785045, -0.24368352958423523, 0.17936096270962665, 0.016197178996936623, 0.15479833275335697, 0.42440895590652306}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){3}, false, (const NNTensorUnit[]){-0.3790951093610243, -0.005213379880157354, 0.42952922981355635}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 4, + .layer_type = 1, + .inputs_size = 3, + .output_size = 1, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_SCALAR, + .act_func = {.scalar_func = nn_act_func_relu}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){1, 3}, false, (const NNTensorUnit[]){0.284051679329552, 0.48448531645823, 0.2442174584917951}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){1}, false, (const NNTensorUnit[]){-0.033986027746438774}, NULL), + .inputs = NULL, + }, + { + .layer_idx = 5, + .layer_type = 2, + .inputs_size = 1, + .output_size = 4, + .mat_mul_func = nn_mat_mul, + .mat_transpose_func = nn_mat_transpose, + .act_func_type = NN_ACT_FUNC_TENSOR, + .act_func = {.tensor_func = nn_act_func_softmax}, + .weights = nn_tensor_init_NNTensor(2, (const size_t[]){4, 1}, false, (const NNTensorUnit[]){0.25849041795540906, -0.366975065426952, -0.496557823214402, -0.2538596356183572}, NULL), + .biases = nn_tensor_init_NNTensor(1, (const size_t[]){4}, false, (const NNTensorUnit[]){0.4514819051107265, 0.42341948454861345, -0.04299072349392463, 0.21650712250130122}, NULL), + .inputs = NULL, + }, + }, + }, + }; + + run_test_cases(test_cases, n_test_cases, "layer_multi"); - run_test_cases(test_cases, N_TEST_CASES, "NNLayer"); return 0; } diff --git a/tests/arch/generic/neuron/main.c b/tests/arch/generic/neuron/main.c deleted file mode 100644 index eba1575..0000000 --- a/tests/arch/generic/neuron/main.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "nn_config.h" -#include "nn_neuron.h" -#include -#include -#include -#include - -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 10 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.0001f - -// TestCase defines a single test case. -typedef struct { - float inputs[NN_NEURON_MAX_WEIGHTS]; - float weights[NN_NEURON_MAX_WEIGHTS]; - size_t input_size; - float bias; - NNDotProdFunc dot_prod_func; - float output_tolerance; - float expected_output; -} TestCase; - -// run_test_cases runs the test cases. -void run_test_cases(TestCase *test_cases, int n_cases, char *info, NNDotProdFunc dot_prod_func) { - for (int i = 0; i < n_cases; ++i) { - TestCase tc = test_cases[i]; - NNNeuron neuron; - NNError error; - - nn_neuron_init(&neuron, tc.weights, tc.input_size, tc.bias, &error); - assert(error.code == NN_ERROR_NONE); - nn_neuron_set_dot_prod_func(&neuron, dot_prod_func, &error); - assert(error.code == NN_ERROR_NONE); - nn_neuron_set_act_func(&neuron, nn_act_func_identity, &error); - const float output = nn_neuron_compute(&neuron, tc.inputs, &error); - assert(error.code == NN_ERROR_NONE); - assert(isnan(output) == false); - assert(fabs(output - tc.expected_output) < tc.output_tolerance); - printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); - } -} - -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .inputs = {0.5f, 1.2f, -0.8f}, - .weights = {0.2f, 0.3f, -0.1f}, - .input_size = 3, - .bias = 0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 1.04f, - }, - - { - .inputs = {-0.6f, -1.1f, 0.9f}, - .weights = {-0.2f, 0.5f, 0.3f}, - .input_size = 3, - .bias = -0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.66f, - }, - - { - .inputs = {1.5f, 2.0f, -1.0f}, - .weights = {0.4f, 0.4f, -0.2f}, - .input_size = 3, - .bias = 2.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 3.6f, - }, - - { - .inputs = {0.1f, -0.2f, 0.3f}, - .weights = {0.3f, -0.2f, 0.1f}, - .input_size = 3, - .bias = 0.05f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.15f, - }, - - { - .inputs = {-2.5f, 3.0f, -1.5f}, - .weights = {0.5f, -0.5f, 0.75f}, - .input_size = 3, - .bias = 1.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -2.875f, - }, - - { - .inputs = {0.0f, 0.0f, 0.0f}, - .weights = {0.25f, -0.75f, 0.5f}, - .input_size = 3, - .bias = 0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.5f, - }, - - { - .inputs = {1.2f, -1.2f, 0.8f}, - .weights = {0.0f, 0.0f, 0.0f}, - .input_size = 3, - .bias = 0.25f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.25f, - }, - - { - .inputs = {1.0f, -1.0f, 1.0f}, - .weights = {-1.0f, 1.0f, -1.0f}, - .input_size = 3, - .bias = -0.5f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -3.5f, - }, - - { - .inputs = {0.123f, 0.456f, -0.789f}, - .weights = {0.321f, -0.654f, 0.987f}, - .input_size = 3, - .bias = 0.1f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = -0.937484, - }, - - { - .inputs = {0.001f, -0.002f, 0.003f}, - .weights = {0.004f, 0.005f, -0.006f}, - .input_size = 3, - .bias = 0.0f, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = 0.000012f, - }, - }; - run_test_cases(test_cases, N_TEST_CASES, "NNNeuron", nn_dot_prod); - return 0; -} diff --git a/tests/arch/generic/neuron_perf/main.c b/tests/arch/generic/neuron_perf/main.c deleted file mode 100644 index 5909f8c..0000000 --- a/tests/arch/generic/neuron_perf/main.c +++ /dev/null @@ -1,55 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include "nn_activation.h" -#include "nn_app.h" -#include "nn_config.h" -#include "nn_neuron.h" -#include "nn_test.h" -#include -#include -#include - -int main(int argc, char *argv[]) { - nn_init_app(argc, argv); - srand((unsigned int)time(NULL)); - - // Init vars - NNNeuron neuron; - NNError error; - size_t input_size = 3; - float weights[NN_NEURON_MAX_WEIGHTS] = {0.2f, 0.8f, -0.5f}; - float bias = 2.0f; - const int n_runs = 1000; - const int n_inputs = n_runs * input_size; - long long total_time = 0; - struct timespec start, end; - float *inputs = malloc(n_inputs * sizeof(float)); - for (int i = 0; i < n_inputs; ++i) { - inputs[i] = (float)rand() / (float)RAND_MAX; - } - - if (!nn_neuron_init(&neuron, weights, input_size, bias, &error)) { - printf("error: %s\n", error.message); - return 1; - } else if (!nn_neuron_set_dot_prod_func(&neuron, nn_dot_prod, &error)) { - printf("error: %s\n", error.message); - return 1; - } else if (!nn_neuron_set_act_func(&neuron, nn_act_func_identity, &error)) { - printf("error: %s\n", error.message); - return 1; - } - - // Benchmark - for (int i = 0; i < n_runs; ++i) { - clock_gettime(CLOCK_MONOTONIC, &start); - nn_neuron_compute(&neuron, inputs + i * input_size, &error); - clock_gettime(CLOCK_MONOTONIC, &end); - total_time += nn_timespec_diff_ns(&start, &end); - } - if (error.code != NN_ERROR_NONE) { - printf("error: %s\n", error.message); - return 1; - } - printf("avg_time_ns=%lld total_time_ms=%lld info=nn_neuron_compute\n", total_time / n_runs, total_time / 1000000); - - return 0; -} diff --git a/tests/arch/generic/softmax/main.c b/tests/arch/generic/softmax/main.c deleted file mode 100644 index 0a92419..0000000 --- a/tests/arch/generic/softmax/main.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "nn_activation.h" -#include "nn_config.h" -#include -#include -#include -#include - -// N_TEST_CASES defines the number of test cases. -#define N_TEST_CASES 4 -// DEFAULT_OUTPUT_TOLERANCE defines the default tolerance for comparing output values. -#define DEFAULT_OUTPUT_TOLERANCE 0.000001f - -// TestCase defines a single test case. -typedef struct { - float input[NN_AF_VECTOR_MAX_SIZE]; - size_t input_size; - NNActFuncVector activation_func; - float output_tolerance; - float expected_output[NN_AF_VECTOR_MAX_SIZE]; -} TestCase; - -// run_test_cases runs the test cases. -void run_test_cases(TestCase *test_cases, int n_cases, char *info, NNActFuncVector activation_func) { - for (int i = 0; i < n_cases; ++i) { - TestCase tc = test_cases[i]; - NNError error; - - float output[NN_AF_VECTOR_MAX_SIZE]; - const bool result = activation_func(tc.input, output, tc.input_size, &error); - assert(result == true); - assert(error.code == NN_ERROR_NONE); - float sum = 0; - for (size_t i = 0; i < tc.input_size; ++i) { - assert(fabs(output[i] - tc.expected_output[i]) < tc.output_tolerance); - sum += output[i]; - } - assert(sum == 1.0f); - printf("passed: %s case=%d info=%s\n", __func__, i + 1, info); - } -} - -int main() { - TestCase test_cases[N_TEST_CASES] = { - { - .input = {1.0, 2.0, 3.0}, - .input_size = 3, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = {0.09003057317038046, 0.24472847105479767, 0.6652409557748219}, - }, - - { - .input = {-1.0, -2.0, -3.0}, - .input_size = 3, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = {0.6652409557748219, 0.24472847105479764, 0.09003057317038046}, - }, - - { - .input = {3.12, 0.845, -0.917}, - .input_size = 3, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = {0.89250074, 0.09174632, 0.01575295}, - }, - - { - .input = {1.8, -3.21, 2.44}, - .input_size = 3, - .output_tolerance = DEFAULT_OUTPUT_TOLERANCE, - .expected_output = {0.34445323, 0.00229781, 0.65324896}, - }, - - }; - run_test_cases(test_cases, N_TEST_CASES, "nn_act_func_softmax", nn_act_func_softmax); - - return 0; -} From f9a142c0e0ce83c68e5ee4b9733111c7317cf588 Mon Sep 17 00:00:00 2001 From: Fatih Cetinkaya <965295+devfacet@users.noreply.github.com> Date: Sat, 11 May 2024 20:32:16 -0400 Subject: [PATCH 2/5] Fix tests --- .github/workflows/test.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 42ea469..79e2586 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -85,11 +85,11 @@ jobs: - name: Test run: | if [ "${{ matrix.test }}" == "arm-neon" ]; then - TESTS=make test ARCH=arm FILTERS=neon + TESTS="make test ARCH=arm FILTERS=neon" elif [ "${{ matrix.test }}" == "arm-cmsis-dsp" ]; then - TESTS=make test ARCH=arm FILTERS=cmsis-dsp + TESTS="make test ARCH=arm FILTERS=cmsis-dsp" elif [ "${{ matrix.test }}" == "amd64-generic" ]; then - TESTS=make test ARCH=generic + TESTS="make test ARCH=generic" else echo "unknown test" exit 1 From f27dde014c3ba05f23b9c41473145d3b89045281 Mon Sep 17 00:00:00 2001 From: Fatih Cetinkaya <965295+devfacet@users.noreply.github.com> Date: Sat, 11 May 2024 20:42:40 -0400 Subject: [PATCH 3/5] Fix tests --- scripts/docker/Dockerfile.amd64-generic | 5 ----- scripts/docker/Dockerfile.arm-cmsis-dsp | 5 ----- scripts/docker/Dockerfile.arm-neon | 5 ----- scripts/docker/Dockerfile.armv7-neon | 5 ----- scripts/docker/Dockerfile.armv8-neon | 5 ----- 5 files changed, 25 deletions(-) diff --git a/scripts/docker/Dockerfile.amd64-generic b/scripts/docker/Dockerfile.amd64-generic index d3c2257..b62df88 100644 --- a/scripts/docker/Dockerfile.amd64-generic +++ b/scripts/docker/Dockerfile.amd64-generic @@ -17,10 +17,5 @@ COPY . /nn WORKDIR /nn RUN make build-artifacts PREFIX=tests/arch/generic LDFLAGS="-lm" -# Runtime -FROM ubuntu:latest -WORKDIR /nn -COPY --from=build /nn /nn - ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.arm-cmsis-dsp b/scripts/docker/Dockerfile.arm-cmsis-dsp index 0af6e22..9ffa1f7 100644 --- a/scripts/docker/Dockerfile.arm-cmsis-dsp +++ b/scripts/docker/Dockerfile.arm-cmsis-dsp @@ -20,10 +20,5 @@ COPY . /nn WORKDIR /nn RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=cmsis-dsp LDFLAGS="-lm" -# Runtime -FROM ubuntu:latest -WORKDIR /nn -COPY --from=build /nn /nn - ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.arm-neon b/scripts/docker/Dockerfile.arm-neon index 39cd7e9..fe12132 100644 --- a/scripts/docker/Dockerfile.arm-neon +++ b/scripts/docker/Dockerfile.arm-neon @@ -20,10 +20,5 @@ COPY . /nn WORKDIR /nn RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" -# Runtime -FROM ubuntu:latest -WORKDIR /nn -COPY --from=build /nn /nn - ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.armv7-neon b/scripts/docker/Dockerfile.armv7-neon index 889adfb..4a60a67 100644 --- a/scripts/docker/Dockerfile.armv7-neon +++ b/scripts/docker/Dockerfile.armv7-neon @@ -20,10 +20,5 @@ COPY . /nn WORKDIR /nn RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" CFLAGS="-mfpu=neon-vfpv4" -# Runtime -FROM arm32v7/ubuntu:latest -WORKDIR /nn -COPY --from=build /nn /nn - ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.armv8-neon b/scripts/docker/Dockerfile.armv8-neon index dc48ce2..a9bda55 100644 --- a/scripts/docker/Dockerfile.armv8-neon +++ b/scripts/docker/Dockerfile.armv8-neon @@ -20,10 +20,5 @@ COPY . /nn WORKDIR /nn RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" -# Runtime -FROM arm64v8/ubuntu:latest -WORKDIR /nn -COPY --from=build /nn /nn - ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] From 57ff4caec9ff02774ab81e54e273796e66c5d850 Mon Sep 17 00:00:00 2001 From: Fatih Cetinkaya <965295+devfacet@users.noreply.github.com> Date: Sat, 11 May 2024 20:51:44 -0400 Subject: [PATCH 4/5] Fix tests --- .github/workflows/test.yaml | 6 +++--- scripts/docker/Dockerfile.amd64-generic | 1 - scripts/docker/Dockerfile.arm-cmsis-dsp | 1 - scripts/docker/Dockerfile.arm-neon | 1 - scripts/docker/Dockerfile.armv7-neon | 1 - scripts/docker/Dockerfile.armv8-neon | 1 - 6 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 79e2586..a30cdf4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -85,11 +85,11 @@ jobs: - name: Test run: | if [ "${{ matrix.test }}" == "arm-neon" ]; then - TESTS="make test ARCH=arm FILTERS=neon" + TESTS="make test ARCH=arm FILTERS=neon LDFLAGS=-lm" elif [ "${{ matrix.test }}" == "arm-cmsis-dsp" ]; then - TESTS="make test ARCH=arm FILTERS=cmsis-dsp" + TESTS="make test ARCH=arm FILTERS=cmsis-dsp LDFLAGS=-lm" elif [ "${{ matrix.test }}" == "amd64-generic" ]; then - TESTS="make test ARCH=generic" + TESTS="make test ARCH=generic LDFLAGS=-lm" else echo "unknown test" exit 1 diff --git a/scripts/docker/Dockerfile.amd64-generic b/scripts/docker/Dockerfile.amd64-generic index b62df88..ffdc7b1 100644 --- a/scripts/docker/Dockerfile.amd64-generic +++ b/scripts/docker/Dockerfile.amd64-generic @@ -15,7 +15,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ FROM base as build COPY . /nn WORKDIR /nn -RUN make build-artifacts PREFIX=tests/arch/generic LDFLAGS="-lm" ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.arm-cmsis-dsp b/scripts/docker/Dockerfile.arm-cmsis-dsp index 9ffa1f7..7fa43d6 100644 --- a/scripts/docker/Dockerfile.arm-cmsis-dsp +++ b/scripts/docker/Dockerfile.arm-cmsis-dsp @@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ FROM base as build COPY . /nn WORKDIR /nn -RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=cmsis-dsp LDFLAGS="-lm" ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.arm-neon b/scripts/docker/Dockerfile.arm-neon index fe12132..53ff7e2 100644 --- a/scripts/docker/Dockerfile.arm-neon +++ b/scripts/docker/Dockerfile.arm-neon @@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ FROM base as build COPY . /nn WORKDIR /nn -RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.armv7-neon b/scripts/docker/Dockerfile.armv7-neon index 4a60a67..14c2e2c 100644 --- a/scripts/docker/Dockerfile.armv7-neon +++ b/scripts/docker/Dockerfile.armv7-neon @@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ FROM base as build COPY . /nn WORKDIR /nn -RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" CFLAGS="-mfpu=neon-vfpv4" ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] diff --git a/scripts/docker/Dockerfile.armv8-neon b/scripts/docker/Dockerfile.armv8-neon index a9bda55..5196f35 100644 --- a/scripts/docker/Dockerfile.armv8-neon +++ b/scripts/docker/Dockerfile.armv8-neon @@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ FROM base as build COPY . /nn WORKDIR /nn -RUN make build-artifacts PREFIX=tests/arch/arm FILTERS=neon LDFLAGS="-lm" ENTRYPOINT ["/bin/bash", "-c"] CMD ["/bin/bash"] From 506310e44a26b35976e69194a125f96338d54546 Mon Sep 17 00:00:00 2001 From: Fatih Cetinkaya <965295+devfacet@users.noreply.github.com> Date: Sat, 11 May 2024 21:11:09 -0400 Subject: [PATCH 5/5] Fix tests --- .github/workflows/test.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a30cdf4..9f9af65 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -85,11 +85,15 @@ jobs: - name: Test run: | if [ "${{ matrix.test }}" == "arm-neon" ]; then - TESTS="make test ARCH=arm FILTERS=neon LDFLAGS=-lm" + if [ "${{ matrix.tag }}" == "nntbn:armv7-neon" ]; then + TESTS="make test ARCH=arm FILTERS=neon LDFLAGS='-lm' CFLAGS='-mfpu=neon-vfpv4'" + else + TESTS="make test ARCH=arm FILTERS=neon LDFLAGS='-lm'" + fi elif [ "${{ matrix.test }}" == "arm-cmsis-dsp" ]; then - TESTS="make test ARCH=arm FILTERS=cmsis-dsp LDFLAGS=-lm" + TESTS="make test ARCH=arm FILTERS=cmsis-dsp LDFLAGS='-lm'" elif [ "${{ matrix.test }}" == "amd64-generic" ]; then - TESTS="make test ARCH=generic LDFLAGS=-lm" + TESTS="make test ARCH=generic LDFLAGS='-lm'" else echo "unknown test" exit 1