diff --git a/autotest/CMakeLists.txt b/autotest/CMakeLists.txt new file mode 100644 index 000000000..365a94e5a --- /dev/null +++ b/autotest/CMakeLists.txt @@ -0,0 +1,23 @@ +include(CTest) +include(cmake/DownloadProject.cmake) + +enable_testing() + +# download gtest at first +download_project( + PROJ googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + UPDATE_DISCONNECTED 1 +) +add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) + +# include directory +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../src) + +# add cpp and lib files +add_executable(autotest autotest.cpp) + +target_link_libraries(autotest ${project_library_target_name} ${REQUIRED_LIBRARIES} gtest gmock) +target_link_libraries(autotest ncnn) diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp new file mode 100644 index 000000000..37179f99f --- /dev/null +++ b/autotest/autotest.cpp @@ -0,0 +1,17 @@ +#include + +#include "blob.h" +#include "net.h" +#include "layer.h" +#include "mat.h" +#include "opencv.h" +#include "platform.h" + +#include "test_convlution.h" +#include "test_innerproduct.h" +#include "gtest/gtest.h" + +int main(int argc, char **argv){ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/autotest/cmake/DownloadProject.CMakeLists.cmake.in b/autotest/cmake/DownloadProject.CMakeLists.cmake.in new file mode 100644 index 000000000..0b3c40b99 --- /dev/null +++ b/autotest/cmake/DownloadProject.CMakeLists.cmake.in @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.2) + +project(${DL_ARGS_PROJ}-download NONE) + +include(ExternalProject) +ExternalProject_Add(${DL_ARGS_PROJ}-download + ${DL_ARGS_UNPARSED_ARGUMENTS} + SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" + BINARY_DIR "${DL_ARGS_BINARY_DIR}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/autotest/cmake/DownloadProject.cmake b/autotest/cmake/DownloadProject.cmake new file mode 100644 index 000000000..209996931 --- /dev/null +++ b/autotest/cmake/DownloadProject.cmake @@ -0,0 +1,143 @@ +# MODULE: DownloadProject +# +# PROVIDES: +# download_project( PROJ projectName +# [PREFIX prefixDir] +# [DOWNLOAD_DIR downloadDir] +# [SOURCE_DIR srcDir] +# [BINARY_DIR binDir] +# [QUIET] +# ... +# ) +# +# Provides the ability to download and unpack a tarball, zip file, git repository, +# etc. at configure time (i.e. when the cmake command is run). How the downloaded +# and unpacked contents are used is up to the caller, but the motivating case is +# to download source code which can then be included directly in the build with +# add_subdirectory() after the call to download_project(). Source and build +# directories are set up with this in mind. +# +# The PROJ argument is required. The projectName value will be used to construct +# the following variables upon exit (obviously replace projectName with its actual +# value): +# +# projectName_SOURCE_DIR +# projectName_BINARY_DIR +# +# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically +# need to be provided. They can be specified if you want the downloaded source +# and build directories to be located in a specific place. The contents of +# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the +# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. +# +# The DOWNLOAD_DIR argument does not normally need to be set. It controls the +# location of the temporary CMake build used to perform the download. +# +# The PREFIX argument can be provided to change the base location of the default +# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments +# are provided, then PREFIX will have no effect. The default value for PREFIX is +# CMAKE_BINARY_DIR. +# +# The QUIET option can be given if you do not want to show the output associated +# with downloading the specified project. +# +# In addition to the above, any other options are passed through unmodified to +# ExternalProject_Add() to perform the actual download, patch and update steps. +# The following ExternalProject_Add() options are explicitly prohibited (they +# are reserved for use by the download_project() command): +# +# CONFIGURE_COMMAND +# BUILD_COMMAND +# INSTALL_COMMAND +# TEST_COMMAND +# +# Only those ExternalProject_Add() arguments which relate to downloading, patching +# and updating of the project sources are intended to be used. Also note that at +# least one set of download-related arguments are required. +# +# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to +# prevent a check at the remote end for changes every time CMake is run +# after the first successful download. See the documentation of the ExternalProject +# module for more information. It is likely you will want to use this option if it +# is available to you. +# +# EXAMPLE USAGE: +# +# include(download_project.cmake) +# download_project(PROJ googletest +# GIT_REPOSITORY https://github.com/google/googletest.git +# GIT_TAG master +# UPDATE_DISCONNECTED 1 +# QUIET +# ) +# +# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) +# +#======================================================================================== + + +set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") + +include(CMakeParseArguments) + +function(download_project) + + set(options QUIET) + set(oneValueArgs + PROJ + PREFIX + DOWNLOAD_DIR + SOURCE_DIR + BINARY_DIR + # Prevent the following from being passed through + CONFIGURE_COMMAND + BUILD_COMMAND + INSTALL_COMMAND + TEST_COMMAND + ) + set(multiValueArgs "") + + cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Hide output if requested + if (DL_ARGS_QUIET) + set(OUTPUT_QUIET "OUTPUT_QUIET") + else() + unset(OUTPUT_QUIET) + message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") + endif() + + # Set up where we will put our temporary CMakeLists.txt file and also + # the base point below which the default source and binary dirs will be + if (NOT DL_ARGS_PREFIX) + set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") + endif() + if (NOT DL_ARGS_DOWNLOAD_DIR) + set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") + endif() + + # Ensure the caller can know where to find the source and build directories + if (NOT DL_ARGS_SOURCE_DIR) + set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") + endif() + if (NOT DL_ARGS_BINARY_DIR) + set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") + endif() + set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) + set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) + + # Create and build a separate CMake project to carry out the download. + # If we've already previously done these steps, they will not cause + # anything to be updated, so extra rebuilds of the project won't occur. + configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" + "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + ${OUTPUT_QUIET} + WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" + ) + execute_process(COMMAND ${CMAKE_COMMAND} --build . + ${OUTPUT_QUIET} + WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" + ) + +endfunction() diff --git a/autotest/test_convlution.h b/autotest/test_convlution.h new file mode 100644 index 000000000..c3243d89c --- /dev/null +++ b/autotest/test_convlution.h @@ -0,0 +1,70 @@ +#pragma once +#include "gtest/gtest.h" +#include "layer/convolution.h" +using namespace ncnn; + +/* +forward - pass: + [0,1,2,3,4, + 1,2,3,4,5, [1,1,1, [ 9.5, 18.5, + 2,3,4,5,6, * 0.5* 1,1,1, + 0.5 = + 3,4,5,6,7, 1,1,1] 18.5, 27.5] + 4,5,6,7,8] +*/ + +TEST(convolution, forward) +{ + // layer params + Convolution convolution_layer; + convolution_layer.num_output = 1; + convolution_layer.kernel_size = 3; + convolution_layer.dilation = 1; + convolution_layer.stride = 2; + convolution_layer.pad = 0; + convolution_layer.bias_term = 1; + convolution_layer.weight_data_size = 9; + + // input & output + float_t in[] = { + 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, + 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, + 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f + }; + + float_t expected_out[] = { + 9.5f, 18.5f, + 18.5f, 27.5f + }; + + + // weights & bias + float_t w[] = { + 0.5f, 0.5f, 0.5f, + 0.5f, 0.5f, 0.5f, + 0.5f, 0.5f, 0.5f + }; + + float_t b[] = { + 0.5f + }; + + // forward + Mat mat_in(5, 5, 1, in); + Mat mat_out; + + convolution_layer.bias_data.data = b; + convolution_layer.weight_data.data = w; + convolution_layer.forward(mat_in, mat_out); + + // check expect + EXPECT_EQ(mat_out.w, 2); + EXPECT_EQ(mat_out.h, 2); + EXPECT_EQ(mat_out.c, 1); + for (int i = 0; i < _countof(expected_out); ++i) + { + EXPECT_NEAR(mat_out[i], expected_out[i], 1E-5); + } + +} \ No newline at end of file diff --git a/autotest/test_innerproduct.h b/autotest/test_innerproduct.h new file mode 100644 index 000000000..f45affa8b --- /dev/null +++ b/autotest/test_innerproduct.h @@ -0,0 +1,55 @@ +#pragma once +#include "gtest/gtest.h" +#include "layer/innerproduct.h" + +/* +forward - pass: +[0,1,2,3] * [1,1,1,1 + [0.5, = [6.5, + 1,1,1,1] 0.5] 6.5] +*/ + +TEST(innerproduct, forward) +{ + // layer params + InnerProduct inner_product_layer; + inner_product_layer.num_output = 2; // W + inner_product_layer.bias_term = 1; // bias + inner_product_layer.weight_data_size = 3; // W + bias + + + // input & output + float_t in[] = { + 0.0f, 1.0f, 2.0f, 3.0f + }; + + float_t expected_out[] = { + 6.5, 6.5 /// 0+1+2+3+0.5 + }; + + + // weights & bias + float_t w[] = { + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + float_t b[] = { + 0.5f, 0.5f + }; + + // forward + Mat mat_in(4, in); + Mat mat_out; + + inner_product_layer.bias_data.data = b; + inner_product_layer.weight_data.data = w; + inner_product_layer.forward(mat_in, mat_out); + + // check expect + EXPECT_EQ(mat_out.c, 2); + for (int i = 0; i < _countof(expected_out); ++i) + { + float output_value = *(mat_out.data + mat_out.cstep * i); + EXPECT_NEAR(output_value, expected_out[i], 1E-5); + } +} \ No newline at end of file