├── CMakeLists.txt ├── LICENSE ├── README.md ├── cpptorch.cmake.in ├── developer_guide.md ├── example ├── basic │ ├── CMakeLists.txt │ ├── main.cpp │ ├── net.t7 │ ├── x.t7 │ └── y.t7 └── openface │ ├── CMakeLists.txt │ ├── face.jpg │ └── main.cpp ├── include ├── General.h ├── allocator.h ├── builder.h ├── cpptorch.h ├── cpptorch_cuda.h ├── nn │ ├── Add.h │ ├── BatchNormalization.h │ ├── Concat.h │ ├── Container.h │ ├── Decorator.h │ ├── DepthConcat.h │ ├── Inception.h │ ├── Layer.h │ ├── Linear.h │ ├── LogSoftMax.h │ ├── MulConstant.h │ ├── Normalize.h │ ├── ReLU.h │ ├── Reshape.h │ ├── Sequential.h │ ├── SoftMax.h │ ├── SpatialAveragePooling.h │ ├── SpatialBatchNormalization.h │ ├── SpatialConvolution.h │ ├── SpatialConvolutionMM.h │ ├── SpatialCrossMapLRN.h │ ├── SpatialLPPooling.h │ ├── SpatialMaxPooling.h │ ├── SpatialReflectionPadding.h │ ├── Sqrt.h │ ├── Square.h │ ├── Tanh.h │ ├── Threshold.h │ └── View.h └── torch │ ├── Storage.h │ └── Tensor.h ├── install.md ├── install_linux.md ├── install_mac.md ├── install_windows.md ├── progress.md ├── src ├── allocator.cpp ├── allocator.h ├── builder.h.inl ├── develop_new_layer.py ├── export.cpp ├── loader.cpp ├── loader.h ├── nn │ ├── Add.h.inl │ ├── BatchNormalization.h.inl │ ├── Concat.h.inl │ ├── Container.h.inl │ ├── Decorator.h.inl │ ├── DepthConcat.h.inl │ ├── Inception.h.inl │ ├── Layer.h.inl │ ├── Linear.h.inl │ ├── LogSoftMax.h.inl │ ├── MulConstant.h.inl │ ├── Normalize.h.inl │ ├── Reshape.h.inl │ ├── Sequential.h.inl │ ├── SoftMax.h.inl │ ├── SpatialAveragePooling.h.inl │ ├── SpatialBatchNormalization.h.inl │ ├── SpatialConvolution.h.inl │ ├── SpatialConvolutionMM.h.inl │ ├── SpatialCrossMapLRN.h.inl │ ├── SpatialMaxPooling.h.inl │ ├── SpatialReflectionPadding.h.inl │ ├── Sqrt.h.inl │ ├── Square.h.inl │ ├── Tanh.h.inl │ ├── Threshold.h.inl │ ├── View.h.inl │ └── util.h.inl ├── reader.h ├── reader.h.inl ├── serializer │ ├── Add.h │ ├── BatchNormalization.h │ ├── Concat.h │ ├── Container.h │ ├── Decorator.h │ ├── DepthConcat.h │ ├── Inception.h │ ├── Linear.h │ ├── LogSoftMax.h │ ├── MulConstant.h │ ├── Normalize.h │ ├── ReLU.h │ ├── Reshape.h │ ├── Sequential.h │ ├── SoftMax.h │ ├── SpatialAveragePooling.h │ ├── SpatialBatchNormalization.h │ ├── SpatialConvolution.h │ ├── SpatialConvolutionMM.h │ ├── SpatialCrossMapLRN.h │ ├── SpatialLPPooling.h │ ├── SpatialMaxPooling.h │ ├── SpatialReflectionPadding.h │ ├── Sqrt.h │ ├── Square.h │ ├── Tanh.h │ ├── Threshold.h │ └── View.h ├── th_wrapper.cpp ├── th_wrapper.h ├── torch │ ├── Storage.h.inl │ ├── Tensor.h.inl │ └── TensorPrint.h.inl └── util.h ├── src_cuda ├── cuda.cpp ├── export.cpp ├── th_wrapper.cpp └── th_wrapper.h └── test ├── CMakeLists.txt ├── cases ├── Containers │ ├── Concat_1.lua │ ├── Concat_2.lua │ ├── DepthConcat_1.lua │ └── Sequental_1.lua ├── ConvolutionLayers │ └── Spatial │ │ ├── SpatialAveragePooling_1.lua │ │ ├── SpatialBatchNormalization_1.lua │ │ ├── SpatialBatchNormalization_2.lua │ │ ├── SpatialConvolutionMM_1.lua │ │ ├── SpatialConvolution_1.lua │ │ ├── SpatialCrossMapLRN_1.lua │ │ ├── SpatialLPPooling_1.lua │ │ ├── SpatialMaxPooling_1.lua │ │ └── SpatialReflectionPadding_1.lua ├── SimpleLayers │ ├── BasicTensor │ │ ├── Reshape_1.lua │ │ └── View_1.lua │ ├── MathTensor │ │ ├── Normalize_1.lua │ │ ├── Normalize_2.lua │ │ └── Sqrt_1.lua │ ├── Miscellaneous │ │ └── BatchNormalization_1.lua │ └── Parameterized │ │ └── Linear_1.lua ├── TransferFunctions │ ├── Add_1.lua │ ├── LogSoftMax_1.lua │ ├── MulConstant_1.lua │ ├── ReLU_1.lua │ ├── SoftMax_1.lua │ └── Tanh_1.lua └── dpnn │ ├── Decorator_1.lua │ └── Inception_1.lua ├── common.h ├── run_test.sh ├── tester.cpp └── tester_cuda.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | option(BUILD_CUDA "Enable cuda" OFF) 5 | option(BUILD_TESTS "Build test programs" OFF) 6 | 7 | 8 | if(UNIX) 9 | # add support for c++11 10 | add_definitions("-std=c++11 -O2") 11 | endif() 12 | 13 | 14 | if(NOT Torch_FOUND) 15 | find_package(Torch REQUIRED) 16 | endif() 17 | 18 | 19 | macro(generate_project name src) 20 | # create target 21 | add_library(${name} SHARED ${src}) 22 | 23 | if(MSVC) 24 | target_compile_definitions(${name} PRIVATE API_CPPTORCH_DEF=1) 25 | endif() 26 | 27 | # include dirs 28 | target_include_directories(${name} PRIVATE "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_INCLUDE_SUBDIR}" "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_INCLUDE_SUBDIR}/THNN" "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_INCLUDE_SUBDIR}/TH") 29 | 30 | # link/usr/share/cmake-3.5/Modules/ 31 | find_library(TH_LIBRARY NAMES TH PATHS ${Torch_INSTALL_PREFIX}/${Torch_INSTALL_LIB_SUBDIR}) 32 | find_library(THNN_LIBRARY NAMES THNN PATHS ${Torch_INSTALL_PREFIX}/${Torch_INSTALL_LIB_SUBDIR}/lua/5.1) 33 | target_link_libraries(${name} ${TH_LIBRARY} ${THNN_LIBRARY}) 34 | 35 | # install target 36 | install(TARGETS ${name} 37 | RUNTIME DESTINATION "bin" 38 | ARCHIVE DESTINATION "lib" 39 | LIBRARY DESTINATION "lib" 40 | ) 41 | set_target_properties(${name} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 42 | set_target_properties(${name} PROPERTIES MACOSX_RPATH TRUE) 43 | endmacro() 44 | 45 | 46 | # cpptorch 47 | file(GLOB_RECURSE cpptorch_src "include/*.h" "src/*.h" "src/*.h.inl" "src/*.cpp" "src/*.cc") 48 | foreach(each_file ${cpptorch_src}) 49 | get_filename_component(file_dir "${each_file}" PATH) 50 | # absolute path -> relative path 51 | string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" file_relative_dir "${file_dir}") 52 | 53 | # skip src or include directory 54 | string(REGEX REPLACE "(\\./)?(src)/?" "" group_name "${file_relative_dir}") 55 | # changes "/" to "\" 56 | string(REPLACE "/" "\\" group_name "${group_name}") 57 | 58 | # group into "Source Files" and "Header Files" 59 | if ("${each_file}" MATCHES ".*\\.cpp") 60 | set(group_name "Source Files\\${group_name}") 61 | elseif("${each_file}" MATCHES ".*\\.h") 62 | set(group_name "Header Files\\${group_name}") 63 | endif() 64 | 65 | source_group("${group_name}" FILES "${each_file}") 66 | endforeach() 67 | generate_project(cpptorch "${cpptorch_src}") 68 | 69 | 70 | # cpptorch_cuda 71 | if(BUILD_CUDA) 72 | if(NOT CUDA_FOUND) 73 | find_package(CUDA 5.5 REQUIRED) 74 | endif() 75 | file(GLOB_RECURSE cpptorch_cuda_src "src_cuda/*.cpp" "src_cuda/*.cc") 76 | generate_project(cpptorch_cuda "${cpptorch_cuda_src}") 77 | target_include_directories(cpptorch_cuda PRIVATE ${CUDA_INCLUDE_DIRS} "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_INCLUDE_SUBDIR}" "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_INCLUDE_SUBDIR}/THCUNN" "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_INCLUDE_SUBDIR}/THC") 78 | find_library(THC_LIBRARY NAMES THC PATHS ${Torch_INSTALL_PREFIX}/${Torch_INSTALL_LIB_SUBDIR}) 79 | find_library(THCUNN_LIBRARY NAMES THCUNN PATHS ${Torch_INSTALL_PREFIX}/${Torch_INSTALL_LIB_SUBDIR}/lua/5.1) 80 | target_link_libraries(cpptorch_cuda cpptorch ${THC_LIBRARY} ${THCUNN_LIBRARY}) 81 | endif() 82 | 83 | 84 | # install headers 85 | file(GLOB_RECURSE cpptorch_headers "include/*.h") 86 | foreach(file ${cpptorch_headers}) 87 | get_filename_component(dir ${file} PATH) 88 | string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/include" "" dir "${dir}") 89 | install(FILES ${file} DESTINATION "include/cpptorch/${dir}") 90 | endforeach() 91 | 92 | 93 | # create cmake file for find_package 94 | set(CPPTORCH_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 95 | set(CPPTORCH_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include") 96 | configure_file(cpptorch.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/cmake-exports/cpptorch-config.cmake") 97 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake-exports/cpptorch-config.cmake" 98 | DESTINATION "share/cmake/cpptorch") 99 | 100 | 101 | ############################################################# 102 | 103 | 104 | if(BUILD_TESTS) 105 | add_subdirectory(test) 106 | 107 | find_package(Torch REQUIRED) 108 | 109 | enable_testing() 110 | 111 | file(GLOB_RECURSE test_cases "test/cases/*.lua") 112 | foreach(each_case ${test_cases}) 113 | string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/test/cases/" "" case_name ${each_case}) 114 | string(REPLACE "/" "_" case_name ${case_name}) 115 | string(REPLACE ".lua" "" case_name ${case_name}) 116 | add_test(NAME cpptorch_${case_name} COMMAND 117 | ${CMAKE_CURRENT_SOURCE_DIR}/test/run_test.sh 118 | "${Torch_INSTALL_PREFIX}/${Torch_INSTALL_BIN_SUBDIR}" 119 | "${CMAKE_CURRENT_BINARY_DIR}" 120 | "${each_case}" 121 | ) 122 | endforeach() 123 | endif() 124 | 125 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {2016} {tuotuoxp@gmail.com} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | cpp-torch is a C++ library, implemented as a wrapper around [torch](https://github.com/torch) **C libraries** (not lua libraries). 4 | 5 | Using this library, you can: 6 | 7 | - load torch data tensor from `.t7` file 8 | - load torch network model from `.t7` file 9 | - feed data into model, perform forward pass and get output 10 | 11 | **All in C++, without touching lua.** 12 | 13 | Pretty handy when you want to deploy an off-the-shelf torch model. 14 | 15 | # Install 16 | Check our install script for ~~[Linux](install_linux.md)~~, [Windows](install_windows.md)(*TODO*) and [MacOS](install_mac.md)(*TODO*). 17 | 18 | ## Install cpp-torch on Linux 19 | The following commands install our C++ wrapper: cpp-torch in default torch install dir: 20 | 21 | ``` bash 22 | git clone https://github.com/yytdfc/cpp-torch 23 | cd cpp-torch 24 | mkdir build 25 | cd build 26 | cmake -DCMAKE_INSTALL_PREFIX=~/torch/install -DCMAKE_PREFIX_PATH=~/torch/install .. 27 | # For GPU version, set -DBUILD_CUDA=ON: 28 | cmake -DBUILD_CUDA=ON -DCMAKE_INSTALL_PREFIX=~/torch/install -DCMAKE_PREFIX_PATH=~/torch/install .. 29 | make 30 | make install 31 | cd .. 32 | ``` 33 | 34 | # Get started 35 | The following code loads a float tensor and a float network from file, and forwards the tensor into the network: 36 | ```c++ 37 | // read input tensor 38 | std::ifstream fs_input("input_tensor.t7", std::ios::binary); 39 | auto obj_input = cpptorch::load(fs_input); 40 | auto input = cpptorch::read_tensor(obj_input.get()); // load float tensor 41 | 42 | // read network 43 | std::ifstream fs_net("net.t7", std::ios::binary); 44 | auto obj_net = cpptorch::load(fs_net); 45 | auto net = cpptorch::read_net(obj_net.get()); // load float network 46 | 47 | // forward 48 | auto output = net->forward(input); 49 | 50 | // display 51 | std::cout << input << std::endl; 52 | std::cout << *net << std::endl; 53 | std::cout << output << std::endl; 54 | ``` 55 | 56 | If tensor and network type is double, change the template type accordingly: 57 | ```c++ 58 | auto input = cpptorch::read_tensor(obj_input.get()); // load double tensor 59 | auto net = cpptorch::read_tensor(obj_net.get()); // load double network 60 | ``` 61 | 62 | To use GPU, use read_cuda_tensor() function: 63 | ```c++ 64 | auto input = cpptorch::read_cuda_tensor(obj_input.get()); // load cuda tensor 65 | auto net = cpptorch::read_cuda_net(obj_net.get()); // load cuda network 66 | ``` 67 | 68 | We also provides an [example script](example/openface/main.cpp) to test the famous [CMU OpenFace](https://github.com/cmusatyalab/openface) model. This example transfers a 3 * 96 * 96 face image(OpenCV Mat) into cpp-torch tensor, forwards it through the network, receives a 128 * 1 identity feature tensor, and print the result. 69 | 70 | # Progress 71 | Currently, this library supports forward pass of 72 | - some modules in [nn package](https://github.com/torch/nn) 73 | - related functions in [torch7 package](https://github.com/torch/torch7) 74 | - a few modules in [dpnn package](https://github.com/Element-Research/dpnn). 75 | 76 | Check [this list](progress.md) to see supported modules. 77 | 78 | You are more than welcome to add new modules to cpp-torch. Please check our [developer guide](developer_guide.md). 79 | 80 | # FAQ 81 | -- How can I train my own model with this wrapper? 82 | 83 | -- We don't support backward functions, so training is impossible. Use the original torch. 84 | -------------------------------------------------------------------------------- /cpptorch.cmake.in: -------------------------------------------------------------------------------- 1 | # Find the cpp-torch includes and library 2 | 3 | 4 | set(CPPTORCH_FOUND 1) 5 | set(CPPTORCH_INCLUDE_DIR "@CPPTORCH_INCLUDE_DIR@") 6 | set(CPPTORCH_LIB_DIR "@CPPTORCH_LIB_DIR@") 7 | 8 | 9 | if(UNIX) 10 | # add support for c++11 11 | add_definitions("-std=c++11") 12 | endif() 13 | 14 | 15 | find_library(CPPTORCH_LIBRARIES NAMES cpptorch PATHS ${CPPTORCH_LIB_DIR}) 16 | -------------------------------------------------------------------------------- /developer_guide.md: -------------------------------------------------------------------------------- 1 | We recommend you read through this document before you develope something new. 2 | - [Use test]( #Use test ) 3 | - [Write new test cases](#Write new test case) 4 | 5 | # Use test 6 | We provide some [cases](/test/cases) to validate our cpp modules. 7 | 8 | ## Build test 9 | During 'Install torch wrapper' step, add -DBUILD_TESTS=ON to cmake setting. 10 | 11 | For CPU version: 12 | ``` 13 | cmake -DBUILD_TESTS=ON -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch .. 14 | ``` 15 | 16 | For GPU version: 17 | ``` 18 | cmake -DBUILD_TESTS=ON -DBUILD_CUDA=ON -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch .. 19 | ``` 20 | 21 | ## Run test 22 | Go to `cpp-torch/build/` and run 'ctest' in command. 23 | You will get something like this: 24 | ``` 25 | 92% tests passed, 2 tests failed out of 24 26 | 27 | Total Test time (real) = 11.16 sec 28 | 29 | The following tests FAILED: 30 | 7 - cpptorch_ConvolutionLayers_Spatial_SpatialBatchNormalization_2.lua (Failed) 31 | 14 - cpptorch_dpnn_Decorator_1.lua (Failed) 32 | ``` 33 | 34 | # Write new test case 35 | ## Organization 36 | Each `.lua` file under [test/cases](/test/cases) is a test case. 37 | Please follow torch's [nn package document](https://github.com/torch/nn/blob/master/README.md) to organize cases as follows: 38 | 39 | ``` 40 | ├─ Containers 41 | ├─ ConvolutionLayers 42 | │ ├─ Spatial 43 | │ ├─ Temporal 44 | │ └─ Volumetric 45 | ├─ dpnn 46 | ├─ SimpleLayers 47 | │ ├─ BasicTensor 48 | │ ├─ MathTensor 49 | │ ├─ Miscellaneous 50 | │ └─ Parameterized 51 | ├─ TableLayers 52 | │ ├─ CMath 53 | │ ├─ Container 54 | │ ├─ Conversion 55 | │ ├─ Criteria 56 | │ └─ Pair 57 | └─ TransferFunctions 58 | ``` 59 | A single module can have multiple test cases, e.g.: `Linear_1.lua`, `Linear_2.lua`... 60 | 61 | ## Write a test case 62 | Check out this test cases for `nn.RELU`: 63 | ```lua 64 | require 'torch' 65 | require 'nn' 66 | torch.setdefaulttensortype('torch.FloatTensor') 67 | -- create input, output and net 68 | input = torch.Tensor(6,3,128,128) 69 | net = nn.ReLU() 70 | net:evaluate() 71 | output = net:forward(input) 72 | -- save 73 | torch.save(arg[1], input) 74 | torch.save(arg[2], output) 75 | net:clearState() 76 | torch.save(arg[3], net) 77 | ``` 78 | Test case saves input, output and net to destination denoted by the 3 command line args. 79 | 80 | Remember to re-build cpp-torch after you add new test cases. 81 | 82 | ## So what's happening? 83 | When you run `ctest` under `/build`, it performs the following actions: 84 | - run each `.lua` file in torch, save input tensor, output tensor and net as `.t7` file. 85 | - feed input tensor into net in cpp-torch, compare output tensor with saved output tensor. 86 | 87 | # Write torch layer(*TODO*) 88 | 89 | # Write self-defined layer(*TODO*) 90 | -------------------------------------------------------------------------------- /example/basic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | if(NOT CPPTORCH_FOUND) 5 | find_package(cpptorch REQUIRED) 6 | endif() 7 | 8 | 9 | set(demo_SRC "main.cpp") 10 | add_executable(cpptorch_demo ${demo_SRC}) 11 | target_include_directories(cpptorch_demo PRIVATE ${CPPTORCH_INCLUDE_DIR}) 12 | target_link_libraries(cpptorch_demo ${CPPTORCH_LIBRARIES}) 13 | 14 | -------------------------------------------------------------------------------- /example/basic/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | template 8 | cpptorch::Tensor read_tensor(const std::string &path) 9 | { 10 | std::ifstream fs(path, std::ios::binary); 11 | assert(fs.good()); 12 | auto obj = cpptorch::load(fs); 13 | return cpptorch::read_tensor(obj.get()); 14 | } 15 | 16 | template 17 | std::shared_ptr> read_layer(const std::string &path) 18 | { 19 | std::ifstream fs(path, std::ios::binary); 20 | assert(fs.good()); 21 | auto obj = cpptorch::load(fs); 22 | return cpptorch::read_net(obj.get()); 23 | } 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | cpptorch::Tensor x = read_tensor("x.t7"); 28 | cpptorch::Tensor y = read_tensor("y.t7"); 29 | auto net = read_layer("net.t7"); 30 | std::cout << *net << std::endl; 31 | 32 | auto yy = net->forward(x); 33 | std::cout << y << std::endl; 34 | std::cout << yy << std::endl; 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /example/basic/net.t7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuotuoxp/cpp-torch/00924a3b98351ceeed2f19f8b78853de1657f8f7/example/basic/net.t7 -------------------------------------------------------------------------------- /example/basic/x.t7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuotuoxp/cpp-torch/00924a3b98351ceeed2f19f8b78853de1657f8f7/example/basic/x.t7 -------------------------------------------------------------------------------- /example/basic/y.t7: -------------------------------------------------------------------------------- 1 | V 1torch.FloatTensorV 1torch.FloatStorage@APA -------------------------------------------------------------------------------- /example/openface/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 | 3 | PROJECT(TestOpenFace) 4 | 5 | FIND_PACKAGE(OpenCV REQUIRED) 6 | 7 | find_package(cpptorch REQUIRED) 8 | 9 | 10 | #ADD_DEFINITIONS(-mavx) 11 | ADD_DEFINITIONS(-msse4) 12 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=gnu++0x") 13 | 14 | add_executable(test_openface main.cpp) 15 | target_include_directories(test_openface PRIVATE ${CPPTORCH_INCLUDE_DIR}) 16 | target_link_libraries(test_openface ${OpenCV_LIBS} ${CPPTORCH_LIBRARIES}) 17 | -------------------------------------------------------------------------------- /example/openface/face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuotuoxp/cpp-torch/00924a3b98351ceeed2f19f8b78853de1657f8f7/example/openface/face.jpg -------------------------------------------------------------------------------- /example/openface/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | const int img_dim = 96; 8 | 9 | int main(int argc, char** argv) 10 | { 11 | // 1. load 96*96 RGB image to OpenCV Mat 12 | cv::Mat image = cv::imread("face.jpg"); 13 | if (image.channels() != 3 || image.rows != img_dim || image.cols != img_dim) 14 | { 15 | std::cerr << "invalid size" << image.channels() << " " << image.rows << " " << image.cols << " " << std::endl; 16 | return 1; 17 | } 18 | 19 | // 2. create input tensor from CV Mat 20 | cpptorch::Tensor input; 21 | input.create(); 22 | input.resize({1, 3, image.rows, image.cols}); 23 | 24 | const unsigned char *img = image.ptr(0); 25 | float *ten = input.data(); 26 | for (size_t c = 0; c < 3; c++) 27 | { 28 | for (size_t p = 0; p < img_dim * img_dim; p++) 29 | { 30 | ten[c * img_dim * img_dim + p] = (float)img[p * 3 + 2 - c] / 255; // normalize to [0,1] 31 | } 32 | } 33 | 34 | // 3. load openface network 35 | std::ifstream fs_net(std::string("nn4.small2.v1.t7"), std::ios::binary); 36 | if (!fs_net.good()) 37 | { 38 | std::cerr << "Cannot find torch module: nn4.small2.v1.t7" << std::endl 39 | << "Please download from http://openface-models.storage.cmusatyalab.org/nn4.small2.v1.t7" << std::endl; 40 | return 2; 41 | } 42 | auto obj_t = cpptorch::load(fs_net); 43 | std::shared_ptr> net = cpptorch::read_net(obj_t.get()); 44 | 45 | // 4. foward 46 | cpptorch::Tensor output = net->forward(input); 47 | 48 | // 5. print 1*128 output 49 | const float *output_ptr = output.data(); 50 | for (int i = 0; i < 128; i++) 51 | { 52 | std::cout << output_ptr[i] << " "; 53 | } 54 | std::cout << std::endl; 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /include/General.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | struct THLongStorage; 5 | struct THFloatStorage; 6 | struct THDoubleStorage; 7 | struct THLongTensor; 8 | struct THFloatTensor; 9 | struct THDoubleTensor; 10 | 11 | struct THCudaStorage; 12 | struct THCudaLongStorage; 13 | struct THCudaDoubleStorage; 14 | struct THCudaTensor; 15 | struct THCudaLongTensor; 16 | struct THCudaDoubleTensor; 17 | 18 | 19 | enum GPUFlag 20 | { 21 | GPU_None = 0, 22 | GPU_Cuda = 1, 23 | }; 24 | 25 | namespace cpptorch 26 | { 27 | template 28 | class THTrait 29 | { 30 | public: 31 | struct Tensor {}; 32 | struct Storage {}; 33 | }; 34 | 35 | template<> class THTrait 36 | { 37 | public: 38 | using Tensor = THLongTensor; 39 | using Storage = THLongStorage; 40 | }; 41 | 42 | template<> class THTrait 43 | { 44 | public: 45 | using Tensor = THFloatTensor; 46 | using Storage = THFloatStorage; 47 | }; 48 | 49 | template<> class THTrait 50 | { 51 | public: 52 | using Tensor = THDoubleTensor; 53 | using Storage = THDoubleStorage; 54 | }; 55 | 56 | template<> class THTrait 57 | { 58 | public: 59 | using Tensor = THCudaLongTensor; 60 | using Storage = THCudaLongStorage; 61 | }; 62 | 63 | template<> class THTrait 64 | { 65 | public: 66 | using Tensor = THCudaTensor; 67 | using Storage = THCudaStorage; 68 | }; 69 | 70 | template<> class THTrait 71 | { 72 | public: 73 | using Tensor = THCudaDoubleTensor; 74 | using Storage = THCudaDoubleStorage; 75 | }; 76 | } 77 | 78 | 79 | 80 | 81 | #ifdef _WIN64 82 | #ifdef API_CPPTORCH_DEF 83 | #define API __declspec(dllexport) 84 | #else 85 | #define API __declspec(dllimport) 86 | #endif 87 | #else 88 | #define API 89 | #endif 90 | -------------------------------------------------------------------------------- /include/allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "General.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace allocator 8 | { 9 | API void init(); 10 | API void cleanup(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /include/builder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "torch/Tensor.h" 3 | #include "nn/Layer.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace cpptorch 14 | { 15 | class object_table; 16 | class object_torch; 17 | class object_torch_tensor; 18 | template class object_torch_storage; 19 | 20 | enum object_type 21 | { 22 | object_type_nil, 23 | object_type_number, 24 | object_type_string, 25 | object_type_boolean, 26 | object_type_table, 27 | object_type_torch, 28 | object_type_torch_tensor, 29 | object_type_torch_storage, 30 | }; 31 | 32 | 33 | class object 34 | { 35 | public: 36 | object(object_type t = object_type_nil) : type_(t) {} 37 | 38 | virtual ~object() {} 39 | 40 | operator bool() const; 41 | operator int() const; 42 | operator long() const; 43 | operator float() const; 44 | operator double() const; 45 | 46 | inline const object_table* to_table() const; 47 | inline const object_torch* to_torch() const; 48 | inline const object_torch_tensor* to_tensor() const; 49 | template 50 | inline const object_torch_storage* to_storage() const; 51 | 52 | object_type type_; 53 | }; 54 | 55 | class object_number : public object 56 | { 57 | public: 58 | object_number() : object(object_type_number) {} 59 | 60 | double num_; 61 | }; 62 | 63 | class object_boolean : public object 64 | { 65 | public: 66 | object_boolean() : object(object_type_boolean) {} 67 | 68 | bool val_; 69 | }; 70 | 71 | class object_string : public object 72 | { 73 | public: 74 | object_string() : object(object_type_string) {} 75 | 76 | std::string str_; 77 | }; 78 | 79 | class object_table : public object 80 | { 81 | public: 82 | object_table() : object(object_type_table) {} 83 | 84 | const object* get(const std::string &key) const 85 | { 86 | auto it = kv_.find(key); 87 | return it == kv_.end() ? nullptr : it->second.get(); 88 | } 89 | const object* get(size_t key) const 90 | { 91 | return key < array_.size() ? array_[key].get() : nullptr; 92 | } 93 | 94 | std::map> kv_; 95 | std::vector> array_; 96 | }; 97 | 98 | class object_torch : public object 99 | { 100 | public: 101 | object_torch(object_type t = object_type_torch) : object(t) {} 102 | 103 | int version_; 104 | int index_; 105 | std::string class_name_; 106 | std::shared_ptr data_; 107 | }; 108 | 109 | class object_torch_tensor : public object_torch 110 | { 111 | public: 112 | object_torch_tensor() : object_torch(object_type_torch_tensor), size_(nullptr), stride_(nullptr) {} 113 | ~object_torch_tensor() 114 | { 115 | if (size_) 116 | { 117 | free(size_); 118 | size_ = nullptr; 119 | } 120 | if (stride_) 121 | { 122 | free(stride_); 123 | stride_ = nullptr; 124 | } 125 | } 126 | 127 | int dimension_; 128 | long *size_, *stride_; 129 | long storage_offset_; 130 | }; 131 | 132 | template 133 | class object_torch_storage : public object_torch 134 | { 135 | public: 136 | object_torch_storage() : object_torch(object_type_torch_storage), storage_(nullptr) {} 137 | ~object_torch_storage() 138 | { 139 | if (storage_) 140 | { 141 | free(storage_); 142 | storage_ = nullptr; 143 | } 144 | } 145 | 146 | long size_; 147 | T *storage_; 148 | }; 149 | 150 | 151 | // load module utils 152 | API std::shared_ptr load(std::istream &is); 153 | 154 | template 155 | API Tensor read_tensor(const object *obj); 156 | template 157 | API std::shared_ptr> read_net(const object *obj); 158 | } 159 | 160 | 161 | inline cpptorch::object::operator bool() const 162 | { 163 | assert(type_ == object_type_boolean); 164 | return (static_cast(this))->val_; 165 | } 166 | inline cpptorch::object::operator int() const 167 | { 168 | return (int)round((double)*this); 169 | } 170 | inline cpptorch::object::operator long() const 171 | { 172 | return (long)round((double)*this); 173 | } 174 | inline cpptorch::object::operator float() const 175 | { 176 | return (float)(double)*this; 177 | } 178 | inline cpptorch::object::operator double() const 179 | { 180 | assert(type_ == object_type_number); 181 | return (static_cast(this))->num_; 182 | } 183 | 184 | 185 | inline const cpptorch::object_table* cpptorch::object::to_table() const 186 | { 187 | assert(type_ == object_type_table); 188 | return static_cast(this); 189 | } 190 | inline const cpptorch::object_torch* cpptorch::object::to_torch() const 191 | { 192 | assert(type_ == object_type_torch); 193 | return static_cast(this); 194 | } 195 | inline const cpptorch::object_torch_tensor* cpptorch::object::to_tensor() const 196 | { 197 | assert(type_ == object_type_torch_tensor); 198 | return static_cast(this); 199 | } 200 | template 201 | inline const cpptorch::object_torch_storage* cpptorch::object::to_storage() const 202 | { 203 | assert(type_ == object_type_torch_storage); 204 | return static_cast*>(this); 205 | } 206 | -------------------------------------------------------------------------------- /include/cpptorch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "General.h" 3 | 4 | #include "torch/Storage.h" 5 | #include "torch/Tensor.h" 6 | 7 | #include "nn/Layer.h" 8 | #include "nn/Container.h" 9 | #include "nn/BatchNormalization.h" 10 | #include "nn/Concat.h" 11 | #include "nn/Decorator.h" 12 | #include "nn/DepthConcat.h" 13 | #include "nn/Inception.h" 14 | #include "nn/Linear.h" 15 | #include "nn/Add.h" 16 | #include "nn/MulConstant.h" 17 | #include "nn/Normalize.h" 18 | #include "nn/ReLU.h" 19 | #include "nn/SoftMax.h" 20 | #include "nn/LogSoftMax.h" 21 | #include "nn/Tanh.h" 22 | #include "nn/Reshape.h" 23 | #include "nn/Sequential.h" 24 | #include "nn/SpatialAveragePooling.h" 25 | #include "nn/SpatialBatchNormalization.h" 26 | #include "nn/SpatialConvolution.h" 27 | #include "nn/SpatialConvolutionMM.h" 28 | #include "nn/SpatialCrossMapLRN.h" 29 | #include "nn/SpatialLPPooling.h" 30 | #include "nn/SpatialMaxPooling.h" 31 | #include "nn/SpatialReflectionPadding.h" 32 | #include "nn/Sqrt.h" 33 | #include "nn/Square.h" 34 | #include "nn/Threshold.h" 35 | #include "nn/View.h" 36 | 37 | #include "allocator.h" 38 | #include "builder.h" 39 | -------------------------------------------------------------------------------- /include/cpptorch_cuda.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cpptorch.h" 3 | 4 | 5 | struct THCState; 6 | 7 | 8 | namespace cpptorch 9 | { 10 | typedef Tensor CudaTensor; 11 | namespace nn 12 | { 13 | typedef Layer CudaLayer; 14 | } 15 | 16 | 17 | API CudaTensor read_cuda_tensor(const object *obj); 18 | API std::shared_ptr read_cuda_net(const object *obj); 19 | 20 | API CudaTensor cpu2cuda(const Tensor &t); 21 | API Tensor cuda2cpu(const CudaTensor &t); 22 | 23 | 24 | namespace cuda 25 | { 26 | API void init(); 27 | API void free(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /include/nn/Add.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Add : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Add"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | bool scalar_; 18 | Tensor bias_, gradBias_, _ones_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/BatchNormalization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | #include "../torch/Tensor.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace nn 9 | { 10 | template 11 | class BatchNormalization : public Layer 12 | { 13 | public: 14 | BatchNormalization() : train_(false), ndim(2) {} 15 | 16 | virtual const std::string name() const override { return "nn.BatchNormalization"; } 17 | virtual Tensor forward(const Tensor &input) const override; 18 | 19 | protected: 20 | Tensor weight_, bias_, running_mean_, running_var_; 21 | bool train_; 22 | double momentum_, eps_; 23 | 24 | // expected dimension of input 25 | int ndim; 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /include/nn/Concat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Container.h" 3 | 4 | #include 5 | 6 | 7 | namespace cpptorch 8 | { 9 | namespace nn 10 | { 11 | template 12 | class Concat : public Container 13 | { 14 | public: 15 | virtual const std::string name() const override { return "nn.Concat"; } 16 | virtual Tensor forward(const Tensor &input) const override; 17 | 18 | protected: 19 | int dimension_; 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /include/nn/Container.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | #include 5 | 6 | 7 | namespace cpptorch 8 | { 9 | namespace nn 10 | { 11 | template 12 | class Container : public Layer 13 | { 14 | public: 15 | virtual const std::string name() const override { return "nn.Container"; } 16 | virtual void print(std::ostream &o, int level) const override; 17 | virtual std::shared_ptr> get(int level) { return modules_[level]; }; 18 | protected: 19 | std::vector>> modules_; 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /include/nn/Decorator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Container.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Decorator : public Container 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Decorator"; } 14 | virtual void print(std::ostream &o, int level) const override; 15 | virtual Tensor forward(const Tensor &input) const override; 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /include/nn/DepthConcat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Container.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class DepthConcat : public Concat 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.DepthConcat"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | Tensor windowNarrow(Tensor &output, Tensor ¤tOutput, std::vector &outputSize, int offset) const; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/Inception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Decorator.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Inception : public Decorator 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Inception"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /include/nn/Layer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../General.h" 3 | #include "../torch/Tensor.h" 4 | 5 | #include 6 | 7 | 8 | namespace cpptorch 9 | { 10 | namespace nn 11 | { 12 | template 13 | class Layer 14 | { 15 | public: 16 | Layer() {} 17 | virtual ~Layer() {} 18 | 19 | virtual const std::string name() const = 0; 20 | virtual void print(std::ostream &o, int level = 0) const { o << name(); } 21 | virtual Tensor forward(const Tensor &input) const = 0; 22 | 23 | friend std::ostream& operator << (std::ostream &o, const Layer &m) 24 | { 25 | m.print(o); 26 | o << std::endl; 27 | return o; 28 | } 29 | 30 | protected: 31 | // copy constructor disallowd 32 | Layer(const Layer &other); 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /include/nn/Linear.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Linear : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Linear"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | Tensor weight_, bias_; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/LogSoftMax.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class LogSoftMax : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.LogSoftMax"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/MulConstant.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class MulConstant : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.MulConstant"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | virtual void setConstant(const T val); 16 | protected: 17 | bool inplace_; 18 | T constant_scalar_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/Normalize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Normalize : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Normalize"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | T p_, eps_; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/ReLU.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Threshold.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class ReLU : public Threshold 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.ReLU"; } 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /include/nn/Reshape.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Reshape : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Reshape"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | int nelement_; 18 | bool batch_mode_; 19 | std::vector size_, batchsize_; 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /include/nn/Sequential.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Container.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Sequential : public Container 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Sequential"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /include/nn/SoftMax.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SoftMax : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SoftMax"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/SpatialAveragePooling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialAveragePooling : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialAveragePooling"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | int kW_, kH_, dW_, dH_, padW_, padH_; 18 | bool ceil_mode_, count_include_pad_, divide_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/SpatialBatchNormalization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "BatchNormalization.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialBatchNormalization : public BatchNormalization 11 | { 12 | public: 13 | SpatialBatchNormalization() { this->ndim = 4; } 14 | 15 | virtual const std::string name() const override { return "nn.SpatialBatchNormalization"; } 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /include/nn/SpatialConvolution.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialConvolution : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialConvolution"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | Tensor weight_, bias_; 18 | int kW_, kH_, dW_, dH_, padW_, padH_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/SpatialConvolutionMM.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialConvolutionMM : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialConvolutionMM"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | Tensor weight_, bias_; 18 | int kW_, kH_, dW_, dH_, padW_, padH_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/SpatialCrossMapLRN.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialCrossMapLRN : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialCrossMapLRN"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | int size_; 18 | T alpha_, beta_, k_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/SpatialLPPooling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Sequential.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialLPPooling : public Sequential 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialLPPooling"; } 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /include/nn/SpatialMaxPooling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialMaxPooling : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialMaxPooling"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | int kW_, kH_, dW_, dH_, padW_, padH_; 18 | bool ceil_mode_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/SpatialReflectionPadding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialReflectionPadding : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.SpatialReflectionPadding"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | int pad_l_, pad_r_, pad_t_, pad_b_; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/Sqrt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Sqrt : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Sqrt"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | T eps_; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/Square.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Square : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Square"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /include/nn/Tanh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Tanh : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Tanh"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /include/nn/Threshold.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Sequential.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Threshold : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.Threshold"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | T threshold_, val_; 18 | bool inplace_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/nn/View.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class View : public Layer 11 | { 12 | public: 13 | virtual const std::string name() const override { return "nn.View"; } 14 | virtual Tensor forward(const Tensor &input) const override; 15 | 16 | protected: 17 | int num_elements_, num_input_dims_; 18 | std::vector size_; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /include/torch/Storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../General.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace cpptorch 9 | { 10 | template 11 | class API Storage 12 | { 13 | public: 14 | explicit Storage(typename THTrait::Storage *th = nullptr); 15 | template 16 | Storage(TIterator begin, TIterator end) : th_(nullptr) { unserialze(begin, end); } 17 | template 18 | Storage(const TContainer &c) : th_(nullptr) { unserialze(c); } 19 | Storage(const std::initializer_list &inputs) : th_(nullptr) { unserialze(inputs); } 20 | Storage(const T *ptr_src, long size, bool take_ownership_of_data = true) : th_(nullptr) { unserialze(ptr_src, size, take_ownership_of_data); } 21 | Storage(const Storage &other) : th_(nullptr) { *this = other; } 22 | Storage(Storage &&other) : th_(nullptr) { *this = std::move(other); } 23 | ~Storage(); 24 | 25 | Storage& operator = (const Storage &src); 26 | Storage& operator = (Storage &&src); 27 | operator typename THTrait::Storage* () const { return th_; } 28 | 29 | // getter 30 | bool valid() const { return th_ != nullptr; } 31 | int size() const; 32 | const T* data() const; 33 | T* data(); 34 | 35 | // creator 36 | void create(); 37 | // from raw ptr 38 | void unserialze(const T *ptr_src, long count, bool take_ownership_of_data = true); 39 | // from stl iterator 40 | template 41 | void unserialze(const TIterator begin, const TIterator end) 42 | { 43 | long size = (long)(end - begin); 44 | T *ptr = (T*)malloc(size * sizeof(T)); 45 | int i = 0; 46 | for (auto it = begin; it != end; it++, i++) 47 | { 48 | ptr[i] = *it; 49 | } 50 | unserialze(ptr, size); 51 | } 52 | // from stl container 53 | template 54 | void unserialze(const TContainer &c) { return unserialze(c.begin(), c.end()); } 55 | // from initializer list 56 | void unserialze(const std::initializer_list &i) { return unserialze(i.begin(), i.end()); } 57 | 58 | protected: 59 | typename THTrait::Storage *th_; 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /include/torch/Tensor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../General.h" 3 | #include "Storage.h" 4 | 5 | #include 6 | 7 | 8 | namespace cpptorch 9 | { 10 | template 11 | class API Tensor 12 | { 13 | public: 14 | explicit Tensor(bool auto_create = false); 15 | Tensor(const Tensor &other) : th_(nullptr) { *this = other; } 16 | Tensor(Tensor &&other) : th_(nullptr) { *this = std::move(other); } 17 | ~Tensor(); 18 | 19 | Tensor& operator = (const Tensor &src); 20 | Tensor& operator = (Tensor &&src); 21 | operator typename THTrait::Tensor* () const { return th_; } 22 | 23 | const std::string name() const; 24 | 25 | // creation methods 26 | void create(); 27 | void create(const Storage &storage, long storage_offset, int dim, const long *size, const long *stride = nullptr); 28 | void resize(const std::vector &size); 29 | void resize(const std::vector &size, const std::vector &stride); 30 | void resizeAs(const Tensor &src); 31 | void copy(const Tensor &src); 32 | 33 | // direct access methods 34 | bool valid() const { return th_ != nullptr; } 35 | Storage storage() const; 36 | long storageOffset() const; 37 | std::vector size() const; 38 | long size(int dim) const; 39 | std::vector stride() const; 40 | int dim() const; 41 | T* data() const; 42 | // for tensor with only ONE element, return it 43 | operator T() const; 44 | 45 | // calculative access methods 46 | bool isContiguous() const; 47 | bool isSameSizeAs(const Tensor &src) const; 48 | int nElement() const; 49 | 50 | // special access methods 51 | // tensor returned by following methods share the same storage 52 | Tensor narrow(int dimension, long firstIndex, long size) const; 53 | Tensor select(int dimension, long sliceIndex) const; 54 | template 55 | Tensor view(const TIterator begin, const TIterator end) const; 56 | template 57 | Tensor view(const TContainer &c) const { return view(c.begin(), c.end()); } 58 | Tensor view(const std::initializer_list &i) const { return view(i.begin(), i.end()); } 59 | Tensor expand(const std::vector &size) const; 60 | template 61 | Tensor expand(const TIterator begin, const TIterator end) const { return expand(std::vector(begin, end)); } 62 | template 63 | Tensor expand(const TContainer &c) const { return expand(std::vector(c.begin(), c.end())); } 64 | Tensor expand(const std::initializer_list &i) const { return expand(i.begin(), i.end()); } 65 | Tensor t() const; 66 | Tensor operator [] (const std::initializer_list &inputs) const; 67 | Tensor operator [] (long dim) const { return (*this)[{ dim }]; } 68 | 69 | // math ops (modify tensor itself) 70 | void fill(T val); 71 | void abs(); 72 | void addmv(T beta, const Tensor &t, 73 | T alpha, const Tensor &matrix, const Tensor &vector); 74 | void addmv(T alpha, const Tensor &matrix, const Tensor &vector) 75 | { 76 | addmv(1, *this, alpha, matrix, vector); 77 | } 78 | void addmm(T beta, const Tensor &t, 79 | T alpha, const Tensor &matrix1, const Tensor &matrix2); 80 | void addr(T beta, const Tensor &t, 81 | T alpha, const Tensor &vector1, const Tensor &vector2); 82 | void addr(T alpha, const Tensor &vector1, const Tensor &vector2) 83 | { 84 | addr(1, *this, alpha, vector1, vector2); 85 | } 86 | Tensor& operator += (T val); 87 | Tensor& operator += (const Tensor &other); 88 | Tensor& operator -= (const Tensor &other); 89 | Tensor& operator *= (T val); 90 | Tensor& operator *= (const Tensor &other); 91 | Tensor& operator ^= (T val); 92 | Tensor& operator ^= (const Tensor &other); 93 | 94 | // tensor math ops (donot modify tensor itself) 95 | T minall() const; 96 | T maxall() const; 97 | Tensor max(int dimension) const; 98 | Tensor sum(int dimension) const; 99 | Tensor operator + (T val) const; 100 | Tensor operator + (const Tensor &other) const; 101 | Tensor operator - (T val) const; 102 | Tensor operator - (const Tensor &other) const; 103 | Tensor operator / (const Tensor &other) const; 104 | Tensor operator ^ (T val) const; 105 | 106 | protected: 107 | typename THTrait::Tensor *th_; 108 | }; 109 | 110 | 111 | template 112 | API cpptorch::Tensor abs(const cpptorch::Tensor &t); 113 | } 114 | 115 | template 116 | API std::ostream& operator << (std::ostream &o, const cpptorch::Tensor &m); 117 | -------------------------------------------------------------------------------- /install.md: -------------------------------------------------------------------------------- 1 | We support the following platforms: 2 | - [Linux](#Linux) 3 | - [Windows](#Windows) 4 | - [MacOS](#MacOS) 5 | 6 | # Linux 7 | 8 | ## Prerequisite 9 | - [OpenBLAS](http://www.openblas.net/) 10 | - or [MKL](https://software.intel.com/en-us/intel-mkl) 11 | 12 | Our wrapper is able to run without these prerequisites, but may be very slow. 13 | 14 | For GPU version, also install 15 | - [CUDA SDK](https://developer.nvidia.com/cuda-75-downloads-archive) 16 | 17 | CUDA 7.5 is testified. Try the latest version on your own risk. 18 | 19 | ## Install torch core 20 | Next we are going to install torch's kernel libraries: TH, THNN, THC, THCUNN. Make sure all the kernel libraries are under the same folder: 21 | ``` 22 | /usr/local/cpp-torch/ (you can change it to your own location) 23 | ├─ torch7 (TH) 24 | ├─ nn (THNN) 25 | ├─ cutorch (THC, for GPU version) 26 | └─ cunn (THCUNN, for GPU version) 27 | ``` 28 | 29 | ### TH 30 | The following commands install a modified version of torch's TH library. 31 | ``` 32 | git clone https://github.com/tuotuoxp/torch7.git 33 | cd torch7 34 | mkdir build 35 | cd build 36 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch ../lib/TH 37 | make 38 | make install 39 | cd ../../ 40 | ``` 41 | Code and logic of the original library is intact. We only strip its dependency on torch. 42 | 43 | ### THNN 44 | The following commands install a modified version of torch's THNN library. 45 | ``` 46 | git clone https://github.com/tuotuoxp/nn.git 47 | cd nn 48 | mkdir build 49 | cd build 50 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch ../lib/THNN 51 | make 52 | make install 53 | cd ../../ 54 | ``` 55 | Same as previous, we only modify the dependency of the library. 56 | 57 | ### THC 58 | > If only CPU version is required, ignore this step. 59 | 60 | The following commands install a modified version of torch's THC library. 61 | ``` 62 | git clone https://github.com/tuotuoxp/cutorch.git 63 | cd cutorch 64 | mkdir build 65 | cd build 66 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch ../lib/THC 67 | make 68 | make install 69 | cd ../../ 70 | ``` 71 | Same as previous, we only modify the dependency of the library. 72 | It takes about half an hour the finish the compilpation. Please kindly ignore the warnings. 73 | 74 | ### THCUNN 75 | > If only CPU version is required, ignore this step. 76 | 77 | The following commands install a modified version of torch's THCUNN library. 78 | ``` 79 | git clone https://github.com/tuotuoxp/cunn.git 80 | cd cunn 81 | mkdir build 82 | cd build 83 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch ../lib/THCUNN 84 | make 85 | make install 86 | cd ../../ 87 | ``` 88 | Same as previous, we only modify the dependency of the library. 89 | Please kindly ignore the warnings. 90 | 91 | ## Install torch wrapper 92 | The following commands install our C++ wrapper: cpp-torch to replace the lua wrapper in original torch. 93 | 94 | Wrapper is under the same directory as core libraries. 95 | ``` 96 | /usr/local/cpp-torch/ (you can change it to your own location) 97 | ├─ torch7 (TH) 98 | ├─ nn (THNN) 99 | ├─ cutorch (THC, for GPU version) 100 | ├─ cunn (THCUNN, for GPU version) 101 | └─ cpp-torch (C++ wrapper) 102 | ``` 103 | 104 | For CPU version: 105 | ``` 106 | git clone https://github.com/tuotuoxp/cpp-torch 107 | cd cpp-torch 108 | mkdir build 109 | cd build 110 | cmake -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch .. 111 | make 112 | make install 113 | cd ../../ 114 | ``` 115 | 116 | For GPU version, set -DBUILD_CUDA=ON: 117 | ``` 118 | git clone https://github.com/tuotuoxp/cpp-torch 119 | cd cpp-torch 120 | mkdir build 121 | cd build 122 | cmake -DBUILD_CUDA=ON -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch .. 123 | make 124 | make install 125 | cd ../../ 126 | ``` 127 | 128 | ## Test it! 129 | Use the following commands to create a simple example to test your installation. 130 | ``` 131 | cd cpp-torch/example/basic 132 | cmake -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch . 133 | make 134 | ``` 135 | Run the generated demo in command line: 136 | ``` 137 | ./cpptorch_demo 138 | ``` 139 | It should yield the following output: 140 | ``` 141 | nn.Linear 142 | 143 | 12 144 | 13 145 | [torch.FloatTensor of size 2] 146 | 147 | 148 | 12 149 | 13 150 | [torch.FloatTensor of size 2] 151 | ``` 152 | 153 | 154 | # Windows 155 | ## Prerequisite 156 | - [CMake](https://cmake.org/), remember to add CMake to PATH 157 | - [Visual Studio 2015](https://www.visualstudio.com/downloads/) 158 | 159 | For GPU version, also install 160 | - [CUDA SDK](https://developer.nvidia.com/cuda-75-downloads-archive) 161 | 162 | CUDA 7.5 is testied. Try the latest version on your own risk. 163 | 164 | ## Install torch core 165 | Next we are going to install torch's kernel libraries: TH, THNN, THC, THCUNN. Make sure all the kernel libraries are under the same folder: 166 | ``` 167 | D:\cpp-torch\ (you can change it to your own place) 168 | ├─ torch7 (TH) 169 | ├─ nn (THNN) 170 | ├─ cutorch (THC, for GPU version) 171 | └─ cunn (THCUNN, for GPU version) 172 | ``` 173 | All the following commands are run using `VS2015 x64 Native Tools Command Prompt`. 174 | 175 | ### TH 176 | The following commands install a modified version of torch's TH library. 177 | ``` 178 | git clone https://github.com/tuotuoxp/torch7.git 179 | cd torch7 180 | mkdir build 181 | cd build 182 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install ..\lib\TH 183 | nmake 184 | nmake install 185 | cd ..\..\ 186 | ``` 187 | Code and logic of the original library is intact. We only strip its dependency on torch. 188 | 189 | ### THNN 190 | The following commands install a modified version of torch's THNN library. 191 | ``` 192 | git clone https://github.com/tuotuoxp/nn.git 193 | cd nn 194 | mkdir build 195 | cd build 196 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install ..\lib\THNN 197 | nmake 198 | nmake install 199 | cd ..\..\ 200 | ``` 201 | Same as previous, we only modify the dependency of the library. 202 | 203 | ### THC 204 | > If only CPU version is required, ignore this step. 205 | 206 | ``` 207 | git clone https://github.com/tuotuoxp/cutorch.git 208 | cd cutorch 209 | mkdir build 210 | cd build 211 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install ..\lib\THC 212 | nmake install 213 | cd ..\..\ 214 | ``` 215 | Same as previous, we only modify the dependency of the library. It takes about half an hour the finish the compilpation. Please kindly ignore the warnings. 216 | 217 | ### THCUNN 218 | > If only CPU version is required, ignore this step. 219 | 220 | ``` 221 | git clone https://github.com/tuotuoxp/cunn.git 222 | cd cunn 223 | mkdir build 224 | cd build 225 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install ..\lib\THCUNN 226 | nmake install 227 | cd ..\..\ 228 | ``` 229 | Same as previous, we only modify the dependency of the library. Please kindly ignore the warnings. 230 | 231 | ## Install torch wrapper 232 | The following commands install our C++ wrapper: cpp-torch to replace the lua wrapper in original torch. 233 | 234 | Wrapper is under the same directory as core libraries. 235 | ``` 236 | ├─ torch7 (TH) 237 | ├─ nn (THNN) 238 | ├─ cutorch (THC, for GPU version) 239 | ├─ cunn (THCUNN, for GPU version) 240 | └─ cpp-torch (C++ wrapper) 241 | ``` 242 | 243 | For CPU version: 244 | ``` 245 | git clone https://github.com/tuotuoxp/cpp-torch 246 | cd cpp-torch 247 | mkdir build 248 | cd build 249 | cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install .. 250 | nmake 251 | nmake install 252 | cd ..\..\ 253 | ``` 254 | 255 | For GPU version, set -DBUILD_CUDA=ON: 256 | ``` 257 | git clone https://github.com/tuotuoxp/cpp-torch 258 | cd cpp-torch 259 | mkdir build 260 | cd build 261 | cmake -DBUILD_CUDA=ON -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install .. 262 | make 263 | make install 264 | cd ..\..\ 265 | ``` 266 | 267 | ## Test it! 268 | Use the following commands to create a simple VS 2015 solution to test your installation. 269 | ``` 270 | cd cpp-torch\example\basic 271 | cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_PREFIX_PATH=..\..\..\install . 272 | ``` 273 | 274 | Copy TH.dll, THNN.dll and cpptorch.dll from `cpp-torch\install\bin\` to project's binary folder `cpp-torch\example\basic\Debug\` and `cpp-torch\example\basic\Release\`. 275 | 276 | Open solution with Visual Studio 2015, run cpptorch_demo project. It should yield the following output: 277 | ``` 278 | nn.Linear 279 | 280 | 12 281 | 13 282 | [torch.FloatTensor of size 2] 283 | 284 | 285 | 12 286 | 13 287 | [torch.FloatTensor of size 2] 288 | ``` 289 | 290 | # MacOS 291 | 292 | ## Prerequisite 293 | - [XCode](http://developer.apple.com/xcode/) 294 | 295 | ## Install 296 | Same as Linux CPU version. 297 | 298 | ## Test it! 299 | Use the following commands to create a simple XCode solution to test your installation. 300 | ``` 301 | cd cpp-torch/example/basic 302 | cmake -G "Xcode" -DCMAKE_PREFIX_PATH=../../../install . 303 | ``` 304 | 305 | Open solution with XCode, build and run cpptorch_demo project. It should yield the following output: 306 | ``` 307 | nn.Linear 308 | 309 | 12 310 | 13 311 | [torch.FloatTensor of size 2] 312 | 313 | 314 | 12 315 | 13 316 | [torch.FloatTensor of size 2] 317 | ``` 318 | -------------------------------------------------------------------------------- /install_linux.md: -------------------------------------------------------------------------------- 1 | # Linux Install (legacy) 2 | 3 | ## Prerequisite 4 | - [OpenBLAS](http://www.openblas.net/) 5 | - or [MKL](https://software.intel.com/en-us/intel-mkl) 6 | 7 | Our wrapper is able to run without these prerequisites, but may be very slow. 8 | 9 | For GPU version, also install 10 | - [CUDA SDK](https://developer.nvidia.com/cuda-75-downloads-archive) 11 | 12 | CUDA 7.5 is testified. Try the latest version on your own risk. 13 | 14 | ## Install torch core 15 | Next we are going to install torch's kernel libraries: TH, THNN, THC, THCUNN. Make sure all the kernel libraries are under the same folder: 16 | ``` 17 | /usr/local/cpp-torch/ (you can change it to your own location) 18 | ├─ torch7 (TH) 19 | ├─ nn (THNN) 20 | ├─ cutorch (THC, for GPU version) 21 | └─ cunn (THCUNN, for GPU version) 22 | ``` 23 | 24 | ### TH 25 | The following commands install a modified version of torch's TH library. 26 | ``` 27 | git clone https://github.com/tuotuoxp/torch7.git 28 | cd torch7 29 | mkdir build 30 | cd build 31 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch ../lib/TH 32 | make 33 | make install 34 | cd ../../ 35 | ``` 36 | Code and logic of the original library is intact. We only strip its dependency on torch. 37 | 38 | ### THNN 39 | The following commands install a modified version of torch's THNN library. 40 | ``` 41 | git clone https://github.com/tuotuoxp/nn.git 42 | cd nn 43 | mkdir build 44 | cd build 45 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch ../lib/THNN 46 | make 47 | make install 48 | cd ../../ 49 | ``` 50 | Same as previous, we only modify the dependency of the library. 51 | 52 | ### THC 53 | > If only CPU version is required, ignore this step. 54 | 55 | The following commands install a modified version of torch's THC library. 56 | ``` 57 | git clone https://github.com/tuotuoxp/cutorch.git 58 | cd cutorch 59 | mkdir build 60 | cd build 61 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch ../lib/THC 62 | make 63 | make install 64 | cd ../../ 65 | ``` 66 | Same as previous, we only modify the dependency of the library. 67 | It takes about half an hour the finish the compilpation. Please kindly ignore the warnings. 68 | 69 | ### THCUNN 70 | > If only CPU version is required, ignore this step. 71 | 72 | The following commands install a modified version of torch's THCUNN library. 73 | ``` 74 | git clone https://github.com/tuotuoxp/cunn.git 75 | cd cunn 76 | mkdir build 77 | cd build 78 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch ../lib/THCUNN 79 | make 80 | make install 81 | cd ../../ 82 | ``` 83 | Same as previous, we only modify the dependency of the library. 84 | Please kindly ignore the warnings. 85 | 86 | ## Install torch wrapper 87 | The following commands install our C++ wrapper: cpp-torch to replace the lua wrapper in original torch. 88 | 89 | Wrapper is under the same directory as core libraries. 90 | ``` 91 | /usr/local/cpp-torch/ (you can change it to your own location) 92 | ├─ torch7 (TH) 93 | ├─ nn (THNN) 94 | ├─ cutorch (THC, for GPU version) 95 | ├─ cunn (THCUNN, for GPU version) 96 | └─ cpp-torch (C++ wrapper) 97 | ``` 98 | 99 | For CPU version: 100 | ``` 101 | git clone https://github.com/tuotuoxp/cpp-torch 102 | cd cpp-torch 103 | mkdir build 104 | cd build 105 | cmake -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch .. 106 | make 107 | make install 108 | cd ../../ 109 | ``` 110 | 111 | For GPU version, set -DBUILD_CUDA=ON: 112 | ``` 113 | git clone https://github.com/tuotuoxp/cpp-torch 114 | cd cpp-torch 115 | mkdir build 116 | cd build 117 | cmake -DBUILD_CUDA=ON -DCMAKE_INSTALL_PREFIX=/usr/local/cpp-torch -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch .. 118 | make 119 | make install 120 | cd ../../ 121 | ``` 122 | 123 | ## Test it! 124 | Use the following commands to create a simple example to test your installation. 125 | ``` 126 | cd cpp-torch/example/basic 127 | cmake -DCMAKE_PREFIX_PATH=/usr/local/cpp-torch . 128 | make 129 | ``` 130 | Run the generated demo in command line: 131 | ``` 132 | ./cpptorch_demo 133 | ``` 134 | It should yield the following output: 135 | ``` 136 | nn.Linear 137 | 138 | 12 139 | 13 140 | [torch.FloatTensor of size 2] 141 | 142 | 143 | 12 144 | 13 145 | [torch.FloatTensor of size 2] 146 | ``` 147 | -------------------------------------------------------------------------------- /install_mac.md: -------------------------------------------------------------------------------- 1 | # MacOS Install 2 | 3 | ## Prerequisite 4 | - [XCode](http://developer.apple.com/xcode/) 5 | 6 | ## Install 7 | Same as Linux CPU version. 8 | 9 | ## Test it! 10 | Use the following commands to create a simple XCode solution to test your installation. 11 | ``` 12 | cd cpp-torch/example/basic 13 | cmake -G "Xcode" -DCMAKE_PREFIX_PATH=../../../install . 14 | ``` 15 | 16 | Open solution with XCode, build and run cpptorch_demo project. It should yield the following output: 17 | ``` 18 | nn.Linear 19 | 20 | 12 21 | 13 22 | [torch.FloatTensor of size 2] 23 | 24 | 25 | 12 26 | 13 27 | [torch.FloatTensor of size 2] 28 | ``` 29 | -------------------------------------------------------------------------------- /install_windows.md: -------------------------------------------------------------------------------- 1 | # Windows Install 2 | ## Prerequisite 3 | - [CMake](https://cmake.org/), remember to add CMake to PATH 4 | - [Visual Studio 2015](https://www.visualstudio.com/downloads/) 5 | 6 | For GPU version, also install 7 | - [CUDA SDK](https://developer.nvidia.com/cuda-75-downloads-archive) 8 | 9 | CUDA 7.5 is testied. Try the latest version on your own risk. 10 | 11 | ## Install torch core 12 | Next we are going to install torch's kernel libraries: TH, THNN, THC, THCUNN. Make sure all the kernel libraries are under the same folder: 13 | ``` 14 | D:\cpp-torch\ (you can change it to your own place) 15 | ├─ torch7 (TH) 16 | ├─ nn (THNN) 17 | ├─ cutorch (THC, for GPU version) 18 | └─ cunn (THCUNN, for GPU version) 19 | ``` 20 | All the following commands are run using `VS2015 x64 Native Tools Command Prompt`. 21 | 22 | ### TH 23 | The following commands install a modified version of torch's TH library. 24 | ``` 25 | git clone https://github.com/tuotuoxp/torch7.git 26 | cd torch7 27 | mkdir build 28 | cd build 29 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install ..\lib\TH 30 | nmake 31 | nmake install 32 | cd ..\..\ 33 | ``` 34 | Code and logic of the original library is intact. We only strip its dependency on torch. 35 | 36 | ### THNN 37 | The following commands install a modified version of torch's THNN library. 38 | ``` 39 | git clone https://github.com/tuotuoxp/nn.git 40 | cd nn 41 | mkdir build 42 | cd build 43 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install ..\lib\THNN 44 | nmake 45 | nmake install 46 | cd ..\..\ 47 | ``` 48 | Same as previous, we only modify the dependency of the library. 49 | 50 | ### THC 51 | > If only CPU version is required, ignore this step. 52 | 53 | ``` 54 | git clone https://github.com/tuotuoxp/cutorch.git 55 | cd cutorch 56 | mkdir build 57 | cd build 58 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install ..\lib\THC 59 | nmake install 60 | cd ..\..\ 61 | ``` 62 | Same as previous, we only modify the dependency of the library. It takes about half an hour the finish the compilpation. Please kindly ignore the warnings. 63 | 64 | ### THCUNN 65 | > If only CPU version is required, ignore this step. 66 | 67 | ``` 68 | git clone https://github.com/tuotuoxp/cunn.git 69 | cd cunn 70 | mkdir build 71 | cd build 72 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install ..\lib\THCUNN 73 | nmake install 74 | cd ..\..\ 75 | ``` 76 | Same as previous, we only modify the dependency of the library. Please kindly ignore the warnings. 77 | 78 | ## Install torch wrapper 79 | The following commands install our C++ wrapper: cpp-torch to replace the lua wrapper in original torch. 80 | 81 | Wrapper is under the same directory as core libraries. 82 | ``` 83 | ├─ torch7 (TH) 84 | ├─ nn (THNN) 85 | ├─ cutorch (THC, for GPU version) 86 | ├─ cunn (THCUNN, for GPU version) 87 | └─ cpp-torch (C++ wrapper) 88 | ``` 89 | 90 | For CPU version: 91 | ``` 92 | git clone https://github.com/tuotuoxp/cpp-torch 93 | cd cpp-torch 94 | mkdir build 95 | cd build 96 | cmake -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install .. 97 | nmake 98 | nmake install 99 | cd ..\..\ 100 | ``` 101 | 102 | For GPU version, set -DBUILD_CUDA=ON: 103 | ``` 104 | git clone https://github.com/tuotuoxp/cpp-torch 105 | cd cpp-torch 106 | mkdir build 107 | cd build 108 | cmake -DBUILD_CUDA=ON -DCMAKE_INSTALL_PREFIX=..\..\install -DCMAKE_PREFIX_PATH=..\..\install .. 109 | make 110 | make install 111 | cd ..\..\ 112 | ``` 113 | 114 | ## Test it! 115 | Use the following commands to create a simple VS 2015 solution to test your installation. 116 | ``` 117 | cd cpp-torch\example\basic 118 | cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_PREFIX_PATH=..\..\..\install . 119 | ``` 120 | 121 | Copy TH.dll, THNN.dll and cpptorch.dll from `cpp-torch\install\bin\` to project's binary folder `cpp-torch\example\basic\Debug\` and `cpp-torch\example\basic\Release\`. 122 | 123 | Open solution with Visual Studio 2015, run cpptorch_demo project. It should yield the following output: 124 | ``` 125 | nn.Linear 126 | 127 | 12 128 | 13 129 | [torch.FloatTensor of size 2] 130 | 131 | 132 | 12 133 | 13 134 | [torch.FloatTensor of size 2] 135 | ``` -------------------------------------------------------------------------------- /progress.md: -------------------------------------------------------------------------------- 1 | This list shows current supported modules and test status. 2 | 3 | Our purpose is to facilitate the **testing procedure**. So backward functions won't be supported in a foresable future. 4 | 5 | # nn package 6 | We follow the structure of [nn package document](https://github.com/torch/nn/blob/master/README.md). Blank cell indicates not implemented. 7 | 8 | ## Containers 9 | |module|code|CPU test|GPU test| 10 | |----|:--:|----|----| 11 | |Sequential|√||| 12 | |Parallel|||| 13 | |Concat|√||| 14 | |DepthConcat|√||| 15 | |Bottle||||| 16 | 17 | ## Transfer functions 18 | |module|code|CPU test|GPU test| 19 | |----|----|----|----| 20 | |HardTanh|||| 21 | |HardShrink|||| 22 | |SoftShrink|||| 23 | |SoftMax|√||| 24 | |SoftMin|||| 25 | |SoftPlus|||| 26 | |SoftSign|||| 27 | |LogSigmoid|||| 28 | |LogSoftMax|√||| 29 | |Sigmoid|||| 30 | |Tanh|√||| 31 | |ReLU|√||| 32 | |ReLU6|||| 33 | |PReLU|||| 34 | |RReLU|||| 35 | |ELU|||| 36 | |LeakyReLU|||| 37 | |SpatialSoftMax|||| 38 | |AddConstant|||| 39 | |MulConstant|√||| 40 | 41 | 42 | ## Simple layers 43 | ### Parameterized Modules 44 | |module|code|CPU test|GPU test| 45 | |----|----|----|----| 46 | |Linear|√||| 47 | |SparseLinear|||| 48 | |BiLinear|||| 49 | |PartialLinear|||| 50 | |Add|√||| 51 | |Mul|||| 52 | |CMul|||| 53 | |Euclidean|||| 54 | |WeightedEuclidean|||| 55 | |Cosine|||| 56 | 57 | 58 | ### Modules that adapt basic Tensor methods 59 | 60 | |module|code|CPU test|GPU test| 61 | |----|----|----|----| 62 | |Copy|||| 63 | |Narrow|||| 64 | |Replicate|||| 65 | |Reshape|√||| 66 | |View|√||| 67 | |Contiguous|||| 68 | |Select|||| 69 | |MaskedSelect|||| 70 | |Index|||| 71 | |Squeeze|||| 72 | |Unsqueeze|||| 73 | |Transpose|||| 74 | 75 | ### Modules that adapt mathematical Tensor methods 76 | |module|code|CPU test|GPU test| 77 | |----|----|----|----| 78 | |AddConstant|||| 79 | |MulConstant|√||| 80 | |Max|||| 81 | |Min|||| 82 | |Mean|||| 83 | |Sum|||| 84 | |Exp|||| 85 | |Log|||| 86 | |Abs|||| 87 | |Power|||| 88 | |Square|||| 89 | |Sqrt|√||| 90 | |Clamp|||| 91 | |Normalize|√||| 92 | |MM|||| 93 | 94 | ### Miscellaneous Modules 95 | |module|code|CPU test|GPU test| 96 | |----|----|----|----| 97 | |BatchNormalization|√||| 98 | |Identity|||| 99 | |Dropout|||| 100 | |SpatialDropout|||| 101 | |VolumetricDropout|||| 102 | |Padding|||| 103 | |L1Penalty|||| 104 | |GradientReversal|||| 105 | |GPU|||| 106 | |TemporalDynamicKMaxPooling|||| 107 | 108 | ## Table layers 109 | ### table Container Modules encapsulate sub-Modules 110 | |module|code|CPU test|GPU test| 111 | |----|----|----|----| 112 | |ConcatTable|||| 113 | |ParallelTable|||| 114 | |MapTable|||| 115 | 116 | ### Table Conversion Modules convert between tables and Tensors or tables 117 | |module|code|CPU test|GPU test| 118 | |----|----|----|----| 119 | |SplitTable|||| 120 | |JoinTable|||| 121 | |MixtureTable|||| 122 | |SelectTable|||| 123 | |NarrowTable|||| 124 | |FlattenTable|||| 125 | 126 | ### Pair Modules compute a measure like distance or similarity from a pair (table) of input Tensors 127 | |module|code|CPU test|GPU test| 128 | |----|----|----|----| 129 | |PairwiseDistance|||| 130 | |DotProduct|||| 131 | |CosineDistance|||| 132 | 133 | ### CMath Modules perform element-wise operations on a table of Tensors 134 | |module|code|CPU test|GPU test| 135 | |----|----|----|----| 136 | |CAddTable|||| 137 | |CSubTable|||| 138 | |CMulTable|||| 139 | |CDivTable|||| 140 | |CMaxTable|||| 141 | |CMinTable|||| 142 | 143 | ### Table of Criteria 144 | |module|code|CPU test|GPU test| 145 | |----|----|----|----| 146 | |CriterionTable|||| 147 | 148 | ## Convolution layers 149 | ### Temporal Modules 150 | |module|code|CPU test|GPU test| 151 | |----|----|----|----| 152 | |TemporalConvolution|||| 153 | |TemporalSubSampling|||| 154 | |TemporalMaxPooling|||| 155 | |LookupTable|||| 156 | 157 | ### Spatial Modules 158 | |module|code|CPU test|GPU test| 159 | |----|----|----|----| 160 | |SpatialConvolution|√||| 161 | |SpatialConvolutionMM|√||| 162 | |SpatialFullConvolution|||| 163 | |SpatialDilatedConvolution|||| 164 | |SpatialConvolutionLocal|||| 165 | |SpatialSubSampling|||| 166 | |SpatialMaxPooling|√||| 167 | |SpatialDilatedMaxPooling|||| 168 | |SpatialFractionalMaxPooling|||| 169 | |SpatialAveragePooling|√||| 170 | |SpatialAdaptvieMaxPooling|||| 171 | |SpatialMaxUnpooling|||| 172 | |SpatialLPPooling|√||| 173 | |SpatialConvolutionMap|||| 174 | |SpatialZeroPadding|||| 175 | |SpatialReflectionPadding|√||| 176 | |SpatialReplicationPadding|||| 177 | |SpatialSubtractiveNormalization|||| 178 | |SpatialCrossMapLRN|√||| 179 | |SpatialBatchNormalization|√||| 180 | |SpatialUpsamplingNearest|||| 181 | |SpatialUpsamplingBilinear|||| 182 | 183 | ### Volumetric Modules 184 | |module|code|CPU test|GPU test| 185 | |----|----|----|----| 186 | |VolumetricConvolution|||| 187 | |VolumetricFullConvolution|||| 188 | |VolumetricDilatedConvolution|||| 189 | |VolumetricMaxPooling|||| 190 | |VolumetricDilatedMaxPooling|||| 191 | |VolumetricAveragePooling|||| 192 | |VolumetricMaxUnpooling|||| 193 | |VolumetricReplicationPadding|||| 194 | 195 | # dpnn package 196 | Currently only [Inception](https://github.com/Element-Research/dpnn#nn.Inception) and [Decorator](https://github.com/Element-Research/dpnn#nn.Decorator) module are supported. 197 | -------------------------------------------------------------------------------- /src/allocator.cpp: -------------------------------------------------------------------------------- 1 | #include "allocator.h" 2 | #include "../include/allocator.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | struct MemoryAllocation 11 | { 12 | void *buf; 13 | long capacity; 14 | }; 15 | 16 | 17 | class MemoryCache 18 | { 19 | public: 20 | MemoryCache() 21 | { 22 | memory_block_info_.reserve(1024); 23 | free_block_info_index_.reserve(1024); 24 | available_memory_block_.reserve(1024); 25 | } 26 | 27 | int requestIndex(long init_size) 28 | { 29 | MemoryAllocation m = { nullptr, init_size }; 30 | if (!free_block_info_index_.empty()) 31 | { 32 | int idx = *free_block_info_index_.rbegin(); 33 | free_block_info_index_.pop_back(); 34 | memory_block_info_[idx] = m; 35 | return idx + 1; 36 | } 37 | memory_block_info_.push_back(m); 38 | return (int)memory_block_info_.size(); 39 | } 40 | 41 | 42 | void* alloc(int index, long size) 43 | { 44 | MemoryAllocation &m = memory_block_info_[index]; 45 | for (size_t i = 0; i < available_memory_block_.size(); i++) 46 | { 47 | MemoryAllocation &findm = available_memory_block_[i]; 48 | if (findm.capacity >= size) 49 | { 50 | m.capacity = findm.capacity; 51 | void *buf = findm.buf; 52 | available_memory_block_.erase(available_memory_block_.begin() + i); 53 | return buf; 54 | } 55 | } 56 | // cannot find proper memory block 57 | m.capacity = size; 58 | return malloc(size); 59 | } 60 | 61 | void* re_alloc(int index, void *ptr, long new_size) 62 | { 63 | MemoryAllocation &m = memory_block_info_[index]; 64 | for (size_t i = 0; i < available_memory_block_.size(); i++) 65 | { 66 | MemoryAllocation &findm = available_memory_block_[i]; 67 | if (findm.capacity >= new_size) 68 | { 69 | // cache old 70 | if (m.capacity > 0) 71 | { 72 | m.buf = ptr; 73 | insertIntoAvailableMemory(m); 74 | } 75 | 76 | // assign new 77 | m.capacity = findm.capacity; 78 | void *buf = findm.buf; 79 | available_memory_block_.erase(available_memory_block_.begin() + i); 80 | return buf; 81 | } 82 | } 83 | // cannot find proper memory block 84 | m.capacity = new_size; 85 | return realloc(ptr, new_size); 86 | } 87 | 88 | void release(int index, void *buf) 89 | { 90 | MemoryAllocation &m = memory_block_info_[index]; 91 | if (m.capacity > 0) 92 | { 93 | m.buf = buf; 94 | insertIntoAvailableMemory(m); 95 | } 96 | free_block_info_index_.push_back(index); 97 | } 98 | 99 | void cleanup() 100 | { 101 | for (auto it = available_memory_block_.begin(); it != available_memory_block_.end(); it++) 102 | { 103 | free(it->buf); 104 | } 105 | available_memory_block_.clear(); 106 | } 107 | 108 | private: 109 | void insertIntoAvailableMemory(MemoryAllocation ma) 110 | { 111 | for (int i = (int)available_memory_block_.size(); i >= 1; i--) 112 | { 113 | if (available_memory_block_[i - 1].capacity <= ma.capacity) 114 | { 115 | available_memory_block_.insert(available_memory_block_.begin() + i, ma); 116 | return; 117 | } 118 | } 119 | available_memory_block_.insert(available_memory_block_.begin(), ma); 120 | } 121 | 122 | // memory block info (include using and unused) 123 | std::vector memory_block_info_; 124 | 125 | // empty holes in memory_block_info_ 126 | std::vector free_block_info_index_; 127 | 128 | // memory blocks which can be reused 129 | std::vector available_memory_block_; 130 | }; 131 | 132 | static MemoryCache *cache_ = nullptr; 133 | 134 | 135 | static void* mallocWrapper(void* ctx, ptrdiff_t size) 136 | { 137 | if (size == 0) 138 | { 139 | return nullptr; 140 | } 141 | if (cache_ && ctx) 142 | { 143 | return cache_->alloc((int)(long long)ctx - 1, (long)size); 144 | } 145 | return malloc(size); 146 | } 147 | 148 | static void* reallocWrapper(void* ctx, void* ptr, ptrdiff_t size) 149 | { 150 | if (cache_ && ctx) 151 | { 152 | return cache_->re_alloc((int)(long long)ctx - 1, ptr, (long)size); 153 | } 154 | return realloc(ptr, size); 155 | } 156 | 157 | static void freeWrapper(void* ctx, void* ptr) 158 | { 159 | if (cache_ && ctx) 160 | { 161 | cache_->release((int)(long long)ctx - 1, ptr); 162 | } 163 | else 164 | { 165 | free(ptr); 166 | } 167 | } 168 | 169 | ////////////////////////////////////////////////////////////////////////// 170 | 171 | void cpptorch::allocator::init() 172 | { 173 | cache_ = new MemoryCache(); 174 | } 175 | 176 | void cpptorch::allocator::cleanup() 177 | { 178 | if (cache_) 179 | { 180 | cache_->cleanup(); 181 | delete cache_; 182 | cache_ = nullptr; 183 | } 184 | } 185 | 186 | ////////////////////////////////////////////////////////////////////////// 187 | 188 | THAllocator* cpptorch::allocator::get() 189 | { 190 | static THAllocator allocator = 191 | { 192 | mallocWrapper, 193 | reallocWrapper, 194 | freeWrapper 195 | }; 196 | return &allocator; 197 | } 198 | 199 | void* cpptorch::allocator::requestIndex(long init_size) 200 | { 201 | if (cache_) 202 | { 203 | return (void*)(long long)cache_->requestIndex(init_size); 204 | } 205 | return nullptr; 206 | } 207 | -------------------------------------------------------------------------------- /src/allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../include/allocator.h" 3 | 4 | 5 | struct THAllocator; 6 | 7 | 8 | namespace cpptorch 9 | { 10 | namespace allocator 11 | { 12 | THAllocator* get(); 13 | void* requestIndex(long init_size); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/builder.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../include/builder.h" 3 | #include "reader.h" 4 | 5 | 6 | template 7 | cpptorch::Tensor cpptorch::read_tensor(const cpptorch::object *obj) 8 | { 9 | object_reader mb; 10 | return mb.build_tensor(obj); 11 | } 12 | 13 | template 14 | std::shared_ptr> cpptorch::read_net(const cpptorch::object *obj) 15 | { 16 | object_reader mb; 17 | return std::static_pointer_cast>(mb.build_layer(obj)); 18 | } 19 | -------------------------------------------------------------------------------- /src/develop_new_layer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | dirs=['include/nn','src/nn','src/serializer'] 4 | template_layer='LogSoftMax' 5 | new_layer='Tanh' 6 | for dir in dirs: 7 | files=[f for f in os.listdir(dir) if f.find(template_layer)>=0] 8 | for file in files: 9 | with open(os.path.join(dir,file),'r') as f: 10 | lines=f.readlines() 11 | idx=file.find(template_layer) 12 | newfile=file[:idx]+new_layer+file[idx+len(template_layer):] 13 | with open(os.path.join(dir,newfile),'w') as f: 14 | for l in lines: 15 | idx=l.find(template_layer) 16 | while idx >= 0: 17 | l=l[:idx]+new_layer+l[idx+len(template_layer):] 18 | idx=l.find(template_layer) 19 | f.write(l) 20 | files=['include/cpptorch.h','src/reader.h.inl','src/export.cpp','src_cuda/export.cpp'] 21 | for file in files: 22 | with open(file,'r') as f: 23 | lines=f.readlines() 24 | idx=file.find(template_layer) 25 | with open(file,'w') as f: 26 | for l in lines: 27 | if l.find(new_layer)<0: 28 | f.write(l) 29 | idx=l.find(template_layer) 30 | if idx>=0: 31 | while idx >= 0: 32 | l=l[:idx]+new_layer+l[idx+len(template_layer):] 33 | idx=l.find(template_layer) 34 | f.write(l) -------------------------------------------------------------------------------- /src/export.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/cpptorch.h" 2 | #include "torch/Storage.h.inl" 3 | #include "torch/Tensor.h.inl" 4 | #include "torch/TensorPrint.h.inl" 5 | 6 | 7 | template API class cpptorch::Storage; 8 | template API class cpptorch::Storage; 9 | template API class cpptorch::Storage; 10 | template API class cpptorch::Tensor; 11 | template API class cpptorch::Tensor; 12 | template API class cpptorch::Tensor; 13 | 14 | template API cpptorch::Tensor cpptorch::abs(const cpptorch::Tensor &t); 15 | template API cpptorch::Tensor cpptorch::abs(const cpptorch::Tensor &t); 16 | template API cpptorch::Tensor cpptorch::abs(const cpptorch::Tensor &t); 17 | 18 | 19 | template<> API std::ostream& operator << (std::ostream &o, const cpptorch::Tensor &m) 20 | { 21 | return TensorPrint(o, m).printTensor(m.name()) << std::endl; 22 | } 23 | template<> API std::ostream& operator << (std::ostream &o, const cpptorch::Tensor &m) 24 | { 25 | return TensorPrint(o, m).printTensor(m.name()) << std::endl; 26 | } 27 | template<> API std::ostream& operator << (std::ostream &o, const cpptorch::Tensor &m) 28 | { 29 | return TensorPrint(o, m).printTensor(m.name()) << std::endl; 30 | } 31 | 32 | 33 | #include "nn/BatchNormalization.h.inl" 34 | #include "nn/Concat.h.inl" 35 | #include "nn/Container.h.inl" 36 | #include "nn/Decorator.h.inl" 37 | #include "nn/DepthConcat.h.inl" 38 | #include "nn/Inception.h.inl" 39 | #include "nn/Linear.h.inl" 40 | #include "nn/Add.h.inl" 41 | #include "nn/MulConstant.h.inl" 42 | #include "nn/Normalize.h.inl" 43 | #include "nn/SoftMax.h.inl" 44 | #include "nn/LogSoftMax.h.inl" 45 | #include "nn/Tanh.h.inl" 46 | #include "nn/Reshape.h.inl" 47 | #include "nn/Sequential.h.inl" 48 | #include "nn/SpatialAveragePooling.h.inl" 49 | #include "nn/SpatialConvolution.h.inl" 50 | #include "nn/SpatialConvolutionMM.h.inl" 51 | #include "nn/SpatialCrossMapLRN.h.inl" 52 | #include "nn/SpatialMaxPooling.h.inl" 53 | #include "nn/SpatialReflectionPadding.h.inl" 54 | #include "nn/Sqrt.h.inl" 55 | #include "nn/Square.h.inl" 56 | #include "nn/Threshold.h.inl" 57 | #include "nn/View.h.inl" 58 | 59 | 60 | #include "builder.h.inl" 61 | #include "reader.h.inl" 62 | 63 | 64 | template API cpptorch::Tensor cpptorch::read_tensor(const object *obj); 65 | template API cpptorch::Tensor cpptorch::read_tensor(const object *obj); 66 | 67 | template API std::shared_ptr> cpptorch::read_net(const object *obj); 68 | template API std::shared_ptr> cpptorch::read_net(const object *obj); 69 | -------------------------------------------------------------------------------- /src/loader.cpp: -------------------------------------------------------------------------------- 1 | #include "loader.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #define TYPE_NIL 0 8 | #define TYPE_NUMBER 1 9 | #define TYPE_STRING 2 10 | #define TYPE_TABLE 3 11 | #define TYPE_TORCH 4 12 | #define TYPE_BOOLEAN 5 13 | #define TYPE_FUNCTION 6 14 | #define TYPE_RECUR_FUNCTION 8 15 | #define LEGACY_TYPE_RECUR_FUNCTION 7 16 | 17 | 18 | template<> 19 | long* object_loader::read_array(std::istream &is, size_t count) 20 | { 21 | long *p = (long*)malloc(count * sizeof(long long)); 22 | is.read((char*)p, count * sizeof(long long)); 23 | 24 | // in windows, sizeof(long) != sizeof(long long) 25 | if (sizeof(long) != sizeof(long long)) 26 | { 27 | long long *pll = (long long*)p; 28 | for (size_t i = 0; i < count; i++) 29 | { 30 | p[i] = (long)pll[i]; 31 | } 32 | p = (long*)realloc(p, count * sizeof(long)); 33 | } 34 | return p; 35 | } 36 | 37 | 38 | ////////////////////////////////////////////////////////////////////////// 39 | 40 | 41 | class object_torch_reader : public cpptorch::object_torch 42 | { 43 | public: 44 | void read(object_loader &extractor, std::istream &is) 45 | { 46 | data_ = extractor.read_object(is); 47 | } 48 | }; 49 | 50 | class object_torch_tensor_reader : public cpptorch::object_torch_tensor 51 | { 52 | public: 53 | void read(object_loader &extractor, std::istream &is) 54 | { 55 | dimension_ = object_loader::read_int(is); 56 | if (dimension_ > 0) 57 | { 58 | size_ = object_loader::read_array(is, dimension_); 59 | stride_ = object_loader::read_array(is, dimension_); 60 | } 61 | storage_offset_ = object_loader::read_long(is) - 1; 62 | data_ = extractor.read_object(is); 63 | } 64 | }; 65 | 66 | template 67 | class object_torch_storage_reader : public cpptorch::object_torch_storage 68 | { 69 | public: 70 | void read(object_loader &extractor, std::istream &is) 71 | { 72 | this->size_ = object_loader::read_long(is); 73 | if (this->size_ > 0) 74 | { 75 | this->storage_ = object_loader::read_array(is, this->size_); 76 | } 77 | } 78 | }; 79 | 80 | 81 | ////////////////////////////////////////////////////////////////////////// 82 | 83 | 84 | #define CREATE_BUILDER(name, T) this->factory_.insert(std::make_pair(name, std::shared_ptr(new class_factory_impl()))) 85 | 86 | 87 | object_loader::object_loader() 88 | { 89 | addClass("torch.LongTensor"); 90 | addClass("torch.FloatTensor"); 91 | addClass("torch.DoubleTensor"); 92 | addClass>("torch.LongStorage"); 93 | addClass>("torch.FloatStorage"); 94 | addClass>("torch.DoubleStorage"); 95 | addClass("torch.CudaTensor"); 96 | addClass>("torch.CudaStorage"); 97 | } 98 | 99 | std::shared_ptr object_loader::read_object(std::istream &is) 100 | { 101 | int typeidx = read_int(is); 102 | 103 | switch (typeidx) 104 | { 105 | case TYPE_NIL: 106 | return std::make_shared(); 107 | case TYPE_NUMBER: 108 | { 109 | std::shared_ptr on = std::make_shared(); 110 | on->num_ = read_double(is); 111 | return on; 112 | } 113 | case TYPE_STRING: 114 | { 115 | std::shared_ptr os = std::make_shared(); 116 | os->str_ = read_string_with_length(is); 117 | return os; 118 | } 119 | case TYPE_BOOLEAN: 120 | { 121 | std::shared_ptr ob = std::make_shared(); 122 | ob->val_ = read_int(is) == 1; 123 | return ob; 124 | } 125 | 126 | case TYPE_TABLE: 127 | case TYPE_TORCH: 128 | case TYPE_RECUR_FUNCTION: 129 | case LEGACY_TYPE_RECUR_FUNCTION: 130 | int index = read_int(is); 131 | 132 | auto it = objects_.find(index); 133 | if (it != objects_.end()) 134 | { 135 | return it->second; 136 | } 137 | 138 | if (typeidx == TYPE_TORCH) 139 | { 140 | std::string version = read_string_with_length(is); 141 | std::string class_name = version; 142 | int version_number = 0; 143 | if (version.length() > 2 && version.substr(0, 2) == "V ") 144 | { 145 | version = version.substr(2); 146 | char *p; 147 | strtol(version.c_str(), &p, 10); 148 | if (*p == 0) 149 | { 150 | version_number = atoi(version.c_str()); 151 | class_name = read_string_with_length(is); 152 | } 153 | } 154 | 155 | std::shared_ptr obj_th; 156 | auto factory = factory_.find(class_name); 157 | if (factory != factory_.end()) 158 | { 159 | obj_th = std::shared_ptr(factory->second->create(*this, is)); 160 | } 161 | else 162 | { 163 | obj_th = std::make_shared(); 164 | ((object_torch_reader*)(obj_th.get()))->read(*this, is); 165 | } 166 | obj_th->version_ = version_number; 167 | obj_th->index_ = index; 168 | obj_th->class_name_ = class_name; 169 | objects_[index] = obj_th; 170 | return obj_th; 171 | } 172 | else if (typeidx == TYPE_TABLE) 173 | { 174 | int size = read_int(is); 175 | 176 | std::shared_ptr obj_tbl = std::make_shared(); 177 | for (int i = 0; i < size; i++) 178 | { 179 | std::shared_ptr k = read_object(is); 180 | if (k->type_ == cpptorch::object_type_string) 181 | { 182 | std::shared_ptr ks = std::static_pointer_cast(k); 183 | obj_tbl->kv_[ks->str_] = read_object(is); 184 | } 185 | else if (k->type_ == cpptorch::object_type_number) 186 | { 187 | std::shared_ptr kn = std::static_pointer_cast(k); 188 | size_t idx = (size_t)round(kn->num_) - 1; 189 | obj_tbl->array_.resize(idx + 1); 190 | obj_tbl->array_[idx] = read_object(is); 191 | } 192 | else 193 | { 194 | assert(0); 195 | } 196 | } 197 | objects_[index] = obj_tbl; 198 | return obj_tbl; 199 | } 200 | break; 201 | } 202 | 203 | assert(0); 204 | return nullptr; 205 | } 206 | 207 | 208 | ////////////////////////////////////////////////////////////////////////// 209 | 210 | 211 | std::shared_ptr cpptorch::load(std::istream &is) 212 | { 213 | object_loader me; 214 | return me.read_object(is); 215 | } 216 | -------------------------------------------------------------------------------- /src/loader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../include/builder.h" 3 | 4 | #include 5 | 6 | 7 | class object_loader 8 | { 9 | public: 10 | 11 | object_loader(); 12 | 13 | std::shared_ptr read_object(std::istream &is); 14 | 15 | 16 | 17 | static int read_int(std::istream &is) 18 | { 19 | int v; 20 | read_raw(is, &v, sizeof(int)); 21 | return v; 22 | } 23 | 24 | static long read_long(std::istream &is) 25 | { 26 | long long v; 27 | read_raw(is, &v, sizeof(long long)); 28 | return (long)v; 29 | } 30 | 31 | static double read_double(std::istream &is) 32 | { 33 | double v; 34 | read_raw(is, &v, sizeof(double)); 35 | return v; 36 | } 37 | 38 | static std::string read_string_with_length(std::istream &is) 39 | { 40 | int len = read_int(is); 41 | std::string str(len, '\0'); 42 | read_raw(is, &str[0], len); 43 | return str; 44 | } 45 | 46 | static void read_raw(std::istream &is, void *buf, size_t len) 47 | { 48 | is.read((char*)buf, len); 49 | } 50 | 51 | template 52 | static T* read_array(std::istream &is, size_t count) 53 | { 54 | T *p = (T*)malloc(count * sizeof(T)); 55 | is.read((char*)p, count * sizeof(T)); 56 | return p; 57 | } 58 | 59 | protected: 60 | 61 | template 62 | inline void addClass(const std::string &name) 63 | { 64 | this->factory_.insert(std::make_pair(name, std::shared_ptr(new class_factory_impl()))); 65 | } 66 | 67 | 68 | // index -> object 69 | std::map> objects_; 70 | 71 | 72 | class class_factory_base 73 | { 74 | public: 75 | virtual cpptorch::object_torch* create(object_loader &extractor, std::istream &is) const = 0; 76 | }; 77 | 78 | template 79 | class class_factory_impl : public class_factory_base 80 | { 81 | public: 82 | virtual cpptorch::object_torch* create(object_loader &extractor, std::istream &is) const 83 | { 84 | T *t = new T(); 85 | t->read(extractor, is); 86 | return static_cast(t); 87 | } 88 | }; 89 | // class name to torch object 90 | std::map> factory_; 91 | }; 92 | 93 | -------------------------------------------------------------------------------- /src/nn/Add.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Add.h" 3 | #include 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Add::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | output.resizeAs(input); 10 | output.copy(input); 11 | if(scalar_) 12 | { 13 | cpptorch::Tensor bias(true); 14 | bias.resizeAs(input); 15 | bias.fill(bias_[0]); 16 | output+=bias; 17 | } 18 | else 19 | { 20 | if(input.isSameSizeAs(bias_)) 21 | { 22 | output+=bias_; 23 | } 24 | else 25 | { 26 | long batchSize=input.size(0); 27 | cpptorch::Tensor bias = bias_.view({-1}); 28 | cpptorch::Tensor output_ref = output.view({batchSize, -1}); 29 | if (_ones_.size(0) == batchSize) 30 | { 31 | output_ref.addr(1, _ones_, bias_); 32 | } 33 | else 34 | { 35 | cpptorch::Tensor _ones(true); 36 | _ones.resize({batchSize}); 37 | _ones.fill(1); 38 | output_ref.addr(1, _ones, bias); 39 | } 40 | 41 | } 42 | } 43 | return output; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/nn/BatchNormalization.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/BatchNormalization.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::BatchNormalization::forward(const cpptorch::Tensor &input) const 7 | { 8 | int idim = input.dim(); 9 | 10 | // check input dim 11 | asserter(idim == ndim || (idim == ndim - 1 && train_ == false)) 12 | << "only mini-batch supported (" << ndim << "D tensor), got " << idim << "D tensor instead"; 13 | int feat_dim = (idim == ndim - 1) ? 0 : 1; 14 | asserter(input.size(feat_dim) == running_mean_.nElement()) 15 | << "got " << input.size(feat_dim) << "-feature tensor, expected " << running_mean_.nElement(); 16 | 17 | // make input contiguous 18 | cpptorch::Tensor input_new; 19 | if (!input.isContiguous()) 20 | { 21 | input_new.create(); 22 | input_new.resizeAs(input); 23 | input_new.copy(input); 24 | } 25 | 26 | // make batch 27 | if (train_ == false && idim == ndim - 1) 28 | { 29 | input_new = addSingletonDimension(input_new.valid() ? input_new : input, 1); 30 | } 31 | 32 | cpptorch::Tensor save_mean(true), save_std(true); 33 | save_mean.resizeAs(running_mean_); 34 | save_std.resizeAs(running_var_); 35 | 36 | cpptorch::Tensor output(true); 37 | output.resizeAs(input_new.valid() ? input_new : input); 38 | cpptorch::th::NN::BatchNormalization_updateOutput(input_new.valid() ? input_new : input, 39 | output, weight_, bias_, running_mean_, running_var_, save_mean, save_std, train_, momentum_, eps_); 40 | return output; 41 | } 42 | -------------------------------------------------------------------------------- /src/nn/Concat.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Concat.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Concat::forward(const cpptorch::Tensor &input) const 7 | { 8 | bool first = true; 9 | std::vector outputSize; 10 | std::vector> outs; 11 | for (auto &it : this->modules_) 12 | { 13 | cpptorch::Tensor currentOutput = it->forward(input); 14 | outs.push_back(currentOutput); 15 | if (first) 16 | { 17 | outputSize = currentOutput.size(); 18 | first = false; 19 | } 20 | else 21 | { 22 | outputSize[dimension_] += currentOutput.size(dimension_); 23 | } 24 | } 25 | cpptorch::Tensor output(true); 26 | output.resize(outputSize); 27 | 28 | int offset = 0; 29 | for (size_t i = 0; i < outs.size(); i++) 30 | { 31 | cpptorch::Tensor ¤tOutput = outs[i]; 32 | output.narrow(dimension_, offset, currentOutput.size(dimension_)).copy(currentOutput); 33 | offset += currentOutput.size(dimension_); 34 | } 35 | return output; 36 | } 37 | -------------------------------------------------------------------------------- /src/nn/Container.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Container.h" 3 | 4 | #include 5 | 6 | 7 | template 8 | void cpptorch::nn::Container::print(std::ostream &o, int level) const 9 | { 10 | o << name() << " {" << std::endl; 11 | int counter = 1; 12 | for (auto &it_mod : modules_) 13 | { 14 | o << std::string(3 * (level + 1), ' ') << "(" << counter++ << ") "; 15 | it_mod->print(o, level + 1); 16 | o << std::endl; 17 | } 18 | o << std::string(3 * level, ' ') << "}"; 19 | } 20 | -------------------------------------------------------------------------------- /src/nn/Decorator.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Decorator.h" 3 | 4 | 5 | template 6 | void cpptorch::nn::Decorator::print(std::ostream &o, int level) const 7 | { 8 | o << name() << " @ "; 9 | this->modules_[0]->print(o, level); 10 | } 11 | 12 | template 13 | cpptorch::Tensor cpptorch::nn::Decorator::forward(const cpptorch::Tensor &input) const 14 | { 15 | return this->modules_[0]->forward(input); 16 | } 17 | -------------------------------------------------------------------------------- /src/nn/DepthConcat.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/DepthConcat.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::DepthConcat::forward(const cpptorch::Tensor &input) const 7 | { 8 | bool first = true; 9 | std::vector outputSize; 10 | std::vector> outs; 11 | for (auto &it : this->modules_) 12 | { 13 | cpptorch::Tensor currentOutput = it->forward(input); 14 | outs.push_back(currentOutput); 15 | if (first) 16 | { 17 | outputSize = currentOutput.size(); 18 | first = false; 19 | } 20 | else 21 | { 22 | outputSize[this->dimension_] += currentOutput.size(this->dimension_); 23 | for (int dim = 0; dim < (int)outputSize.size(); dim++) 24 | { 25 | if (dim != this->dimension_) 26 | { 27 | // take the maximum size(shouldn't change anything for batch dim) 28 | outputSize[dim] = std::max(outputSize[dim], currentOutput.size(dim)); 29 | } 30 | } 31 | } 32 | } 33 | 34 | cpptorch::Tensor output(true); 35 | output.resize(outputSize); 36 | output.fill(0); 37 | 38 | int offset = 0; 39 | for (size_t i = 0; i < outs.size(); i++) 40 | { 41 | cpptorch::Tensor ¤tOutput = outs[i]; 42 | cpptorch::Tensor outputWindow = windowNarrow(output, currentOutput, outputSize, offset); 43 | outputWindow.copy(currentOutput); 44 | offset += currentOutput.size(this->dimension_); 45 | } 46 | return output; 47 | } 48 | 49 | 50 | template 51 | cpptorch::Tensor cpptorch::nn::DepthConcat::windowNarrow(cpptorch::Tensor &output, cpptorch::Tensor ¤tOutput, 52 | std::vector &outputSize, int offset) const 53 | { 54 | cpptorch::Tensor outputWindow = output.narrow(this->dimension_, offset, currentOutput.size(this->dimension_)); 55 | for (int dim = 0; dim < (int)outputSize.size(); dim++) 56 | { 57 | long currentSize = currentOutput.size(dim); 58 | if (dim != this->dimension_ && outputSize[dim] != currentSize) 59 | { 60 | // 5x5 vs 3x3 -> start = [(5-3)/2] = 1 (1 pad each side) 61 | // 9x9 vs 5x5 -> start = [(9-5)/2] = 2 (2 pad each side) 62 | // 9x9 vs 4x4 -> start = [(9-4)/2] = 2.5 (2 pad, 3 pad) 63 | int start = (int)floor((outputSize[dim] - currentSize) / 2); 64 | outputWindow = outputWindow.narrow(dim, start, currentSize); 65 | } 66 | } 67 | return outputWindow; 68 | } 69 | -------------------------------------------------------------------------------- /src/nn/Inception.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Inception.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Inception::forward(const cpptorch::Tensor &input) const 7 | { 8 | if (input.dim() == 3) 9 | { 10 | return fromBatch(Decorator::forward(toBatch(input))); 11 | } 12 | else 13 | { 14 | return Decorator::forward(input); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/nn/Layer.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Layer.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class Layer 11 | { 12 | public: 13 | Layer() {} 14 | virtual ~Layer() {} 15 | 16 | virtual const std::string name() const = 0; 17 | virtual void print(std::ostream &o, int level = 0) const { o << name(); } 18 | virtual Tensor forward(const Tensor &input) const = 0; 19 | 20 | friend std::ostream& operator << (std::ostream &o, const Layer &m) 21 | { 22 | m.print(o); 23 | o << std::endl; 24 | return o; 25 | } 26 | 27 | protected: 28 | // copy constructor disallowd 29 | Layer(const Layer &other); 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/nn/Linear.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Linear.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Linear::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | int idim = input.dim(); 10 | if (idim == 1) 11 | { 12 | output.resize({ weight_.size(0) }); 13 | if (bias_.valid()) 14 | { 15 | output.copy(bias_); 16 | } 17 | else 18 | { 19 | output.fill(0); 20 | } 21 | output.addmv(1, weight_, input); 22 | } 23 | else if (idim == 2) 24 | { 25 | long nframe = input.size(0); 26 | long nElement = output.nElement(); 27 | output.resize({ nframe, weight_.size(0) }); 28 | if (output.nElement() != nElement) 29 | { 30 | output.fill(0); 31 | } 32 | 33 | cpptorch::Tensor addBuffer(true); 34 | addBuffer.resize({ nframe }); 35 | addBuffer.fill(1); 36 | output.addmm(0, output, 1, input, weight_.t()); 37 | if (bias_.valid()) 38 | { 39 | output.addr(1, addBuffer, bias_); 40 | } 41 | } 42 | else 43 | { 44 | assert(0 && "input must be vector or matrix"); 45 | } 46 | return output; 47 | } 48 | -------------------------------------------------------------------------------- /src/nn/LogSoftMax.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/LogSoftMax.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::LogSoftMax::forward(const cpptorch::Tensor &input) const 7 | { 8 | 9 | cpptorch::Tensor output(true); 10 | cpptorch::th::NN::LogSoftMax_updateOutput(input, output); 11 | return output; 12 | } 13 | -------------------------------------------------------------------------------- /src/nn/MulConstant.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/MulConstant.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::MulConstant::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | output.resizeAs(input); 10 | output.copy(input); 11 | output *= constant_scalar_; 12 | return output; 13 | } 14 | 15 | template 16 | void cpptorch::nn::MulConstant::setConstant(const T val) { 17 | constant_scalar_ = val; 18 | } -------------------------------------------------------------------------------- /src/nn/Normalize.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Normalize.h" 3 | 4 | #include 5 | 6 | 7 | template 8 | cpptorch::Tensor cpptorch::nn::Normalize::forward(const cpptorch::Tensor &input) const 9 | { 10 | assert(input.dim() <= 2 && "only 1d layer supported"); 11 | std::vector input_size = input.size(); 12 | cpptorch::Tensor input_new; 13 | if (input.dim() == 1) 14 | { 15 | input_new = input.view({ 1, -1 }); 16 | } 17 | else 18 | { 19 | input_new = input; 20 | } 21 | 22 | cpptorch::Tensor norm; 23 | if (std::isinf((double)p_)) 24 | { 25 | // specialization for the infinity norm 26 | norm = cpptorch::abs(input_new).max(1) + eps_; 27 | } 28 | else 29 | { 30 | cpptorch::Tensor buffer; 31 | if ((int)p_ % 2 != 0) 32 | { 33 | buffer = cpptorch::abs(input_new) ^ p_; 34 | } 35 | else 36 | { 37 | buffer = input_new ^ p_; 38 | } 39 | norm = (buffer.sum(1) + eps_) ^ (1 / p_); 40 | } 41 | 42 | cpptorch::Tensor output; 43 | output = (input / norm.view({ -1, 1 }).expand(input_new.size())).view(input_size); 44 | return output; 45 | } 46 | -------------------------------------------------------------------------------- /src/nn/Reshape.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Reshape.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Reshape::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor input_new; 9 | if (!input.isContiguous()) 10 | { 11 | input_new.create(); 12 | input_new.resizeAs(input); 13 | input_new.copy(input); 14 | } 15 | else 16 | { 17 | input_new = input; 18 | } 19 | cpptorch::Tensor output; 20 | if (!batch_mode_ && input_new.nElement() == nelement_ && input_new.size(0) != 1) 21 | { 22 | output = input_new.view(size_); 23 | } 24 | else 25 | { 26 | std::vector batchsize = batchsize_; 27 | batchsize[0] = input_new.size(0); 28 | output = input_new.view(batchsize); 29 | } 30 | return output; 31 | } 32 | -------------------------------------------------------------------------------- /src/nn/Sequential.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Sequential.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Sequential::forward(const cpptorch::Tensor &input) const 7 | { 8 | bool first = true; 9 | cpptorch::Tensor out; 10 | for (auto &it : this->modules_) 11 | { 12 | out = it->forward(first ? input : out); 13 | first = false; 14 | } 15 | return out; 16 | } 17 | -------------------------------------------------------------------------------- /src/nn/SoftMax.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SoftMax.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::SoftMax::forward(const cpptorch::Tensor &input) const 7 | { 8 | 9 | cpptorch::Tensor output(true); 10 | cpptorch::th::NN::SoftMax_updateOutput(input, output); 11 | return output; 12 | } 13 | -------------------------------------------------------------------------------- /src/nn/SpatialAveragePooling.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialAveragePooling.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::SpatialAveragePooling::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | cpptorch::th::NN::SpatialAveragePooling_updateOutput(input, output, 10 | kW_, kH_, dW_, dH_, padW_, padH_, ceil_mode_, count_include_pad_); 11 | 12 | // for backward compatibility with saved models which are not supposed to have "divide" field 13 | if (!divide_) 14 | { 15 | output *= (T)(kW_ * kH_); 16 | } 17 | return output; 18 | } 19 | -------------------------------------------------------------------------------- /src/nn/SpatialBatchNormalization.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "BatchNormalization.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace nn 8 | { 9 | template 10 | class SpatialBatchNormalization : public BatchNormalization 11 | { 12 | public: 13 | SpatialBatchNormalization() { this->ndim = 4; } 14 | 15 | virtual const std::string name() const override { return "nn.SpatialBatchNormalization"; } 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/nn/SpatialConvolution.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialConvolution.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::SpatialConvolution::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor finput(true), fgradinput(true); 9 | cpptorch::Tensor input_new; 10 | if (!input.isContiguous()) 11 | { 12 | input_new.create(); 13 | input_new.resizeAs(input); 14 | input_new.copy(input); 15 | } 16 | 17 | cpptorch::Tensor out(true); 18 | cpptorch::th::NN::SpatialConvolutionMM_updateOutput(input_new.valid() ? input_new : input, 19 | out, weight_, bias_, finput, fgradinput, kW_, kH_, dW_, dH_, padW_, padH_); 20 | return out; 21 | } 22 | -------------------------------------------------------------------------------- /src/nn/SpatialConvolutionMM.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialConvolutionMM.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::SpatialConvolutionMM::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor finput(true), fgradinput(true); 9 | cpptorch::Tensor input_new; 10 | if (!input.isContiguous()) 11 | { 12 | input_new.create(); 13 | input_new.resizeAs(input); 14 | input_new.copy(input); 15 | } 16 | 17 | cpptorch::Tensor out(true); 18 | cpptorch::th::NN::SpatialConvolutionMM_updateOutput(input_new.valid() ? input_new : input, 19 | out, weight_, bias_, finput, fgradinput, kW_, kH_, dW_, dH_, padW_, padH_); 20 | return out; 21 | } 22 | -------------------------------------------------------------------------------- /src/nn/SpatialCrossMapLRN.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialCrossMapLRN.h" 3 | #include "util.h.inl" 4 | 5 | 6 | template 7 | cpptorch::Tensor cpptorch::nn::SpatialCrossMapLRN::forward(const cpptorch::Tensor &input) const 8 | { 9 | int idim = input.dim(); 10 | asserter(idim == 3 || idim == 4) << "Input must be 3D or 4D"; 11 | 12 | cpptorch::Tensor input_new; 13 | bool isBatch = true; 14 | if (input.dim() == 3) 15 | { 16 | input_new = cpptorch::addSingletonDimension(input, 1); 17 | isBatch = false; 18 | } 19 | else 20 | { 21 | input_new = input; 22 | } 23 | 24 | std::vector input_size = input_new.size(); 25 | long channels = input_size[1]; 26 | 27 | // storage #1 : inputSquare/squareNext/squarePrevious/output 28 | // storage #2 : scale/scaleFirst/scalePrevious/scaleCurrent 29 | cpptorch::Tensor inputSquare = input_new ^ (T)2; 30 | 31 | int prePad = (size_ - 1) / 2 + 1; 32 | int prePadCrop = prePad > channels ? channels : prePad; 33 | 34 | cpptorch::Tensor scale(true); 35 | scale.resizeAs(input_new); 36 | 37 | cpptorch::Tensor scaleFirst = scale.select(1, 0); 38 | scaleFirst.fill(0); 39 | 40 | // compute first feature map normalization 41 | for (int c = 0; c < prePadCrop; c++) 42 | { 43 | scaleFirst += inputSquare.select(1, c); 44 | } 45 | 46 | // reuse computations for next feature maps normalization 47 | // by adding the next feature map and removing the previous 48 | for (int c = 1; c < channels; c++) 49 | { 50 | cpptorch::Tensor scalePrevious = scale.select(1, c - 1); 51 | cpptorch::Tensor scaleCurrent = scale.select(1, c); 52 | scaleCurrent.copy(scalePrevious); 53 | if (c <= channels - prePad) 54 | { 55 | cpptorch::Tensor squareNext = inputSquare.select(1, c + prePad - 1); 56 | scaleCurrent += squareNext; 57 | } 58 | if (c >= prePad) 59 | { 60 | cpptorch::Tensor squarePrevious = inputSquare.select(1, c - prePad); 61 | scaleCurrent -= squarePrevious; 62 | } 63 | } 64 | 65 | scale *= alpha_ / (T)size_; 66 | scale += k_; 67 | 68 | // use scale's storage as output buffer 69 | cpptorch::Tensor output = scale; 70 | output ^= -beta_; 71 | output *= input_new; 72 | 73 | if (!isBatch) 74 | { 75 | output = output[1]; 76 | } 77 | return output; 78 | 79 | /* 80 | void THNN_CudaSpatialCrossMapLRN_updateOutput( 81 | THCState *state, 82 | THCudaTensor *input, 83 | THCudaTensor *output, 84 | THCudaTensor *scale, 85 | int size, 86 | float alpha, 87 | float beta, 88 | float k) 89 | */ 90 | } 91 | -------------------------------------------------------------------------------- /src/nn/SpatialMaxPooling.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialMaxPooling.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::SpatialMaxPooling::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | cpptorch::Tensor indices(true); 10 | cpptorch::th::NN::SpatialMaxPooling_updateOutput(input, output, indices, kW_, kH_, dW_, dH_, padW_, padH_, ceil_mode_); 11 | return output; 12 | } 13 | -------------------------------------------------------------------------------- /src/nn/SpatialReflectionPadding.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialReflectionPadding.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::SpatialReflectionPadding::forward(const cpptorch::Tensor &input) const 7 | { 8 | int idim = input.dim(); 9 | assert((idim == 3 || idim == 4) && "input must be 3 or 4-dimensional"); 10 | cpptorch::Tensor output(true); 11 | cpptorch::th::NN::SpatialReflectionPadding_updateOutput(input, output, pad_l_, pad_r_, pad_t_, pad_b_); 12 | return output; 13 | } 14 | -------------------------------------------------------------------------------- /src/nn/Sqrt.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Sqrt.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Sqrt::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | cpptorch::th::NN::Sqrt_updateOutput(input, output, eps_); 10 | return output; 11 | } 12 | -------------------------------------------------------------------------------- /src/nn/Square.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Square.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Square::forward(const cpptorch::Tensor &input) const 7 | { 8 | cpptorch::Tensor output(true); 9 | cpptorch::th::NN::Square_updateOutput(input, output); 10 | return output; 11 | } 12 | -------------------------------------------------------------------------------- /src/nn/Tanh.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Tanh.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Tanh::forward(const cpptorch::Tensor &input) const 7 | { 8 | 9 | cpptorch::Tensor output(true); 10 | cpptorch::th::NN::Tanh_updateOutput(input, output); 11 | return output; 12 | } 13 | -------------------------------------------------------------------------------- /src/nn/Threshold.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Threshold.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::Threshold::forward(const cpptorch::Tensor &input) const 7 | { 8 | // validate parameters 9 | if (inplace_) 10 | { 11 | asserter(val_ <= threshold_) << "in-place processing requires value (" << val_ << ") not exceed threshold (" << threshold_ << ")"; 12 | } 13 | 14 | cpptorch::Tensor output(true); 15 | cpptorch::th::NN::Threshold_updateOutput(input, output, threshold_, val_, inplace_); 16 | return output; 17 | } 18 | -------------------------------------------------------------------------------- /src/nn/View.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/View.h" 3 | 4 | 5 | template 6 | cpptorch::Tensor cpptorch::nn::View::forward(const cpptorch::Tensor &input) const 7 | { 8 | int ind = input.dim(); 9 | std::vector isz = input.size(); 10 | int maxdim = num_input_dims_ > 0 ? num_input_dims_ : ind; 11 | int ine = 1; 12 | for (int i = ind - 1; i >= ind - maxdim; i--) 13 | { 14 | ine *= isz[i]; 15 | } 16 | 17 | assert(ine % num_elements_ == 0 && "input view (input) and desired view (size_) do not match"); 18 | 19 | // the remainder is either the batch... 20 | int bsz = ine / num_elements_; 21 | // ... or the missing size dim 22 | for (int i = 0; i < (int)size_.size(); i++) 23 | { 24 | if (size_[i] == -1) 25 | { 26 | bsz = 1; 27 | break; 28 | } 29 | } 30 | 31 | // for dim over maxdim, it is definitively the batch 32 | for (int i = ind - maxdim - 1; i >= 0; i--) 33 | { 34 | bsz *= isz[i]; 35 | } 36 | 37 | // special card 38 | cpptorch::Tensor output; 39 | if (bsz == 1 && (num_elements_ <= 0 || ind <= num_elements_)) 40 | { 41 | output = input.view(size_); 42 | } 43 | else 44 | { 45 | std::vector sz; 46 | sz.push_back(bsz); 47 | sz.insert(sz.end(), size_.begin(), size_.end()); 48 | output = input.view(sz); 49 | } 50 | return output; 51 | } 52 | -------------------------------------------------------------------------------- /src/nn/util.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/torch/Tensor.h" 3 | #include "../util.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | /** 9 | * add a dimension to an existing tensor 10 | * 11 | * before: axbxcxd 12 | * after: dim = 0 : 1xaxbxcxd 13 | * dim = 2 : axbx1xcxd 14 | */ 15 | template 16 | cpptorch::Tensor addSingletonDimension(const cpptorch::Tensor &t, int dim) 17 | { 18 | int tdim = t.dim(); 19 | asserter(dim > 0 && dim <= tdim + 1) 20 | << "invalid dimension: " << dim << ". Tensor is of " << tdim << " dimensions."; 21 | 22 | std::vector tsize = t.size(), tstride = t.stride(); 23 | std::vector size, stride; 24 | size.resize(tdim + 1); 25 | stride.resize(tdim + 1); 26 | 27 | for (int d = 0; d < dim - 1; d++) 28 | { 29 | size[d] = tsize[d]; 30 | stride[d] = tstride[d]; 31 | } 32 | size[dim] = 1; 33 | stride[dim] = 1; 34 | for (int d = dim + 1; d < tdim + 1; d++) 35 | { 36 | size[d] = tsize[d - 1]; 37 | stride[d] = tstride[d - 1]; 38 | } 39 | cpptorch::Tensor view; 40 | view.create(t.storage(), t.storageOffset(), (int)size.size(), &size[0], &stride[0]); 41 | return view; 42 | } 43 | 44 | /** 45 | * add a dimension to the first of an existing tensor 46 | * 47 | * before: axbxc 48 | * after: 1xaxbxc 49 | */ 50 | template 51 | cpptorch::Tensor toBatch(const cpptorch::Tensor &tensor) 52 | { 53 | std::vector tsize = tensor.size(); 54 | tsize.insert(tsize.begin(), 1); 55 | return tensor.view(tsize); 56 | } 57 | 58 | /** 59 | * remove the first dimension from an existing tensor 60 | * 61 | * before: 1xaxbxc 62 | * after: axbxc 63 | */ 64 | template 65 | cpptorch::Tensor fromBatch(const cpptorch::Tensor &tensor) 66 | { 67 | std::vector tsize = tensor.size(); 68 | assert(tsize[0] == 1); 69 | tsize.erase(tsize.begin()); 70 | return tensor.view(tsize); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/reader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../include/torch/Tensor.h" 3 | #include "../include/nn/Layer.h" 4 | #include "../include/builder.h" 5 | 6 | #include 7 | 8 | 9 | #define CREATE_BUILDER(name, type) this->factory_.insert(std::make_pair(name, std::shared_ptr(new class_factory_impl()))) 10 | 11 | 12 | template 13 | class object_reader 14 | { 15 | public: 16 | object_reader(); 17 | 18 | 19 | void build_storage(const cpptorch::object *obj, cpptorch::Storage &storage); 20 | void build_from_size_storage(const cpptorch::object *obj, std::vector &data); 21 | cpptorch::Tensor build_tensor(const cpptorch::object *obj); 22 | std::shared_ptr> build_layer(const cpptorch::object *obj); 23 | 24 | 25 | protected: 26 | 27 | template 28 | inline void addClass(const std::string &name) 29 | { 30 | this->factory_.insert(std::make_pair(name, std::shared_ptr(new class_factory_impl()))); 31 | } 32 | 33 | 34 | class class_factory_base 35 | { 36 | public: 37 | virtual cpptorch::nn::Layer* operator()(const cpptorch::object_torch *obj, object_reader *mb) const = 0; 38 | }; 39 | 40 | template 41 | class class_factory_impl : public class_factory_base 42 | { 43 | public: 44 | virtual cpptorch::nn::Layer* operator()(const cpptorch::object_torch *obj, object_reader *mb) const 45 | { 46 | TNN *t = new TNN(); 47 | t->unserialize(obj, mb); 48 | return static_cast*>(t); 49 | } 50 | }; 51 | // class name to builder 52 | std::map> factory_; 53 | 54 | // objects can be referenced more than once, when one object is refereneced the second time, 55 | // we cannot create a new nn class, we should copy the first one, 56 | // so here we keep a map for each nn object we created 57 | 58 | // Layer cannot be copied, only referenced by pointer allowed 59 | std::map>> layer_map_; 60 | 61 | // Storage can be copied, because TH is self-counted 62 | std::map> storage_map_; 63 | }; 64 | -------------------------------------------------------------------------------- /src/reader.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "reader.h" 3 | 4 | 5 | template 6 | TSerializerBase* Cast(TSerializer *c) 7 | { 8 | static_assert(std::is_base_of::value, "serializer class should derived from the nn class"); 9 | static_assert(std::is_base_of::value, "serializer class should derived from the nn class"); 10 | static_assert(std::is_base_of::value, "only casting to base class allowd"); 11 | return (TSerializerBase*)c; 12 | } 13 | 14 | #define CHECK_AND_CAST(class_name, class_base_name, T) Cast, serializer::class_base_name, nn::class_name, nn::class_base_name>(this) 15 | 16 | 17 | #include "serializer/BatchNormalization.h" 18 | #include "serializer/Concat.h" 19 | #include "serializer/Container.h" 20 | #include "serializer/Decorator.h" 21 | #include "serializer/DepthConcat.h" 22 | #include "serializer/Inception.h" 23 | #include "serializer/Linear.h" 24 | #include "serializer/Add.h" 25 | #include "serializer/MulConstant.h" 26 | #include "serializer/Normalize.h" 27 | #include "serializer/ReLU.h" 28 | #include "serializer/SoftMax.h" 29 | #include "serializer/LogSoftMax.h" 30 | #include "serializer/Tanh.h" 31 | #include "serializer/Reshape.h" 32 | #include "serializer/Sequential.h" 33 | #include "serializer/SpatialAveragePooling.h" 34 | #include "serializer/SpatialBatchNormalization.h" 35 | #include "serializer/SpatialConvolution.h" 36 | #include "serializer/SpatialConvolutionMM.h" 37 | #include "serializer/SpatialCrossMapLRN.h" 38 | #include "serializer/SpatialLPPooling.h" 39 | #include "serializer/SpatialMaxPooling.h" 40 | #include "serializer/SpatialReflectionPadding.h" 41 | #include "serializer/Sqrt.h" 42 | #include "serializer/Square.h" 43 | #include "serializer/Threshold.h" 44 | #include "serializer/View.h" 45 | 46 | 47 | template 48 | object_reader::object_reader() 49 | { 50 | addClass>("nn.BatchNormalization"); 51 | addClass>("nn.Concat"); 52 | addClass>("nn.Decorator"); 53 | addClass>("nn.DepthConcat"); 54 | addClass>("nn.Inception"); 55 | addClass>("nn.Linear"); 56 | addClass>("nn.Add"); 57 | addClass>("nn.MulConstant"); 58 | addClass>("nn.Normalize"); 59 | addClass>("nn.ReLU"); 60 | addClass>("nn.SoftMax"); 61 | addClass>("nn.LogSoftMax"); 62 | addClass>("nn.Tanh"); 63 | addClass>("nn.Reshape"); 64 | addClass>("nn.Sequential"); 65 | addClass>("nn.SpatialAveragePooling"); 66 | addClass>("nn.SpatialBatchNormalization"); 67 | addClass>("nn.SpatialConvolution"); 68 | addClass>("nn.SpatialConvolutionMM"); 69 | addClass>("nn.SpatialCrossMapLRN"); 70 | addClass>("nn.SpatialLPPooling"); 71 | addClass>("nn.SpatialMaxPooling"); 72 | addClass>("nn.SpatialReflectionPadding"); 73 | addClass>("nn.Sqrt"); 74 | addClass>("nn.Square"); 75 | addClass>("nn.Threshold"); 76 | addClass>("nn.View"); 77 | } 78 | 79 | template 80 | void object_reader::build_storage(const cpptorch::object *obj, cpptorch::Storage &storage) 81 | { 82 | auto obj_storage = const_cast*>(obj->to_storage()); 83 | auto it = storage_map_.find(obj_storage->index_); 84 | if (it == storage_map_.end()) 85 | { 86 | storage.unserialze(obj_storage->storage_, obj_storage->size_); 87 | // move the ownership of data to cpptorch::Storage 88 | obj_storage->storage_ = nullptr; 89 | storage_map_.insert(std::make_pair(obj_storage->index_, storage)); 90 | } 91 | else 92 | { 93 | storage = it->second; 94 | } 95 | } 96 | 97 | template 98 | void object_reader::build_from_size_storage(const cpptorch::object *obj, std::vector &data) 99 | { 100 | auto *obj_storage = obj->to_storage(); 101 | data.assign(obj_storage->storage_, obj_storage->storage_ + obj_storage->size_); 102 | } 103 | 104 | 105 | template 106 | cpptorch::Tensor object_reader::build_tensor(const cpptorch::object *obj) 107 | { 108 | cpptorch::Tensor out; 109 | const cpptorch::object_torch_tensor *obj_tensor = obj->to_tensor(); 110 | if (obj_tensor->dimension_ > 0) 111 | { 112 | cpptorch::Storage storage; 113 | build_storage(obj_tensor->data_.get(), storage); 114 | out.create(storage, (long)obj_tensor->storage_offset_, obj_tensor->dimension_, obj_tensor->size_, obj_tensor->stride_); 115 | } 116 | return std::move(out); 117 | } 118 | 119 | template 120 | std::shared_ptr> object_reader::build_layer(const cpptorch::object *obj) 121 | { 122 | const cpptorch::object_torch *obj_torch = obj->to_torch(); 123 | auto it = layer_map_.find(obj_torch->index_); 124 | if (it == layer_map_.end()) 125 | { 126 | auto factory = factory_.find(obj_torch->class_name_); 127 | if (factory != factory_.end()) 128 | { 129 | std::shared_ptr> l((*factory->second)(obj_torch, this)); 130 | layer_map_.insert(std::make_pair(obj_torch->index_, l)); 131 | return l; 132 | } 133 | assert(0); 134 | return nullptr; 135 | } 136 | else 137 | { 138 | return it->second; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/serializer/Add.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Add.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Add : public nn::Add 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | if(obj_tbl->get("scalar")) 17 | this->scalar_ = obj_tbl->get("scalar"); 18 | else 19 | this->scalar_ = false; 20 | this->bias_ = mb->build_tensor(obj_tbl->get("bias")); 21 | this->gradBias_ = mb->build_tensor(obj_tbl->get("gradBias")); 22 | this->_ones_ = mb->build_tensor(obj_tbl->get("_ones")); 23 | } 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/serializer/BatchNormalization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/BatchNormalization.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class BatchNormalization : public nn::BatchNormalization 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->weight_ = mb->build_tensor(obj_tbl->get("weight")); 17 | this->bias_ = mb->build_tensor(obj_tbl->get("bias")); 18 | this->running_mean_ = mb->build_tensor(obj_tbl->get("running_mean")); 19 | this->momentum_ = *obj_tbl->get("momentum"); 20 | this->eps_ = *obj_tbl->get("eps"); 21 | this->train_ = false; 22 | if (obj->version_ < 2) 23 | { 24 | cpptorch::Tensor running_std = mb->build_tensor(obj_tbl->get("running_std")); 25 | this->running_var_ = (running_std ^ (T)-2) + (T)-this->eps_; 26 | } 27 | else 28 | { 29 | this->running_var_ = mb->build_tensor(obj_tbl->get("running_var")); 30 | } 31 | } 32 | }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/serializer/Concat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Concat.h" 3 | #include "Container.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class Concat : public nn::Concat 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(Concat, Container, T)->unserialize(obj, mb); 17 | const object_table *obj_tbl = obj->data_->to_table(); 18 | this->dimension_ = (int)*obj_tbl->get("dimension") - 1; 19 | } 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/serializer/Container.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Container.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Container : public nn::Container 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | const object_table *obj_modules = obj_tbl->get("modules")->to_table(); 17 | for (auto &it_obj : obj_modules->array_) 18 | { 19 | this->modules_.push_back(std::static_pointer_cast>(mb->build_layer(it_obj.get()))); 20 | } 21 | } 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/serializer/Decorator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Decorator.h" 3 | #include "Container.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class Decorator : public nn::Decorator 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(Decorator, Container, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/DepthConcat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/DepthConcat.h" 3 | #include "Concat.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class DepthConcat : public nn::DepthConcat 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(DepthConcat, Concat, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/Inception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Inception.h" 3 | #include "Decorator.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class Inception : public nn::Inception 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(Inception, Decorator, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/Linear.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Linear.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Linear : public nn::Linear 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->weight_ = mb->build_tensor(obj_tbl->get("weight")); 17 | this->bias_ = mb->build_tensor(obj_tbl->get("bias")); 18 | } 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/serializer/LogSoftMax.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/LogSoftMax.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class LogSoftMax : public nn::LogSoftMax 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | 16 | } 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/serializer/MulConstant.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/MulConstant.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class MulConstant : public nn::MulConstant 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->inplace_ = *obj_tbl->get("inplace"); 17 | this->constant_scalar_ = *obj_tbl->get("constant_scalar"); 18 | assert(this->inplace_ == false && "change input inplace is dangerous"); 19 | } 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/serializer/Normalize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Normalize.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Normalize : public nn::Normalize 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->p_ = *obj_tbl->get("p"); 17 | this->eps_ = *obj_tbl->get("eps"); 18 | } 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/serializer/ReLU.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/ReLU.h" 3 | #include "Threshold.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class ReLU : public nn::ReLU 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(ReLU, Threshold, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/Reshape.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Reshape.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Reshape : public nn::Reshape 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->nelement_ = *obj_tbl->get("nelement"); 17 | mb->build_from_size_storage(obj_tbl->get("size"), this->size_); 18 | mb->build_from_size_storage(obj_tbl->get("batchsize"), this->batchsize_); 19 | const object *batch_mode = obj_tbl->get("batchMode"); 20 | this->batch_mode_ = batch_mode ? *batch_mode : false; 21 | } 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/serializer/Sequential.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Sequential.h" 3 | #include "Container.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class Sequential : public nn::Sequential 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(Sequential, Container, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/SoftMax.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SoftMax.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SoftMax : public nn::SoftMax 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | 16 | } 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/serializer/SpatialAveragePooling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialAveragePooling.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SpatialAveragePooling : public nn::SpatialAveragePooling 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->kW_ = *obj_tbl->get("kW"); 17 | this->kH_ = *obj_tbl->get("kH"); 18 | this->dW_ = *obj_tbl->get("dW"); 19 | this->dH_ = *obj_tbl->get("dH"); 20 | 21 | const object *ceil_mode = obj_tbl->get("ceil_mode"); 22 | if (ceil_mode == nullptr) 23 | { 24 | // backward compatible 25 | this->ceil_mode_ = false; 26 | this->count_include_pad_ = true; 27 | this->padW_ = 0; 28 | this->padH_ = 0; 29 | } 30 | else 31 | { 32 | this->ceil_mode_ = *ceil_mode; 33 | this->count_include_pad_ = *obj_tbl->get("count_include_pad"); 34 | this->padW_ = *obj_tbl->get("padW"); 35 | this->padH_ = *obj_tbl->get("padH"); 36 | } 37 | 38 | const object *divide = obj_tbl->get("divide"); 39 | this->divide_ = divide ? *divide : false; 40 | } 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/serializer/SpatialBatchNormalization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialBatchNormalization.h" 3 | #include "BatchNormalization.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class SpatialBatchNormalization : public nn::SpatialBatchNormalization 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(SpatialBatchNormalization, BatchNormalization, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/SpatialConvolution.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialConvolution.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SpatialConvolution : public nn::SpatialConvolution 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | 17 | this->weight_ = mb->build_tensor(obj_tbl->get("weight")); 18 | this->bias_ = mb->build_tensor(obj_tbl->get("bias")); 19 | 20 | this->kW_ = *obj_tbl->get("kW"); 21 | this->kH_ = *obj_tbl->get("kH"); 22 | this->dW_ = *obj_tbl->get("dW"); 23 | this->dH_ = *obj_tbl->get("dH"); 24 | 25 | const object *padding_obj = obj_tbl->get("padding"); 26 | if (padding_obj) 27 | { 28 | // backward compatibility 29 | this->padH_ = this->padW_ = *padding_obj; 30 | } 31 | else 32 | { 33 | this->padW_ = *obj_tbl->get("padW"); 34 | this->padH_ = *obj_tbl->get("padH"); 35 | } 36 | 37 | if (this->weight_.dim() == 2) 38 | { 39 | int output_plane = *obj_tbl->get("nOutputPlane"); 40 | int input_plane = *obj_tbl->get("nInputPlane"); 41 | this->weight_ = this->weight_.view({ output_plane, input_plane, this->kH_, this->kW_ }); 42 | } 43 | } 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/serializer/SpatialConvolutionMM.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialConvolutionMM.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SpatialConvolutionMM : public nn::SpatialConvolutionMM 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | 17 | this->weight_ = mb->build_tensor(obj_tbl->get("weight")); 18 | this->bias_ = mb->build_tensor(obj_tbl->get("bias")); 19 | 20 | this->kW_ = *obj_tbl->get("kW"); 21 | this->kH_ = *obj_tbl->get("kH"); 22 | this->dW_ = *obj_tbl->get("dW"); 23 | this->dH_ = *obj_tbl->get("dH"); 24 | 25 | const object *padding_obj = obj_tbl->get("padding"); 26 | if (padding_obj) 27 | { 28 | // backward compatibility 29 | this->padH_ = this->padW_ = *padding_obj; 30 | } 31 | else 32 | { 33 | this->padW_ = *obj_tbl->get("padW"); 34 | this->padH_ = *obj_tbl->get("padH"); 35 | } 36 | } 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/serializer/SpatialCrossMapLRN.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialCrossMapLRN.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SpatialCrossMapLRN : public nn::SpatialCrossMapLRN 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->size_ = *obj_tbl->get("size"); 17 | this->alpha_ = *obj_tbl->get("alpha"); 18 | this->beta_ = *obj_tbl->get("beta"); 19 | this->k_ = *obj_tbl->get("k"); 20 | } 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/serializer/SpatialLPPooling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialLPPooling.h" 3 | #include "Sequential.h" 4 | 5 | 6 | namespace cpptorch 7 | { 8 | namespace serializer 9 | { 10 | template 11 | class SpatialLPPooling : public nn::SpatialLPPooling 12 | { 13 | public: 14 | void unserialize(const object_torch *obj, object_reader *mb) 15 | { 16 | CHECK_AND_CAST(SpatialLPPooling, Sequential, T)->unserialize(obj, mb); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/SpatialMaxPooling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialMaxPooling.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SpatialMaxPooling : public nn::SpatialMaxPooling 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->kW_ = *obj_tbl->get("kW"); 17 | this->kH_ = *obj_tbl->get("kH"); 18 | this->dW_ = *obj_tbl->get("dW"); 19 | this->dH_ = *obj_tbl->get("dH"); 20 | this->padW_ = *obj_tbl->get("padW"); 21 | this->padH_ = *obj_tbl->get("padH"); 22 | this->ceil_mode_ = *obj_tbl->get("ceil_mode"); 23 | } 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/serializer/SpatialReflectionPadding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/SpatialReflectionPadding.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class SpatialReflectionPadding : public nn::SpatialReflectionPadding 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->pad_l_ = *obj_tbl->get("pad_l"); 17 | this->pad_r_ = *obj_tbl->get("pad_r"); 18 | this->pad_t_ = *obj_tbl->get("pad_t"); 19 | this->pad_b_ = *obj_tbl->get("pad_b"); 20 | } 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/serializer/Sqrt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Sqrt.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Sqrt : public nn::Sqrt 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->eps_ = *obj_tbl->get("eps"); 17 | } 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/serializer/Square.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Square.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Square : public nn::Square 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) {} 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/serializer/Tanh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Tanh.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Tanh : public nn::Tanh 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | 16 | } 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/serializer/Threshold.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/Threshold.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class Threshold : public nn::Threshold 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->threshold_ = *obj_tbl->get("threshold"); 17 | this->val_ = *obj_tbl->get("val"); 18 | this->inplace_ = *obj_tbl->get("inplace"); 19 | } 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/serializer/View.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/nn/View.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace serializer 8 | { 9 | template 10 | class View : public nn::View 11 | { 12 | public: 13 | void unserialize(const object_torch *obj, object_reader *mb) 14 | { 15 | const object_table *obj_tbl = obj->data_->to_table(); 16 | this->num_elements_ = *obj_tbl->get("numElements"); 17 | mb->build_from_size_storage(obj_tbl->get("size"), this->size_); 18 | const object *num_input_dims = obj_tbl->get("numInputDims"); 19 | this->num_input_dims_ = num_input_dims ? *num_input_dims : -1; 20 | } 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/th_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../include/General.h" 3 | 4 | 5 | typedef void THNNState; 6 | struct THAllocator; 7 | 8 | 9 | namespace cpptorch 10 | { 11 | namespace th 12 | { 13 | template 14 | class API Storage 15 | { 16 | public: 17 | // creation methods 18 | static typename THTrait::Storage* newWithData(const T *ptr_src, long count, bool take_ownership_of_data); 19 | static void retain(typename THTrait::Storage *storage); 20 | static void release(typename THTrait::Storage *storage); 21 | 22 | // getter 23 | static T* data(typename THTrait::Storage *storage); 24 | static T data_by_index(const typename THTrait::Storage *storage, long index); 25 | static long size(const typename THTrait::Storage *storage); 26 | }; 27 | 28 | 29 | template 30 | class API Tensor 31 | { 32 | public: 33 | // creation methods 34 | static typename THTrait::Tensor* newWithStorage(typename THTrait::Storage *storage, long offset, 35 | int dim, const long *size, const long *stride); 36 | static void resize(typename THTrait::Tensor *self, 37 | typename THTrait::Storage *size, typename THTrait::Storage *stride); 38 | static void resizeAs(typename THTrait::Tensor *self, typename THTrait::Tensor *src); 39 | static void copy(typename THTrait::Tensor *self, typename THTrait::Tensor *src); 40 | static void retain(typename THTrait::Tensor *tensor); 41 | static void release(typename THTrait::Tensor *tensor); 42 | 43 | // direct access methods 44 | static typename THTrait::Storage* storage(const typename THTrait::Tensor *tensor); 45 | static long storageOffset(const typename THTrait::Tensor *tensor); 46 | static int nDimension(const typename THTrait::Tensor *tensor); 47 | static long size(const typename THTrait::Tensor *tensor, int dim); 48 | static typename THTrait::Storage* size(const typename THTrait::Tensor *tensor); 49 | static typename THTrait::Storage* stride(const typename THTrait::Tensor *tensor); 50 | static T* data(const typename THTrait::Tensor *tensor); 51 | 52 | // calculative access methods 53 | static int isContiguous(const typename THTrait::Tensor *tensor); 54 | static int isSameSizeAs(const typename THTrait::Tensor *self, const typename THTrait::Tensor *src); 55 | static long nElement(const typename THTrait::Tensor *tensor); 56 | 57 | // special access methods (shares the same storage) 58 | static void narrow(typename THTrait::Tensor *self, typename THTrait::Tensor *src, int dimension, long firstIndex, long size); 59 | static void select(typename THTrait::Tensor *self, typename THTrait::Tensor *src, int dimension, long sliceIndex); 60 | static void transpose(typename THTrait::Tensor *self, typename THTrait::Tensor *src, int dimension1, int dimension2); 61 | 62 | // maths 63 | static void fill(typename THTrait::Tensor *self, T val); 64 | static T minall(typename THTrait::Tensor *self); 65 | static T maxall(typename THTrait::Tensor *self); 66 | static void max(typename THTrait::Tensor *values, typename THTrait::Tensor *t, int dimension); 67 | static void sum(typename THTrait::Tensor *values, typename THTrait::Tensor *t, int dimension); 68 | // r = t + val 69 | static void add(typename THTrait::Tensor *r, typename THTrait::Tensor *t, 70 | T val); 71 | // r = t + val * src 72 | static void cadd(typename THTrait::Tensor *r, typename THTrait::Tensor *t, 73 | T val, typename THTrait::Tensor *src); 74 | // r = t * val 75 | static void mul(typename THTrait::Tensor *r, typename THTrait::Tensor *t, 76 | T val); 77 | // r = t * src 78 | static void cmul(typename THTrait::Tensor *r, typename THTrait::Tensor *t, typename THTrait::Tensor *src); 79 | // r = t / src 80 | static void cdiv(typename THTrait::Tensor *r, typename THTrait::Tensor *t, typename THTrait::Tensor *src); 81 | // r = t ^ val 82 | static void pow(typename THTrait::Tensor *r, typename THTrait::Tensor *t, 83 | T val); 84 | // r = pow(t, src) 85 | static void cpow(typename THTrait::Tensor *r, typename THTrait::Tensor *t, typename THTrait::Tensor *src); 86 | // r = beta * t + alpha * (mat * vec) 87 | static void addmv(typename THTrait::Tensor *r, T beta, 88 | typename THTrait::Tensor *t, T alpha, 89 | typename THTrait::Tensor *mat, typename THTrait::Tensor *vec); 90 | // r = beta * t + alpha * (mat1 * mat1) 91 | static void addmm(typename THTrait::Tensor *r, T beta, 92 | typename THTrait::Tensor *t, T alpha, 93 | typename THTrait::Tensor *mat1, typename THTrait::Tensor *mat2); 94 | // r = beta * t + alpha * (vec1 x vec2) 95 | static void addr(typename THTrait::Tensor *r, T beta, 96 | typename THTrait::Tensor *t, T alpha, 97 | typename THTrait::Tensor *vec1, typename THTrait::Tensor *vec2); 98 | // r = abs(t) 99 | static void abs(typename THTrait::Tensor *r, typename THTrait::Tensor *t); 100 | }; 101 | 102 | 103 | template 104 | class NN 105 | { 106 | public: 107 | static void BatchNormalization_updateOutput( 108 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 109 | typename THTrait::Tensor *weight, typename THTrait::Tensor *bias, 110 | typename THTrait::Tensor *running_mean, typename THTrait::Tensor *running_var, 111 | typename THTrait::Tensor *save_mean, typename THTrait::Tensor *save_std, 112 | bool train, double momentum, double eps); 113 | 114 | static void SpatialAveragePooling_updateOutput( 115 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 116 | int kW, int kH, int dW, int dH, int padW, int padH, bool ceil_mode, bool count_include_pad); 117 | 118 | static void SpatialConvolutionMM_updateOutput( 119 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 120 | typename THTrait::Tensor *weight, typename THTrait::Tensor *bias, 121 | typename THTrait::Tensor *finput, typename THTrait::Tensor *fgradInput, 122 | int kW, int kH, int dW, int dH, int padW, int padH); 123 | 124 | static void SpatialMaxPooling_updateOutput( 125 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 126 | typename THTrait::Tensor *indices, int kW, int kH, int dW, int dH, int padW, int padH, bool ceil_mode); 127 | 128 | static void SpatialReflectionPadding_updateOutput( 129 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 130 | int pad_l, int pad_r, int pad_t, int pad_b); 131 | 132 | static void Sqrt_updateOutput( 133 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 134 | T eps); 135 | 136 | static void Square_updateOutput( 137 | typename THTrait::Tensor *input, typename THTrait::Tensor *output); 138 | 139 | static void Threshold_updateOutput( 140 | typename THTrait::Tensor *input, typename THTrait::Tensor *output, 141 | T threshold, T val, 142 | bool inplace); 143 | static void SoftMax_updateOutput( 144 | typename THTrait::Tensor *input, typename THTrait::Tensor *output); 145 | static void LogSoftMax_updateOutput( 146 | typename THTrait::Tensor *input, typename THTrait::Tensor *output); 147 | static void Tanh_updateOutput( 148 | typename THTrait::Tensor *input, typename THTrait::Tensor *output); 149 | }; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/torch/Storage.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../include/torch/Storage.h" 3 | #include "../th_wrapper.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | template 11 | cpptorch::Storage::Storage(typename THTrait::Storage *th) : th_(th) 12 | { 13 | if (th_) 14 | { 15 | cpptorch::th::Storage::retain(th_); 16 | } 17 | } 18 | 19 | template 20 | cpptorch::Storage::~Storage() 21 | { 22 | if (th_) 23 | { 24 | cpptorch::th::Storage::release(th_); 25 | th_ = nullptr; 26 | } 27 | } 28 | 29 | template 30 | cpptorch::Storage& cpptorch::Storage::operator =(const cpptorch::Storage &other) 31 | { 32 | if (this != &other) { 33 | if (th_) 34 | { 35 | cpptorch::th::Storage::release(th_); 36 | th_ = nullptr; 37 | } 38 | if (other.th_) 39 | { 40 | th_ = other.th_; 41 | cpptorch::th::Storage::retain(th_); 42 | } 43 | } 44 | return *this; 45 | } 46 | 47 | template 48 | cpptorch::Storage& cpptorch::Storage::operator =(Storage &&other) 49 | { 50 | assert(this != &other); 51 | if (th_) 52 | { 53 | cpptorch::th::Storage::release(th_); 54 | th_ = nullptr; 55 | } 56 | if (other.th_) 57 | { 58 | th_ = other.th_; 59 | other.th_ = nullptr; 60 | } 61 | return *this; 62 | } 63 | 64 | template 65 | int cpptorch::Storage::size() const 66 | { 67 | return th_ ? cpptorch::th::Storage::size(th_) : 0; 68 | } 69 | 70 | template 71 | const T* cpptorch::Storage::data() const 72 | { 73 | return th_ ? cpptorch::th::Storage::data(th_) : nullptr; 74 | } 75 | 76 | template 77 | T* cpptorch::Storage::data() 78 | { 79 | return th_ ? cpptorch::th::Storage::data(th_) : nullptr; 80 | } 81 | 82 | ////////////////////////////////////////////////////////////////////////// 83 | 84 | template 85 | void cpptorch::Storage::create() 86 | { 87 | assert(th_ == nullptr); 88 | th_ = cpptorch::th::Storage::newWithData(nullptr, 0, false); 89 | } 90 | 91 | template 92 | void cpptorch::Storage::unserialze(const T *ptr_src, long count, bool take_ownership_of_data) 93 | { 94 | th_ = cpptorch::th::Storage::newWithData(ptr_src, count, take_ownership_of_data); 95 | } 96 | -------------------------------------------------------------------------------- /src/torch/TensorPrint.h.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../util.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | template 11 | class TensorPrint 12 | { 13 | public: 14 | TensorPrint(std::ostream &o, const cpptorch::Tensor &t); 15 | 16 | std::ostream& printTensor(const std::string &name); 17 | 18 | protected: 19 | void getPrintFormat(int offset, double &scale, int &len); 20 | void printMatrix(int offset, const std::string &indent); 21 | void printSubTensor(int offset, std::vector &dims); 22 | 23 | 24 | std::ostream &out_; 25 | const cpptorch::Tensor &tensor_; 26 | const cpptorch::Storage storage_cache_; 27 | const std::vector stride_cache_; 28 | const std::vector size_cache_; 29 | const T * const data_; 30 | const int offset_; 31 | }; 32 | 33 | 34 | template 35 | TensorPrint::TensorPrint(std::ostream &o, const cpptorch::Tensor &t) : out_(o), tensor_(t), 36 | storage_cache_(tensor_.storage()), 37 | stride_cache_(tensor_.stride()), 38 | size_cache_(tensor_.size()), 39 | data_(storage_cache_.data()), 40 | offset_(tensor_.storageOffset()) {} 41 | 42 | 43 | template 44 | void TensorPrint::getPrintFormat(int offset, double &scale, int &len) 45 | { 46 | scale = 1.0f; 47 | bool is_int = true; 48 | auto minval = std::numeric_limits::max(); 49 | auto maxval = std::numeric_limits::min(); 50 | 51 | int dim_x = (int)size_cache_.size() - 1; 52 | int size_y = dim_x == 0 ? 1 : size_cache_[dim_x - 1]; 53 | for (int y = 0; y < size_y; y++) 54 | { 55 | int ox = offset; 56 | for (int x = 0; x < size_cache_[dim_x]; x++) 57 | { 58 | if (is_int && data_[ox] != ceil(data_[ox])) 59 | { 60 | is_int = false; 61 | } 62 | minval = std::min(minval, template_abs(data_[ox])); 63 | maxval = std::max(maxval, template_abs(data_[ox])); 64 | ox += stride_cache_[dim_x]; 65 | } 66 | if (dim_x > 0) 67 | { 68 | offset += stride_cache_[dim_x - 1]; 69 | } 70 | } 71 | 72 | int exp_min = 1 + (minval != 0 ? (int)floor(log10(minval)) : 0); 73 | int exp_max = 1 + (maxval != 0 ? (int)floor(log10(maxval)) : 0); 74 | 75 | out_.precision(4); 76 | out_ << std::fixed; 77 | if (is_int) 78 | { 79 | if (exp_max > 9) 80 | { 81 | out_ << std::scientific; 82 | len = 11; 83 | } 84 | else 85 | { 86 | out_.precision(0); 87 | len = std::max(exp_max, 3) + 1; 88 | } 89 | } 90 | else 91 | { 92 | if (exp_max - exp_min > 4) 93 | { 94 | out_ << std::scientific; 95 | len = 11; 96 | if (std::abs(exp_max) > 99 || std::abs(exp_min) > 99) 97 | { 98 | len = len + 1; 99 | } 100 | } 101 | else 102 | { 103 | if (exp_max > 5 || exp_max < 0) 104 | { 105 | len = 7; 106 | scale = pow(10, exp_max - 1); 107 | } 108 | else 109 | { 110 | if (exp_max == 0) 111 | { 112 | len = 7; 113 | } 114 | else 115 | { 116 | len = exp_max + 6; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | 123 | 124 | template 125 | void TensorPrint::printMatrix(int offset, const std::string &indent) 126 | { 127 | double scale; 128 | int len; 129 | getPrintFormat(offset, scale, len); 130 | std::ios state(nullptr); 131 | state.copyfmt(out_); 132 | 133 | int dim_x = (int)size_cache_.size() - 1; 134 | int column_per_line = (int)floor((80 - indent.length()) / (len + 2)); 135 | bool not_enough_col = column_per_line < size_cache_[dim_x]; 136 | int y_begin = 0; 137 | std::string data_indent = not_enough_col ? (indent + " ") : indent; 138 | while (y_begin < size_cache_[dim_x]) 139 | { 140 | int y_end = std::min(y_begin + column_per_line, (int)size_cache_[dim_x]); 141 | if (not_enough_col) 142 | { 143 | if (y_begin != 0) 144 | { 145 | out_ << indent << std::endl; 146 | } 147 | out_ << indent << "Columns " << y_begin << " to " << (y_end - 1) << std::endl; 148 | } 149 | if (scale != 1) 150 | { 151 | out_.precision(8); 152 | out_.unsetf(std::ios_base::floatfield); 153 | out_ << data_indent << scale << " *" << std::endl; 154 | out_.copyfmt(state); 155 | } 156 | int offset_round = offset; 157 | for (int y = 0; y < size_cache_[dim_x - 1]; y++) 158 | { 159 | out_ << data_indent; 160 | int ox = offset_round + y_begin * stride_cache_[dim_x]; 161 | for (int x = y_begin; x < y_end; x++) 162 | { 163 | out_ << (data_[ox] >= 0 ? " " : "") << data_[ox] / scale; 164 | if (x < y_end - 1) 165 | { 166 | out_ << " "; 167 | } 168 | else 169 | { 170 | out_ << std::endl; 171 | } 172 | ox += stride_cache_[dim_x]; 173 | } 174 | offset_round += stride_cache_[dim_x - 1]; 175 | } 176 | y_begin = y_end; 177 | } 178 | } 179 | 180 | 181 | template 182 | void TensorPrint::printSubTensor(int offset, std::vector &dims) 183 | { 184 | if (dims.size() == size_cache_.size() - 2) 185 | { 186 | if (offset != offset_) 187 | { 188 | // not the first one 189 | out_ << std::endl; 190 | } 191 | out_ << "("; 192 | std::copy(dims.begin(), dims.end(), std::ostream_iterator(out_, ",")); 193 | out_ << ".,.) = " << std::endl; 194 | printMatrix(offset, " "); 195 | return; 196 | } 197 | 198 | int current_dim = (int)dims.size(); 199 | dims.push_back(0); 200 | for (int i = 0; i < (int)size_cache_[current_dim]; i++) 201 | { 202 | dims[current_dim] = i; 203 | printSubTensor(offset + i * stride_cache_[current_dim], dims); 204 | } 205 | dims.pop_back(); 206 | } 207 | 208 | 209 | template 210 | std::ostream& TensorPrint::printTensor(const std::string &name) 211 | { 212 | std::ios state_init(nullptr); 213 | state_init.copyfmt(out_); 214 | if (size_cache_.size() == 1) 215 | { 216 | double scale; 217 | int len; 218 | getPrintFormat(offset_, scale, len); 219 | std::ios state(nullptr); 220 | state.copyfmt(out_); 221 | 222 | if (scale != 1) 223 | { 224 | out_.precision(8); 225 | out_.unsetf(std::ios_base::floatfield); 226 | out_ << scale << " *" << std::endl; 227 | out_.copyfmt(state); 228 | } 229 | int ox = offset_; 230 | for (int x = 0; x < size_cache_[0]; x++) 231 | { 232 | out_ << (data_[ox] >= 0 ? " " : "") << data_[ox] / scale << std::endl; 233 | ox += stride_cache_[0]; 234 | } 235 | } 236 | else 237 | { 238 | std::vector dims; 239 | printSubTensor(offset_, dims); 240 | } 241 | out_.copyfmt(state_init); 242 | // get tensor name 243 | out_ << "[" << name << " of size " << join(size_cache_, "x") << "]" << std::endl; 244 | return out_; 245 | } 246 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | template 9 | class Joiner 10 | { 11 | public: 12 | Joiner(const TIterator begin, const TIterator end, const std::string &deli) : begin_(begin), end_(end), deli_(deli) {} 13 | 14 | friend std::ostream& operator << (std::ostream& stream, const Joiner &j) 15 | { 16 | bool first = true; 17 | for (auto it = j.begin_; it != j.end_; it++) 18 | { 19 | if (!first) 20 | { 21 | stream << j.deli_; 22 | } 23 | stream << *it; 24 | first = false; 25 | } 26 | return stream; 27 | } 28 | 29 | protected: 30 | const TIterator begin_, end_; 31 | const std::string &deli_; 32 | }; 33 | 34 | 35 | template 36 | Joiner join(const TIterator begin, const TIterator end, const std::string &deli) 37 | { 38 | return Joiner(begin, end, deli); 39 | } 40 | 41 | template 42 | Joiner join(const TContainer &c, const std::string &deli) 43 | { 44 | return Joiner(c.begin(), c.end(), deli); 45 | } 46 | 47 | 48 | ////////////////////////////////////////////////////////////////////////// 49 | 50 | 51 | class asserter 52 | { 53 | public: 54 | asserter(bool expr) : expr_(expr) {} 55 | ~asserter() { assert(expr_); } 56 | 57 | template 58 | asserter& operator << (const T &j) 59 | { 60 | if (!expr_) 61 | { 62 | std::cerr << j; 63 | } 64 | return *this; 65 | } 66 | 67 | protected: 68 | bool expr_; 69 | }; 70 | 71 | 72 | ////////////////////////////////////////////////////////////////////////// 73 | 74 | 75 | template inline 76 | T template_abs(const T& v) { return v < 0 ? -v : v; } 77 | -------------------------------------------------------------------------------- /src_cuda/cuda.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/cpptorch_cuda.h" 2 | 3 | #include 4 | 5 | 6 | static THCState *global_thc = nullptr; 7 | 8 | 9 | THCState* getCudaState() 10 | { 11 | return global_thc; 12 | } 13 | 14 | 15 | void cpptorch::cuda::init() 16 | { 17 | global_thc = THCState_alloc(); 18 | /* Enable the caching allocator unless THC_CACHING_ALLOCATOR=0 */ 19 | char* thc_caching_allocator = getenv("THC_CACHING_ALLOCATOR"); 20 | if (!thc_caching_allocator || strcmp(thc_caching_allocator, "0") != 0) { 21 | THCState_setDeviceAllocator(global_thc, THCCachingAllocator_get()); 22 | global_thc->cudaHostAllocator = &THCCachingHostAllocator; 23 | } 24 | THCudaInit(global_thc); 25 | #ifdef USE_MAGMA 26 | THCMagma_init(state); 27 | #endif 28 | } 29 | 30 | void cpptorch::cuda::free() 31 | { 32 | THCudaShutdown(global_thc); 33 | THCState_free(global_thc); 34 | //global_thc = nullptr; 35 | } 36 | -------------------------------------------------------------------------------- /src_cuda/export.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/cpptorch_cuda.h" 2 | #include "../src/torch/Storage.h.inl" 3 | #include "../src/torch/Tensor.h.inl" 4 | #include "../src/torch/TensorPrint.h.inl" 5 | #include "th_wrapper.h" 6 | 7 | 8 | template API class cpptorch::Storage; 9 | template API class cpptorch::Storage; 10 | template API class cpptorch::Storage; 11 | template API class cpptorch::Tensor; 12 | template API class cpptorch::Tensor; 13 | template API class cpptorch::Tensor; 14 | 15 | template API cpptorch::Tensor cpptorch::abs(const cpptorch::Tensor &t); 16 | template API cpptorch::Tensor cpptorch::abs(const cpptorch::Tensor &t); 17 | template API cpptorch::Tensor cpptorch::abs(const cpptorch::Tensor &t); 18 | 19 | 20 | template<> API std::ostream& operator << (std::ostream &o, const cpptorch::Tensor &t) 21 | { 22 | cpptorch::Tensor t_cpu(true); 23 | cpptorch::th::copy_cuda2cpu(t_cpu, t); 24 | return TensorPrint(o, t_cpu).printTensor(t.name()) << std::endl; 25 | } 26 | 27 | 28 | #include "../src/nn/BatchNormalization.h.inl" 29 | #include "../src/nn/Concat.h.inl" 30 | #include "../src/nn/Container.h.inl" 31 | #include "../src/nn/Decorator.h.inl" 32 | #include "../src/nn/DepthConcat.h.inl" 33 | #include "../src/nn/Inception.h.inl" 34 | #include "../src/nn/Linear.h.inl" 35 | #include "../src/nn/Add.h.inl" 36 | #include "../src/nn/MulConstant.h.inl" 37 | #include "../src/nn/Normalize.h.inl" 38 | #include "../src/nn/SoftMax.h.inl" 39 | #include "../src/nn/LogSoftMax.h.inl" 40 | #include "../src/nn/Tanh.h.inl" 41 | #include "../src/nn/Reshape.h.inl" 42 | #include "../src/nn/Sequential.h.inl" 43 | #include "../src/nn/SpatialAveragePooling.h.inl" 44 | #include "../src/nn/SpatialConvolution.h.inl" 45 | #include "../src/nn/SpatialConvolutionMM.h.inl" 46 | #include "../src/nn/SpatialCrossMapLRN.h.inl" 47 | #include "../src/nn/SpatialMaxPooling.h.inl" 48 | #include "../src/nn/SpatialReflectionPadding.h.inl" 49 | #include "../src/nn/Sqrt.h.inl" 50 | #include "../src/nn/Square.h.inl" 51 | #include "../src/nn/Threshold.h.inl" 52 | #include "../src/nn/View.h.inl" 53 | 54 | 55 | #include "../src/builder.h.inl" 56 | #include "../src/reader.h.inl" 57 | 58 | 59 | cpptorch::CudaTensor cpptorch::read_cuda_tensor(const cpptorch::object *obj) 60 | { 61 | object_reader mb; 62 | return mb.build_tensor(obj); 63 | } 64 | 65 | std::shared_ptr cpptorch::read_cuda_net(const cpptorch::object *obj) 66 | { 67 | object_reader mb; 68 | return std::static_pointer_cast>(mb.build_layer(obj)); 69 | } 70 | 71 | 72 | template API cpptorch::Tensor cpptorch::read_tensor(const object *obj); 73 | template API std::shared_ptr> cpptorch::read_net(const object *obj); 74 | 75 | 76 | cpptorch::Tensor cpptorch::cpu2cuda(const cpptorch::Tensor &t) 77 | { 78 | cpptorch::Tensor t_gpu(true); 79 | cpptorch::th::copy_cpu2cuda(t_gpu, t); 80 | return t_gpu; 81 | } 82 | 83 | cpptorch::Tensor cpptorch::cuda2cpu(const cpptorch::Tensor &t) 84 | { 85 | cpptorch::Tensor t_cpu(true); 86 | cpptorch::th::copy_cuda2cpu(t_cpu, t); 87 | return t_cpu; 88 | } 89 | -------------------------------------------------------------------------------- /src_cuda/th_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../include/General.h" 3 | 4 | 5 | namespace cpptorch 6 | { 7 | namespace th 8 | { 9 | template 10 | void copy_cpu2cuda(typename THTrait::Tensor *self, typename THTrait::Tensor *src); 11 | 12 | template 13 | void copy_cuda2cpu(typename THTrait::Tensor *self, typename THTrait::Tensor *src); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | macro(generate_test_project name src) 5 | add_executable(${name} ${src}) 6 | 7 | target_include_directories(${name} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../include") 8 | target_link_libraries(${name} cpptorch) 9 | 10 | set_target_properties(${name} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 11 | set_target_properties(${name} PROPERTIES MACOSX_RPATH TRUE) 12 | endmacro() 13 | 14 | generate_test_project(cpptorch_tester "tester.cpp") 15 | 16 | if(BUILD_CUDA) 17 | generate_test_project(cpptorch_tester_cuda "tester_cuda.cpp") 18 | target_link_libraries(cpptorch_tester_cuda cpptorch cpptorch_cuda) 19 | endif() 20 | 21 | -------------------------------------------------------------------------------- /test/cases/Containers/Concat_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,5) 7 | 8 | net = nn.Concat(2); 9 | net:add(nn.Linear(5,3)) 10 | net:add(nn.Linear(5,7)) 11 | 12 | output = net:forward(input) 13 | 14 | --print(output:size()) 15 | 16 | torch.save(arg[1], input) 17 | torch.save(arg[2], output) 18 | 19 | net:clearState() 20 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/Containers/Concat_2.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(5) 7 | 8 | net = nn.Concat(1); 9 | net:add(nn.Linear(5,3)) 10 | net:add(nn.Linear(5,7)) 11 | 12 | output = net:forward(input) 13 | 14 | --print(output:size()) 15 | 16 | torch.save(arg[1], input) 17 | torch.save(arg[2], output) 18 | 19 | net:clearState() 20 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/Containers/DepthConcat_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | inputSize = 3 7 | outputSize = 2 8 | 9 | input = torch.Tensor(inputSize, 7, 7) 10 | 11 | net = nn.DepthConcat(1); 12 | net:add(nn.SpatialConvolutionMM(inputSize, outputSize, 1, 1)) 13 | net:add(nn.SpatialConvolutionMM(inputSize, outputSize, 3, 3)) 14 | net:add(nn.SpatialConvolutionMM(inputSize, outputSize, 4, 4)) 15 | 16 | output = net:forward(input) 17 | 18 | --print(output:size()) 19 | 20 | torch.save(arg[1], input) 21 | torch.save(arg[2], output) 22 | 23 | net:clearState() 24 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/Containers/Sequental_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6, 10) 7 | 8 | net = nn.Sequential() 9 | net:add( nn.Linear(10, 25) ) 10 | net:evaluate() 11 | 12 | output = net:forward(input) 13 | 14 | --print(output:size()) 15 | 16 | torch.save(arg[1], input) 17 | torch.save(arg[2], output) 18 | 19 | net:clearState() 20 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialAveragePooling_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,128,96,96) 7 | net = nn.SpatialAveragePooling(3,3,1,1,1,1) 8 | net:evaluate() 9 | 10 | output = net:forward(input) 11 | 12 | --print(output:size()) 13 | 14 | torch.save(arg[1], input) 15 | torch.save(arg[2], output) 16 | 17 | net:clearState() 18 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialBatchNormalization_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,64,96,96) 7 | net = nn.SpatialBatchNormalization(64) 8 | net:evaluate() 9 | 10 | output = net:forward(input) 11 | 12 | --print(output:size()) 13 | 14 | torch.save(arg[1], input) 15 | torch.save(arg[2], output) 16 | 17 | net:clearState() 18 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialBatchNormalization_2.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,64,96,96) 7 | net = nn.SpatialBatchNormalization(64, nil, nil, false) 8 | net:evaluate() 9 | 10 | output = net:forward(input) 11 | 12 | --print(output:size()) 13 | 14 | torch.save(arg[1], input) 15 | torch.save(arg[2], output) 16 | 17 | net:clearState() 18 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialConvolutionMM_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(10, 64, 128, 128) 7 | 8 | net = nn.SpatialConvolutionMM(64, 128, 5,5, 1,1,1,1) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialConvolution_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(10, 64, 128, 128) 7 | 8 | net = nn.SpatialConvolution(64, 128, 5,5, 1,1,1,1) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialCrossMapLRN_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,64,96,96) 7 | net = nn.SpatialCrossMapLRN(3) 8 | net:evaluate() 9 | 10 | output = net:forward(input) 11 | 12 | --print(output:size()) 13 | 14 | torch.save(arg[1], input) 15 | torch.save(arg[2], output) 16 | 17 | net:clearState() 18 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialLPPooling_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,128,96,96) 7 | net = nn.SpatialLPPooling(128,2,3,3,1,1) 8 | net:evaluate() 9 | 10 | output = net:forward(input) 11 | 12 | --print(output:size()) 13 | 14 | torch.save(arg[1], input) 15 | torch.save(arg[2], output) 16 | 17 | net:clearState() 18 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialMaxPooling_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,128,96,96) 7 | 8 | net = nn.SpatialMaxPooling(5,5,1,1,1,1) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/ConvolutionLayers/Spatial/SpatialReflectionPadding_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(1,3,128,128) 7 | net = nn.SpatialReflectionPadding(10,9,5,7) 8 | net:evaluate() 9 | 10 | output = net:forward(input) 11 | 12 | --print(output:size()) 13 | 14 | torch.save(arg[1], input) 15 | torch.save(arg[2], output) 16 | 17 | net:clearState() 18 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/BasicTensor/Reshape_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.Reshape(12,32,128,true) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/BasicTensor/View_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(1,3,128,128) 7 | net = nn.View(3*64,2*128) 8 | 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/MathTensor/Normalize_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(1000, 512) 7 | 8 | net = nn.Normalize(2) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/MathTensor/Normalize_2.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(512) 7 | 8 | net = nn.Normalize(math.huge) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/MathTensor/Sqrt_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(1,3,128,128) + 1 7 | 8 | net = nn.Sqrt() 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/Miscellaneous/BatchNormalization_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(10, 5) 7 | 8 | net = nn.BatchNormalization(5) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/SimpleLayers/Parameterized/Linear_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,1024) 7 | 8 | net = nn.Linear(1024,256) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/TransferFunctions/Add_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.Add(6,3,128,128) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) 20 | -------------------------------------------------------------------------------- /test/cases/TransferFunctions/LogSoftMax_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.LogSoftMax() 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/TransferFunctions/MulConstant_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.MulConstant(0.5) 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/TransferFunctions/ReLU_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.ReLU() 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/TransferFunctions/SoftMax_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.SoftMax() 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/TransferFunctions/Tanh_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | 4 | torch.setdefaulttensortype('torch.FloatTensor') 5 | 6 | input = torch.Tensor(6,3,128,128) 7 | 8 | net = nn.Tanh() 9 | net:evaluate() 10 | 11 | output = net:forward(input) 12 | 13 | --print(output:size()) 14 | 15 | torch.save(arg[1], input) 16 | torch.save(arg[2], output) 17 | 18 | net:clearState() 19 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/dpnn/Decorator_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | require 'dpnn' 4 | 5 | torch.setdefaulttensortype('torch.FloatTensor') 6 | 7 | input = torch.Tensor(6,64,96,96) 8 | net = nn.SpatialBatchNormalization(64, nil, nil, false) 9 | net = nn.Decorator(net) 10 | net:evaluate() 11 | 12 | output = net:forward(input) 13 | 14 | --print(output:size()) 15 | 16 | torch.save(arg[1], input) 17 | torch.save(arg[2], output) 18 | 19 | net:clearState() 20 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/cases/dpnn/Inception_1.lua: -------------------------------------------------------------------------------- 1 | require 'torch' 2 | require 'nn' 3 | require 'dpnn' 4 | 5 | torch.setdefaulttensortype('torch.FloatTensor') 6 | 7 | input = torch.Tensor(6, 192, 96, 96) 8 | config = {inputSize = 192, 9 | kernelSize = {3, 5}, 10 | kernelStride = {1, 1}, 11 | outputSize = {128, 32}, 12 | reduceSize = {96, 16, 32, 64}, 13 | pool = nn.SpatialMaxPooling(3, 3, 1, 1, 1, 1), 14 | batchNorm = true} 15 | net = nn.Inception(config) 16 | net:evaluate() 17 | 18 | output = net:forward(input) 19 | 20 | --print(output:size()) 21 | 22 | torch.save(arg[1], input) 23 | torch.save(arg[2], output) 24 | 25 | net:clearState() 26 | torch.save(arg[3], net) -------------------------------------------------------------------------------- /test/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | 11 | static int optind = 0, opterr = 0; 12 | static char *optarg = nullptr; 13 | static int run_times = 1; 14 | static char *input = nullptr; 15 | static char *output = nullptr; 16 | static char *network = nullptr; 17 | static bool use_allocator = false; 18 | 19 | 20 | int my_getopt(int argc, char *argv[], const char *optstring) 21 | { 22 | static char *next = nullptr; 23 | if (optind == 0) 24 | next = nullptr; 25 | 26 | optarg = nullptr; 27 | 28 | if (next == nullptr || *next == '\0') 29 | { 30 | if (optind == 0) 31 | optind++; 32 | 33 | if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') 34 | { 35 | optarg = nullptr; 36 | if (optind < argc) 37 | optarg = argv[optind]; 38 | return -1; 39 | } 40 | 41 | if (strcmp(argv[optind], "--") == 0) 42 | { 43 | optind++; 44 | optarg = nullptr; 45 | if (optind < argc) 46 | optarg = argv[optind]; 47 | return -1; 48 | } 49 | 50 | next = argv[optind]; 51 | next++; // skip past - 52 | optind++; 53 | } 54 | 55 | char c = *next++; 56 | char *cp = strchr((char*)optstring, c); 57 | 58 | if (cp == nullptr || c == ':') 59 | return '?'; 60 | 61 | cp++; 62 | if (*cp == ':') 63 | { 64 | if (*next != '\0') 65 | { 66 | optarg = next; 67 | next = nullptr; 68 | } 69 | else if (optind < argc) 70 | { 71 | optarg = argv[optind]; 72 | optind++; 73 | } 74 | else 75 | { 76 | return '?'; 77 | } 78 | } 79 | 80 | return c; 81 | } 82 | 83 | 84 | void usage() 85 | { 86 | std::cerr << std::endl 87 | << "Usage: -i [input tensor] -o [output tensor] -n [network]" << std::endl 88 | << std::endl 89 | << "Additional options:" << std::endl 90 | << " -a use optimized allocator (only for cpu)" << std::endl 91 | << " -t [n] run forward operation n-times" << std::endl 92 | << std::endl; 93 | } 94 | 95 | 96 | int process_args(int argc, char *argv[]) 97 | { 98 | int c = 0; 99 | while ((c = my_getopt(argc, argv, "ai:o:n:t:")) >= 0) 100 | { 101 | switch (c) 102 | { 103 | case 'a': 104 | use_allocator = true; 105 | break; 106 | case 'i': 107 | input = optarg; 108 | break; 109 | case 'o': 110 | output = optarg; 111 | break; 112 | case 'n': 113 | network = optarg; 114 | break; 115 | case 't': 116 | run_times = atoi(optarg); 117 | break; 118 | case '?': 119 | usage(); 120 | return 10; 121 | } 122 | } 123 | 124 | if (!input || !output || !network) 125 | { 126 | usage(); 127 | return 10; 128 | } 129 | 130 | return 0; 131 | } 132 | 133 | 134 | template 135 | cpptorch::Tensor read_tensor_template(const cpptorch::object *obj); 136 | 137 | template 138 | std::shared_ptr> read_net_template(const cpptorch::object *obj); 139 | 140 | 141 | template 142 | cpptorch::Tensor read_tensor(const char *tensor) 143 | { 144 | std::ifstream fs(tensor, std::ios::binary); 145 | if (!fs.good()) 146 | { 147 | std::cerr << "Cannot read tensor from " << tensor << std::endl; 148 | exit(100); 149 | } 150 | auto obj = cpptorch::load(fs); 151 | return read_tensor_template(obj.get()); 152 | } 153 | 154 | template 155 | int test_layer() 156 | { 157 | std::ifstream fs(network, std::ios::binary); 158 | if (!fs.good()) 159 | { 160 | std::cerr << "Cannot read network from " << network << std::endl; 161 | exit(101); 162 | } 163 | auto obj = cpptorch::load(fs); 164 | auto net = read_net_template(obj.get()); 165 | cpptorch::Tensor x = read_tensor(input); 166 | cpptorch::Tensor y = read_tensor(output); 167 | 168 | auto begin = std::chrono::high_resolution_clock::now(); 169 | cpptorch::Tensor yy; 170 | for (int i = 0; i < run_times; i++) 171 | { 172 | yy = net->forward(x); 173 | } 174 | auto end = std::chrono::high_resolution_clock::now(); 175 | auto sub = cpptorch::abs(y - yy); 176 | if (sub.minall() > 1e-05 || sub.maxall() > 1e-05) 177 | { 178 | std::cout << "FAILED" << std::endl; 179 | return 1; 180 | } 181 | std::cout << std::chrono::duration_cast(end - begin).count() << "ms" << std::endl; 182 | return 0; 183 | } 184 | -------------------------------------------------------------------------------- /test/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | # $1 - the bin directory of torch 5 | # $2 - the root directory of cmake build-tree 6 | # $3 - the lua testcase 7 | 8 | input_t7=/tmp/input.t7 9 | output_t7=/tmp/output.t7 10 | net_t7=/tmp/net.t7 11 | 12 | 13 | # generate t7 files for comparison 14 | $1/luajit "$3" $input_t7 $output_t7 $net_t7 15 | if [ $? != 0 ] 16 | then 17 | echo Revoke luajit failed 18 | exit 1 19 | fi 20 | 21 | 22 | # run test 23 | $2/test/cpptorch_tester -i $input_t7 -o $output_t7 -n $net_t7 24 | if [ $? != 0 ] 25 | then 26 | echo Run test failed 27 | exit 2 28 | fi 29 | 30 | 31 | # cleanup 32 | rm -f $input_t7 $output_t7 $net_t7 33 | exit 0 34 | 35 | -------------------------------------------------------------------------------- /test/tester.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | 4 | template <> cpptorch::Tensor read_tensor_template(const cpptorch::object *obj) 5 | { 6 | return cpptorch::read_tensor(obj); 7 | } 8 | 9 | template <> std::shared_ptr> read_net_template(const cpptorch::object *obj) 10 | { 11 | return cpptorch::read_net(obj); 12 | } 13 | 14 | 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | int ret = process_args(argc, argv); 19 | if (ret != 0) 20 | { 21 | return ret; 22 | } 23 | 24 | if (use_allocator) 25 | { 26 | cpptorch::allocator::init(); 27 | } 28 | 29 | ret = test_layer(); 30 | 31 | if (use_allocator) 32 | { 33 | cpptorch::allocator::cleanup(); 34 | } 35 | 36 | #ifdef _WIN64 37 | _CrtDumpMemoryLeaks(); 38 | #endif 39 | return ret; 40 | } 41 | -------------------------------------------------------------------------------- /test/tester_cuda.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | 4 | 5 | template <> cpptorch::Tensor read_tensor_template(const cpptorch::object *obj) 6 | { 7 | return cpptorch::read_cuda_tensor(obj); 8 | } 9 | 10 | template <> std::shared_ptr> read_net_template(const cpptorch::object *obj) 11 | { 12 | return cpptorch::read_cuda_net(obj); 13 | } 14 | 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | int ret = process_args(argc, argv); 19 | if (ret != 0) 20 | { 21 | return ret; 22 | } 23 | 24 | cpptorch::cuda::init(); 25 | 26 | ret = test_layer(); 27 | 28 | cpptorch::cuda::free(); 29 | 30 | #ifdef _WIN64 31 | _CrtDumpMemoryLeaks(); 32 | #endif 33 | return ret; 34 | } 35 | --------------------------------------------------------------------------------