Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
- name: Run tests
working-directory: ${{github.workspace}}
run: |
./build/tools/run_tests
./build/tools/run_tests -s
./build/tools/benchmodel ./example_models/wavenet.nam
./build/tools/benchmodel ./example_models/lstm.nam
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "Dependencies/eigen"]
path = Dependencies/eigen
url = https://gitlab.com/libeigen/eigen
[submodule "Dependencies/catch2"]
path = Dependencies/catch2
url = https://github.com/catchorg/Catch2
1 change: 1 addition & 0 deletions Dependencies/catch2
Submodule catch2 added at a1faad
41 changes: 27 additions & 14 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
file(GLOB_RECURSE NAM_SOURCES ../NAM/*.cpp ../NAM/*.c ../NAM*.h)
file(GLOB TEST_SOURCES test/*.cpp)

# TODO: add loadmodel and run_tests to TOOLS?
set(TOOLS benchmodel)
add_subdirectory(${NAM_DEPS_PATH}/catch2 Catch2)

# TODO: add loadmodel to TOOLS?
set(TOOLS benchmodel run_tests)

add_custom_target(tools ALL
DEPENDS ${TOOLS})
Expand All @@ -12,11 +15,15 @@ include_directories(tools ${NAM_DEPS_PATH}/nlohmann)

add_executable(loadmodel loadmodel.cpp ${NAM_SOURCES})
add_executable(benchmodel benchmodel.cpp ${NAM_SOURCES})
add_executable(run_tests run_tests.cpp ${NAM_SOURCES})
add_executable(run_tests run_tests.cpp ${NAM_SOURCES} ${TEST_SOURCES})
target_link_libraries(run_tests PRIVATE Catch2::Catch2WithMain)

source_group(NAM ${CMAKE_CURRENT_SOURCE_DIR} FILES ${NAM_SOURCES})

target_compile_features(${TOOLS} PUBLIC cxx_std_20)
foreach(TOOL IN LISTS TOOLS)
target_compile_features(${TOOL} PUBLIC cxx_std_20)
endforeach()


set_target_properties(${TOOLS}
PROPERTIES
Expand All @@ -26,20 +33,26 @@ set_target_properties(${TOOLS}
)

if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(${TOOLS} PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN)
foreach(TOOL IN LISTS TOOLS)
target_compile_definitions(${TOOL} PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN)
endforeach()
endif()

if (MSVC)
target_compile_options(${TOOLS} PRIVATE
"$<$<CONFIG:DEBUG>:/W4>"
"$<$<CONFIG:RELEASE>:/O2>"
)
foreach(TOOL IN LISTS TOOLS)
target_compile_options(${TOOL} PRIVATE
"$<$<CONFIG:DEBUG>:/W4>"
"$<$<CONFIG:RELEASE>:/O2>"
)
endforeach()
else()
target_compile_options(${TOOLS} PRIVATE
-Wall -Wextra -Wpedantic -Wstrict-aliasing -Wunreachable-code -Weffc++ -Wno-unused-parameter
"$<$<CONFIG:DEBUG>:-Og;-ggdb;-Werror>"
"$<$<CONFIG:RELEASE>:-Ofast>"
)
foreach(TOOL IN LISTS TOOLS)
target_compile_options(${TOOL} PRIVATE
-Wall -Wextra -Wpedantic -Wstrict-aliasing -Wunreachable-code -Weffc++ -Wno-unused-parameter
"$<$<CONFIG:DEBUG>:-Og;-ggdb;-Werror>"
"$<$<CONFIG:RELEASE>:-Ofast>"
)
endforeach()
endif()

# There's an error in eigen's
Expand Down
42 changes: 2 additions & 40 deletions tools/run_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,40 +1,2 @@
// Entry point for tests
// See the GitHub Action for a demo how to build and run tests.

#include <iostream>
#include "test/test_activations.cpp"
#include "test/test_dsp.cpp"
#include "test/test_get_dsp.cpp"
#include "test/test_wavenet.cpp"

int main()
{
std::cout << "Running tests..." << std::endl;
// TODO Automatically loop, catch exceptions, log results

test_activations::TestFastTanh::test_core_function();
test_activations::TestFastTanh::test_get_by_init();
test_activations::TestFastTanh::test_get_by_str();

test_activations::TestLeakyReLU::test_core_function();
test_activations::TestLeakyReLU::test_get_by_init();
test_activations::TestLeakyReLU::test_get_by_str();

test_dsp::test_construct();
test_dsp::test_get_input_level();
test_dsp::test_get_output_level();
test_dsp::test_has_input_level();
test_dsp::test_has_output_level();
test_dsp::test_set_input_level();
test_dsp::test_set_output_level();

test_get_dsp::test_gets_input_level();
test_get_dsp::test_gets_output_level();
test_get_dsp::test_null_input_level();
test_get_dsp::test_null_output_level();

test_wavenet::test_gated();

std::cout << "Success!" << std::endl;
return 0;
}
#define CATCH_CONFIG_MAIN
#include <catch2/catch_test_macros.hpp>
171 changes: 69 additions & 102 deletions tools/test/test_activations.cpp
Original file line number Diff line number Diff line change
@@ -1,122 +1,89 @@
// Tests for activation functions
//
// Things you want ot test for:
// 1. That the core elementwise funciton is snapshot-correct.
// 2. The class that wraps the core function for an array of data
// 3. .cpp: that you have the singleton defined, and that it's in the unordered map to get by string

#include <cassert>
#include <string>
#include <vector>
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>

#include "NAM/activations.h"

namespace test_activations
TEST_CASE("Test fast_tanh core function", "[activations]")
{
// TODO get nonzero cases
class TestFastTanh
REQUIRE(nam::activations::fast_tanh(0.0f) == 0.0f);
// The original test had these commented out.
// REQUIRE(nam::activations::fast_tanh(1.0f) == Catch::Approx(0.98f));
// REQUIRE(nam::activations::fast_tanh(-1.0f) == Catch::Approx(-0.98f));
}

void _test_fast_tanh_class(nam::activations::Activation* a)
{
public:
static void test_core_function()
{
auto TestCase = [](float input, float expectedOutput) {
float actualOutput = nam::activations::fast_tanh(input);
assert(actualOutput == expectedOutput);
};
// A few snapshot tests
TestCase(0.0f, 0.0f);
// TestCase(1.0f, 1.0f);
// TestCase(-1.0f, -0.01f);
};

static void test_get_by_init()
{
auto a = nam::activations::ActivationLeakyReLU();
_test_class(&a);
}
std::vector<float> inputs, expectedOutputs;

inputs.push_back(0.0f);
expectedOutputs.push_back(0.0f);

// inputs.push_back(1.0f);
// expectedOutputs.push_back(1.0f);

// Get the singleton and test it
static void test_get_by_str()
// inputs.push_back(-1.0f);
// expectedOutputs.push_back(-0.01f);

a->apply(inputs.data(), (long)inputs.size());
for (size_t i = 0; i < inputs.size(); ++i)
{
const std::string name = "Fasttanh";
auto a = nam::activations::Activation::get_activation(name);
_test_class(a);
REQUIRE(inputs[i] == Catch::Approx(expectedOutputs[i]));
}
}

private:
// Put the class through its paces
static void _test_class(nam::activations::Activation* a)
{
std::vector<float> inputs, expectedOutputs;
TEST_CASE("Test FastTanh get by init", "[activations]")
{
auto a = nam::activations::ActivationFastTanh();
_test_fast_tanh_class(&a);
}

inputs.push_back(0.0f);
expectedOutputs.push_back(0.0f);
TEST_CASE("Test FastTanh get by str", "[activations]")
{
const std::string name = "Fasttanh";
auto a = nam::activations::Activation::get_activation(name);
REQUIRE(a != nullptr);
_test_fast_tanh_class(a);
}

// inputs.push_back(1.0f);
// expectedOutputs.push_back(1.0f);
TEST_CASE("Test LeakyReLU core function", "[activations]")
{
REQUIRE(nam::activations::leaky_relu(0.0f) == 0.0f);
REQUIRE(nam::activations::leaky_relu(1.0f) == 1.0f);
REQUIRE(nam::activations::leaky_relu(-1.0f) == -0.01f);
}

// inputs.push_back(-1.0f);
// expectedOutputs.push_back(-0.01f);
void _test_leaky_relu_class(nam::activations::Activation* a)
{
std::vector<float> inputs, expectedOutputs;

a->apply(inputs.data(), (long)inputs.size());
for (auto itActual = inputs.begin(), itExpected = expectedOutputs.begin(); itActual != inputs.end();
++itActual, ++itExpected)
{
assert(*itActual == *itExpected);
}
};
};
inputs.push_back(0.0f);
expectedOutputs.push_back(0.0f);

class TestLeakyReLU
{
public:
static void test_core_function()
{
auto TestCase = [](float input, float expectedOutput) {
float actualOutput = nam::activations::leaky_relu(input);
assert(actualOutput == expectedOutput);
};
// A few snapshot tests
TestCase(0.0f, 0.0f);
TestCase(1.0f, 1.0f);
TestCase(-1.0f, -0.01f);
};

static void test_get_by_init()
{
auto a = nam::activations::ActivationLeakyReLU();
_test_class(&a);
}
inputs.push_back(1.0f);
expectedOutputs.push_back(1.0f);

// Get the singleton and test it
static void test_get_by_str()
inputs.push_back(-1.0f);
expectedOutputs.push_back(-0.01f);

a->apply(inputs.data(), (long)inputs.size());
for (size_t i = 0; i < inputs.size(); ++i)
{
const std::string name = "LeakyReLU";
auto a = nam::activations::Activation::get_activation(name);
_test_class(a);
REQUIRE(inputs[i] == Catch::Approx(expectedOutputs[i]));
}
}

private:
// Put the class through its paces
static void _test_class(nam::activations::Activation* a)
{
std::vector<float> inputs, expectedOutputs;

inputs.push_back(0.0f);
expectedOutputs.push_back(0.0f);

inputs.push_back(1.0f);
expectedOutputs.push_back(1.0f);

inputs.push_back(-1.0f);
expectedOutputs.push_back(-0.01f);

a->apply(inputs.data(), (long)inputs.size());
for (auto itActual = inputs.begin(), itExpected = expectedOutputs.begin(); itActual != inputs.end();
++itActual, ++itExpected)
{
assert(*itActual == *itExpected);
}
};
};
}; // namespace test_activations
TEST_CASE("Test LeakyReLU get by init", "[activations]")
{
auto a = nam::activations::ActivationLeakyReLU();
_test_leaky_relu_class(&a);
}

TEST_CASE("Test LeakyReLU get by str", "[activations]")
{
const std::string name = "LeakyReLU";
auto a = nam::activations::Activation::get_activation(name);
REQUIRE(a != nullptr);
_test_leaky_relu_class(a);
}
Loading