├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CMakeModules ├── FindMDBQ.cmake ├── FindTBB.cmake ├── FindVIGRA.cmake ├── GetGitRevisionDescription.cmake └── GetGitRevisionDescription.cmake.in ├── LICENSE.txt ├── README.md ├── doc ├── Doxyfile.in ├── visual-feature.png └── visual-feature.svg ├── scripts ├── NYU │ ├── _solarized.py │ ├── _structure_classes.py │ └── convert.py └── hyperopt │ └── hyperopt_search.py ├── src ├── CMakeLists.txt ├── curfil │ ├── 0_mainpage.h │ ├── CMakeLists.txt │ ├── export.cpp │ ├── export.h │ ├── hyperopt.cpp │ ├── hyperopt.h │ ├── hyperopt_main.cpp │ ├── image.cpp │ ├── image.h │ ├── import.cpp │ ├── import.h │ ├── ndarray_ops.cpp │ ├── ndarray_ops.h │ ├── predict.cpp │ ├── predict.h │ ├── predict_main.cpp │ ├── random_features.cu │ ├── random_forest_image.cpp │ ├── random_forest_image.h │ ├── random_tree.cpp │ ├── random_tree.h │ ├── random_tree_image.cpp │ ├── random_tree_image.h │ ├── random_tree_image_gpu.cu │ ├── random_tree_image_gpu.h │ ├── score.h │ ├── train.cpp │ ├── train.h │ ├── train_main.cpp │ ├── utils.cpp │ ├── utils.h │ ├── version.cpp.in │ └── version.h ├── testdata │ ├── testing1_colors.png │ ├── testing1_depth.png │ ├── testing1_ground_truth.png │ ├── training1_colors.png │ ├── training1_depth.png │ ├── training1_ground_truth.png │ ├── training2_colors.png │ ├── training2_depth.png │ ├── training2_ground_truth.png │ ├── training3_colors.png │ ├── training3_depth.png │ └── training3_ground_truth.png └── tests │ ├── CMakeLists.txt │ ├── feature_generation_test.cpp │ ├── hyperopt_test.cpp │ ├── image_cache_test.cu │ ├── image_test.cpp │ ├── import_export_test.cpp │ ├── random_tree_image_gpu_test.cu │ ├── random_tree_image_test.cpp │ ├── random_tree_test.cpp │ └── test_common.h └── util └── add_license.pl /.gitignore: -------------------------------------------------------------------------------- 1 | doc/ 2 | build/ 3 | debug/ 4 | 5 | *.o 6 | *.so 7 | 8 | *.pyc 9 | *.pyo 10 | 11 | .*.swo 12 | .*.swp 13 | .*.swn 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/ndarray"] 2 | path = src/ndarray 3 | url = https://github.com/deeplearningais/ndarray 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | cmake_minimum_required( VERSION 2.6 FATAL_ERROR ) 27 | 28 | # 29 | # If the user specifies -DCMAKE_BUILD_TYPE on the command line, take their 30 | # definition # and dump it in the cache along with proper documentation, 31 | # otherwise set CMAKE_BUILD_TYPE # to Debug prior to calling PROJECT() 32 | # 33 | IF(DEFINED CMAKE_BUILD_TYPE) 34 | SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") 35 | ELSE() 36 | SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") 37 | ENDIF() 38 | 39 | PROJECT(curfil CXX C) 40 | SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/CMakeModules ) 41 | 42 | ENABLE_TESTING() 43 | add_subdirectory(src) 44 | 45 | FIND_PACKAGE(Doxygen) 46 | IF(DOXYGEN_FOUND) 47 | CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/doc/Doxyfile.in ${CMAKE_BINARY_DIR}/docs/Doxyfile) 48 | ADD_CUSTOM_COMMAND( 49 | DEPENDS ${CMAKE_BINARY_DIR}/docs/Doxyfile 50 | OUTPUT ${CMAKE_BINARY_DIR}/docs/html/index.html 51 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/docs/Doxyfile 52 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 53 | ) 54 | ADD_CUSTOM_TARGET(doc DEPENDS ${CMAKE_BINARY_DIR}/docs/html/index.html ${CMAKE_BINARY_DIR}/docs/Doxyfile) 55 | ENDIF(DOXYGEN_FOUND) 56 | 57 | include(GetGitRevisionDescription) 58 | git_describe(VERSION --tags --dirty --long) 59 | message(STATUS "GIT VERSION: " ${VERSION}) 60 | string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VERSION}") 61 | string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VERSION}") 62 | string(REGEX REPLACE "^v[0-9]+\\.[0-9]+-([0-9]+)-.*" "\\1" VERSION_PATCH "${VERSION}") 63 | string(REGEX REPLACE "^v[0-9]+\\.[0-9]+-[0-9]+-([a-z0-9]+).*" "\\1" VERSION_SHA "${VERSION}") 64 | string(REGEX MATCH "-dirty" VERSION_DIRTY "${VERSION}") 65 | set(VERSION_LONG "${VERSION_MAJOR}.${VERSION_MINOR}-${VERSION_PATCH}-${VERSION_SHA}${VERSION_DIRTY}") 66 | message(STATUS "GIT VERSION: `${VERSION_LONG}'") 67 | 68 | 69 | ADD_CUSTOM_COMMAND( 70 | OUTPUT ${CMAKE_BINARY_DIR}/curfil-${VERSION_LONG}-doc.tar.gz 71 | COMMAND ln -sTf doc curfil-${VERSION_LONG}-doc 72 | COMMAND tar chzvf curfil-${VERSION_LONG}-doc.tar.gz curfil-${VERSION_LONG}-doc 73 | DEPENDS ${CMAKE_BINARY_DIR}/docs/html/index.html 74 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 75 | ) 76 | ADD_CUSTOM_COMMAND( 77 | OUTPUT ${CMAKE_BINARY_DIR}/curfil-${VERSION_LONG}.tar.gz 78 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. 79 | COMMAND ln -sTf ${CMAKE_SOURCE_DIR} curfil-${VERSION_LONG} 80 | COMMAND tar chzvf ${CMAKE_BINARY_DIR}/curfil-${VERSION_LONG}.tar.gz --exclude-vcs --exclude 'curfil-${VERSION_LONG}/build*' curfil-${VERSION_LONG} 81 | ) 82 | ADD_CUSTOM_TARGET(dist 83 | DEPENDS 84 | ${CMAKE_BINARY_DIR}/curfil-${VERSION_LONG}-doc.tar.gz 85 | ${CMAKE_BINARY_DIR}/curfil-${VERSION_LONG}.tar.gz 86 | ) 87 | -------------------------------------------------------------------------------- /CMakeModules/FindMDBQ.cmake: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | # This module finds an installed MDBQ package. 27 | # 28 | # It sets the following variables: 29 | # MDBQ_FOUND - Set to false, or undefined, if MDBQ isn't found. 30 | # MDBQ_INCLUDE_DIRS - MDBQ include directories 31 | # MDBQ_LIBRARIES - MDBQ libraries 32 | 33 | FIND_PATH(MDBQ_INCLUDE_DIR mdbq/client.hpp PATHS ${MDBQ_ROOT}/src /usr/local/include /usr/include) 34 | FIND_LIBRARY(MDBQ_LIBRARY mdbq PATHS ${MDBQ_ROOT}/build/src/mdbq /usr/local/lib /usr/lib) 35 | 36 | FIND_PATH(BSON_INCLUDE_DIR mongo/bson/bson.h) 37 | 38 | set(MDBQ_LIBRARIES ${MDBQ_LIBRARY} ) 39 | set(MDBQ_INCLUDE_DIRS ${MDBQ_INCLUDE_DIR} ${BSON_INCLUDE_DIR}) 40 | 41 | # handle the QUIETLY and REQUIRED arguments and set MDBQ_FOUND to TRUE if 42 | # all listed variables are TRUE 43 | INCLUDE(FindPackageHandleStandardArgs) 44 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(MDBQ DEFAULT_MSG MDBQ_LIBRARY MDBQ_INCLUDE_DIR) 45 | IF(MDBQ_FOUND) 46 | IF (NOT MDBQ_FIND_QUIETLY) 47 | MESSAGE(STATUS " MDBQ include dirs: ${MDBQ_INCLUDE_DIRS}") 48 | MESSAGE(STATUS " MDBQ libraries: ${MDBQ_LIBRARIES}") 49 | ENDIF() 50 | ENDIF() 51 | 52 | 53 | MARK_AS_ADVANCED( MDBQ_INCLUDE_DIR MDBQ_LIBRARY MDBQ_LIBRARY_DIR) 54 | -------------------------------------------------------------------------------- /CMakeModules/FindVIGRA.cmake: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | # This module finds an installed Vigra package. 27 | # 28 | # It sets the following variables: 29 | # VIGRA_FOUND - Set to false, or undefined, if vigra isn't found. 30 | # VIGRA_INCLUDE_DIR - Vigra include directory. 31 | # VIGRA_IMPEX_LIBRARY - Vigra's impex library 32 | # VIGRA_IMPEX_LIBRARY_DIR - path to Vigra impex library 33 | 34 | # configVersion.hxx only present, after build of Vigra 35 | FIND_PATH(VIGRA_INCLUDE_DIR vigra/configVersion.hxx PATHS $ENV{VIGRA_ROOT}/include ENV CPLUS_INCLUDE_PATH) 36 | FIND_LIBRARY(VIGRA_IMPEX_LIBRARY vigraimpex PATHS $ENV{VIGRA_ROOT}/src/impex $ENV{VIGRA_ROOT}/lib ENV LD_LIBRARY_PATH ENV LIBRARY_PATH) 37 | GET_FILENAME_COMPONENT(VIGRA_IMPEX_LIBRARY_PATH ${VIGRA_IMPEX_LIBRARY} PATH) 38 | SET( VIGRA_IMPEX_LIBRARY_DIR ${VIGRA_IMPEX_LIBRARY_PATH} CACHE PATH "Path to Vigra impex library.") 39 | 40 | # handle the QUIETLY and REQUIRED arguments and set VIGRA_FOUND to TRUE if 41 | # all listed variables are TRUE 42 | INCLUDE(FindPackageHandleStandardArgs) 43 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(VIGRA DEFAULT_MSG VIGRA_IMPEX_LIBRARY VIGRA_INCLUDE_DIR) 44 | IF(VIGRA_FOUND) 45 | IF (NOT VIGRA_FIND_QUIETLY) 46 | MESSAGE(STATUS " includes: ${VIGRA_INCLUDE_DIR}") 47 | MESSAGE(STATUS " impex library dir: ${VIGRA_IMPEX_LIBRARY_DIR}") 48 | MESSAGE(STATUS " impex library: ${VIGRA_IMPEX_LIBRARY}") 49 | ENDIF() 50 | ENDIF() 51 | 52 | 53 | MARK_AS_ADVANCED( VIGRA_INCLUDE_DIR VIGRA_IMPEX_LIBRARY VIGRA_IMPEX_LIBRARY_DIR) 54 | -------------------------------------------------------------------------------- /CMakeModules/GetGitRevisionDescription.cmake: -------------------------------------------------------------------------------- 1 | # - Returns a version string from Git 2 | # 3 | # These functions force a re-configure on each git commit so that you can 4 | # trust the values of the variables in your build system. 5 | # 6 | # get_git_head_revision( [ ...]) 7 | # 8 | # Returns the refspec and sha hash of the current head revision 9 | # 10 | # git_describe( [ ...]) 11 | # 12 | # Returns the results of git describe on the source tree, and adjusting 13 | # the output so that it tests false if an error occurs. 14 | # 15 | # git_get_exact_tag( [ ...]) 16 | # 17 | # Returns the results of git describe --exact-match on the source tree, 18 | # and adjusting the output so that it tests false if there was no exact 19 | # matching tag. 20 | # 21 | # Requires CMake 2.6 or newer (uses the 'function' command) 22 | # 23 | # Original Author: 24 | # 2009-2010 Ryan Pavlik 25 | # http://academic.cleardefinition.com 26 | # Iowa State University HCI Graduate Program/VRAC 27 | # 28 | # Copyright Iowa State University 2009-2010. 29 | # Distributed under the Boost Software License, Version 1.0. 30 | # (See accompanying file LICENSE_1_0.txt or copy at 31 | # http://www.boost.org/LICENSE_1_0.txt) 32 | 33 | if(__get_git_revision_description) 34 | return() 35 | endif() 36 | set(__get_git_revision_description YES) 37 | 38 | # We must run the following at "include" time, not at function call time, 39 | # to find the path to this module rather than the path to a calling list file 40 | get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) 41 | 42 | function(get_git_head_revision _refspecvar _hashvar) 43 | set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}") 44 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 45 | while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories 46 | set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") 47 | get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) 48 | if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) 49 | # We have reached the root directory, we are not in git 50 | set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 51 | set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 52 | return() 53 | endif() 54 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 55 | endwhile() 56 | set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") 57 | if(NOT EXISTS "${GIT_DATA}") 58 | file(MAKE_DIRECTORY "${GIT_DATA}") 59 | endif() 60 | 61 | if(NOT EXISTS "${GIT_DIR}/HEAD") 62 | return() 63 | endif() 64 | set(HEAD_FILE "${GIT_DATA}/HEAD") 65 | configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) 66 | 67 | configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" 68 | "${GIT_DATA}/grabRef.cmake" 69 | @ONLY) 70 | include("${GIT_DATA}/grabRef.cmake") 71 | 72 | set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) 73 | set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) 74 | endfunction() 75 | 76 | function(git_describe _var) 77 | if(NOT GIT_FOUND) 78 | find_package(Git QUIET) 79 | endif() 80 | get_git_head_revision(refspec hash) 81 | if(NOT GIT_FOUND) 82 | set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) 83 | return() 84 | endif() 85 | if(NOT hash) 86 | set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) 87 | return() 88 | endif() 89 | 90 | # TODO sanitize 91 | #if((${ARGN}" MATCHES "&&") OR 92 | # (ARGN MATCHES "||") OR 93 | # (ARGN MATCHES "\\;")) 94 | # message("Please report the following error to the project!") 95 | # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") 96 | #endif() 97 | 98 | #message(STATUS "Arguments to execute_process: ${ARGN}") 99 | 100 | execute_process(COMMAND 101 | "${GIT_EXECUTABLE}" 102 | describe 103 | ${ARGN} 104 | WORKING_DIRECTORY 105 | "${CMAKE_SOURCE_DIR}" 106 | RESULT_VARIABLE 107 | res 108 | OUTPUT_VARIABLE 109 | out 110 | ERROR_QUIET 111 | OUTPUT_STRIP_TRAILING_WHITESPACE) 112 | if(NOT res EQUAL 0) 113 | set(out "${out}-${res}-NOTFOUND") 114 | endif() 115 | 116 | set(${_var} "${out}" PARENT_SCOPE) 117 | endfunction() 118 | 119 | function(git_get_exact_tag _var) 120 | git_describe(out --exact-match ${ARGN}) 121 | set(${_var} "${out}" PARENT_SCOPE) 122 | endfunction() 123 | -------------------------------------------------------------------------------- /CMakeModules/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") 27 | configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 28 | set(HEAD_HASH "${HEAD_REF}") 29 | endif() 30 | else() 31 | # detached HEAD 32 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 33 | endif() 34 | 35 | if(NOT HEAD_HASH) 36 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 37 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 38 | endif() 39 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CUDA Random Forests for Image Labeling (CURFIL) 2 | ----------------------------------------------- 3 | 4 | This project is an open source implementation with NVIDIA CUDA that accelerates random 5 | forest training and prediction for image labeling by using the 6 | massive parallel computing power offered by GPUs. 7 | 8 | CURFIL is the result of Benedikt Waldvogel’s master thesis 9 | "[Accelerating Random Forests on CPUs and GPUs for Object-Class Image Segmentation][master-thesis]" 10 | at the University of Bonn, [Autonomous Intelligent Systems][ais-bonn]. 11 | 12 | Implemented Visual Features 13 | --------------------------- 14 | 15 | We currently focus on image labelling tasks such as image segmentation or classification applications. 16 | We implement two types of image features as described in the 17 | [documentation of visual features][visual-features] in more detail. 18 | 19 | Installation 20 | ------------ 21 | 22 | ### Dependencies ### 23 | 24 | To build the C++ library and the binaries, you will need: 25 | 26 | - cmake (and cmake-curses-gui for easy configuration) 27 | - [ndarray][ndarray] (included as git submodule) 28 | - GCC 4.4 or higher 29 | - Boost 1.46 or higher 30 | - NVIDIA CUDA™ 5.0 or higher 31 | - [Thrust][thrust] - included in CUDA since 4.0 32 | - [Vigra Impex][vigra] 33 | - Intel TBB 34 | - [MDBQ][mdbq] (optional, required for [hyperopt][hyperopt] parameter search) 35 | - A CUDA capable GPU with compute capability 2.0 or higher 36 | 37 | 38 | ### Building ### 39 | 40 | ```bash 41 | git clone --recursive https://github.com/deeplearningais/curfil.git # --recursive will also init the submodules 42 | cd curfil 43 | mkdir -p build 44 | cd build 45 | cmake -DCMAKE_BUILD_TYPE=Release .. # change to 'Debug' to build the debugging version 46 | ccmake . # adjust paths to your system (cuda, thrust, ...)! 47 | make -j 48 | ctest # run tests to see if it went well 49 | sudo make install 50 | ``` 51 | Refer to your local Unix expert if you do not know what to do with this instruction. 52 | Pay special attention to the `CUDA_ARCHITECTURE` variable in ccmake. If you have a very recent GPU (eg TITAN), you probably want to enable support for device capability 5.2 by adding/replacing with `;-gencode;arch=compute_52,code=sm_52`. 53 | 54 | Dataset Format 55 | -------------- 56 | 57 | Training and prediction requires to load a set of images from a dataset. We 58 | currently only support datasets that contain RGB-D images, as for example 59 | captured by the Microsoft Kinect or the Asus Xtion PRO LIVE. RGB-D images have 60 | three channels that encode the color information and one channel for the depth 61 | of each pixel. Depth is the distance of the object to the camera. Note that 62 | stereo cameras such as the Kinect do not guarantee to deliver a valid depth 63 | measure for every pixel in the image. Distance cannot be measured if the object 64 | is occluded for one of the two cameras. Missing or invalid distance is either 65 | encoded with a zero value or by using the special floating point value `NaN`. 66 | 67 | To load images from disk, we use a similar format as the [RGB-D object dataset 68 | of Kevin Lai et al.][lai-rgbd]. 69 | 70 | We expect to find the color image, depth information and the ground truth in three files in the same folder. 71 | All images must have the same size. Datasets with varying image sizes must be padded manually. 72 | You can specify to skip the padding color when sampling the dataset by using the `--ignoreColor` parameter. 73 | 74 | The filename schema and format is 75 | 76 | - `_colors.png` 77 | A three-channel `uint8` RGB image where pixels take on values between 0-255 78 | - `_depth.png` 79 | A single-channel `uint16` depth image. Each pixel gives 80 | the depth in millimeters, with 0 denoting missing depth. The depth image can be 81 | read using MATLAB with the standard function ([imread][matlab-imread]), and in OpenCV by loading 82 | it into an image of type `IPL_DEPTH_16U`. 83 | - `_ground_truth.png` 84 | A three-channel `uint8` RGB image where pixels take on values between 0-255. 85 | Each color represents a different class label. Black indicates "void" or 86 | "background". 87 | 88 | Usage 89 | ----- 90 | 91 | ### Training ### 92 | 93 | Use the binary `curfil_train`. 94 | 95 | The training process produces a random forest consisting of multiple decision trees 96 | that are serialized to compressed JSON files, one file per tree. 97 | 98 | See the [documentation of training parameters](https://github.com/deeplearningais/curfil/wiki/Training-Parameters). 99 | 100 | ### Prediction ### 101 | 102 | Use the binary `curfil_predict`. 103 | 104 | The program reads the trees from the compresses JSON files and performs a dense 105 | pixel-wise classification of the specified input images. 106 | Prediction is accelerated on GPU and runs in real-time speed even on mobile 107 | GPUs such as the NVIDIA GeForce GTX 675M. 108 | 109 | Also see [documentation of prediction parameters](http://github.com/deeplearningais/curfil/wiki/Prediction-Parameters). 110 | 111 | ### Hyperopt Parameter Search ### 112 | 113 | Use the binary `curfil_hyperopt`. 114 | 115 | This [Hyperopt][hyperopt] client is only built if [MDBQ][MDBQ] is installed. 116 | The client fetches hyperopt trials (jobs) from a MongoDB database and performs 5-fold cross-validation to evaluate the loss. 117 | You can run the hyperopt client in parallel on as many machines as desired. 118 | 119 | The trials need to be inserted into the database in advance. 120 | We include sample python scripts in [scripts/](scripts/). 121 | Note that there is only one *new* trial in the database at any given point in time. 122 | Thus, the python script needs to be running during the entire parameter search. 123 | 124 | The procedure: 125 | 126 | 1. Make sure the MongoDB database is up an running. 127 | 2. Run the python script that inserts new trials. Example: `scripts/NYU/hyperopt_search.py` 128 | 3. Run `curfil_hyperopt` on as many machine as desired. 129 | 130 | Also see [documentation of hyperopt parameter search in the wiki](http://github.com/deeplearningais/curfil/wiki/Hyperopt-Parameter-Search). 131 | 132 | ### As a `C++` Library ### 133 | 134 | See [the example in the wiki](https://github.com/deeplearningais/curfil/wiki/Usage-as-a-Library) and the [API Documentation](http://deeplearningais.github.io/curfil/doc/index.html). 135 | 136 | Examples 137 | -------- 138 | 139 | - [Training and Prediction with the NYU Depth v2 Dataset](https://github.com/deeplearningais/curfil/wiki/Training-and-Prediction-with-the-NYU-Depth-v2-Dataset) 140 | 141 | 142 | [master-thesis]: http://www.ais.uni-bonn.de/theses/Benedikt_Waldvogel_Master_Thesis_07_2013.pdf 143 | [ais-bonn]: http://www.ais.uni-bonn.de 144 | [visual-features]: https://github.com/deeplearningais/curfil/wiki/Visual-Features 145 | [lai-rgbd]: http://www.cs.washington.edu/rgbd-dataset/trd5326jglrepxk649ed/rgbd-dataset_full/README.txt 146 | [ndarray]: https://github.com/deeplearningais/ndarray 147 | [thrust]: http://code.google.com/p/thrust/ 148 | [mdbq]: https://github.com/temporaer/MDBQ 149 | [hyperopt]: https://github.com/jaberg/hyperopt 150 | [vigra]: https://ukoethe.github.io/vigra/ 151 | [matlab-imread]: http://www.mathworks.de/de/help/matlab/ref/imread.html 152 | -------------------------------------------------------------------------------- /doc/visual-feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/doc/visual-feature.png -------------------------------------------------------------------------------- /scripts/NYU/_solarized.py: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | colors = [ 27 | (0, 43, 54), 28 | (7, 54, 66), # floor 29 | (88, 110, 117), 30 | (101, 123, 131), 31 | (131, 148, 150), 32 | (147, 161, 161), # structure 33 | (238, 232, 213), 34 | (253, 246, 227), 35 | (181, 137, 0), # prop 36 | (203, 75, 22), # furniture 37 | (220, 50, 47), 38 | (211, 54, 130), 39 | (108, 113, 196), 40 | (38, 139, 210), 41 | (42, 161, 152), 42 | (133, 153, 0) 43 | ] 44 | -------------------------------------------------------------------------------- /scripts/NYU/convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | # vim: set fileencoding=utf-8 : 28 | # 29 | # Helper script to convert the NYU Depth v2 dataset Matlab file into a set of 30 | # PNG images in the CURFIL dataset format. 31 | # 32 | # See https://github.com/deeplearningais/curfil/wiki/Training-and-Prediction-with-the-NYU-Depth-v2-Dataset 33 | 34 | from __future__ import print_function 35 | 36 | from joblib import Parallel, delayed 37 | from skimage import exposure 38 | from skimage.io import imsave 39 | import h5py 40 | import numpy as np 41 | import os 42 | import png 43 | import scipy.io 44 | import sys 45 | 46 | from _structure_classes import get_structure_classes 47 | import _solarized 48 | 49 | 50 | def process_ground_truth(ground_truth): 51 | colors = dict() 52 | colors["structure"] = _solarized.colors[5] 53 | colors["prop"] = _solarized.colors[8] 54 | colors["furniture"] = _solarized.colors[9] 55 | colors["floor"] = _solarized.colors[1] 56 | shape = list(ground_truth.shape) + [3] 57 | img = np.ndarray(shape=shape, dtype=np.uint8) 58 | for i in xrange(shape[0]): 59 | for j in xrange(shape[1]): 60 | l = ground_truth[i, j] 61 | if (l == 0): 62 | img[i, j] = (0, 0, 0) # background 63 | else: 64 | name = classes[names[l - 1]] 65 | assert name in colors, name 66 | img[i, j] = colors[name] 67 | return img 68 | 69 | 70 | def visualize_depth_image(data): 71 | 72 | data[data == 0.0] = np.nan 73 | 74 | maxdepth = np.nanmax(data) 75 | mindepth = np.nanmin(data) 76 | data = data.copy() 77 | data -= mindepth 78 | data /= (maxdepth - mindepth) 79 | 80 | gray = np.zeros(list(data.shape) + [3], dtype=data.dtype) 81 | data = (1.0 - data) 82 | gray[..., :3] = np.dstack((data, data, data)) 83 | 84 | # use a greenish color to visualize missing depth 85 | gray[np.isnan(data), :] = (97, 160, 123) 86 | gray[np.isnan(data), :] /= 255 87 | 88 | gray = exposure.equalize_hist(gray) 89 | 90 | # set alpha channel 91 | gray = np.dstack((gray, np.ones(data.shape[:2]))) 92 | gray[np.isnan(data), -1] = 0.5 93 | 94 | return gray * 255 95 | 96 | 97 | def convert_image(i, scene, img_depth, image, label): 98 | 99 | idx = int(i) + 1 100 | if idx in train_images: 101 | train_test = "training" 102 | else: 103 | assert idx in test_images, "index %d neither found in training set nor in test set" % idx 104 | train_test = "testing" 105 | 106 | folder = "%s/%s/%s" % (out_folder, train_test, scene) 107 | if not os.path.exists(folder): 108 | os.makedirs(folder) 109 | 110 | img_depth = img_depth * 1000.0 111 | 112 | png.from_array(img_depth, 'L;16').save("%s/%05d_depth.png" % (folder, i)) 113 | 114 | depth_visualization = visualize_depth_image(img_depth) 115 | 116 | # workaround for a bug in the png module 117 | depth_visualization = depth_visualization.copy() # makes in contiguous 118 | shape = depth_visualization.shape 119 | depth_visualization.shape = (shape[0], np.prod(shape[1:])) 120 | 121 | depth_image = png.from_array(depth_visualization, "RGBA;8") 122 | depth_image.save("%s/%05d_depth_visualization.png" % (folder, i)) 123 | 124 | imsave("%s/%05d_colors.png" % (folder, i), image) 125 | 126 | ground_truth = process_ground_truth(label) 127 | imsave("%s/%05d_ground_truth.png" % (folder, i), ground_truth) 128 | 129 | 130 | if __name__ == "__main__": 131 | 132 | if len(sys.argv) < 4: 133 | print("usage: %s [ ]" % sys.argv[0], file=sys.stderr) 134 | sys.exit(0) 135 | 136 | h5_file = h5py.File(sys.argv[1], "r") 137 | # h5py is not able to open that file. but scipy is 138 | train_test = scipy.io.loadmat(sys.argv[2]) 139 | out_folder = sys.argv[3] 140 | if len(sys.argv) >= 5: 141 | raw_depth = bool(int(sys.argv[4])) 142 | else: 143 | raw_depth = False 144 | 145 | if len(sys.argv) >= 6: 146 | num_threads = int(sys.argv[5]) 147 | else: 148 | num_threads = -1 149 | 150 | test_images = set([int(x) for x in train_test["testNdxs"]]) 151 | train_images = set([int(x) for x in train_test["trainNdxs"]]) 152 | print("%d training images" % len(train_images)) 153 | print("%d test images" % len(test_images)) 154 | 155 | if raw_depth: 156 | print("using raw depth images") 157 | depth = h5_file['rawDepths'] 158 | else: 159 | print("using filled depth images") 160 | depth = h5_file['depths'] 161 | 162 | print("reading", sys.argv[1]) 163 | 164 | labels = h5_file['labels'] 165 | images = h5_file['images'] 166 | 167 | rawDepthFilenames = [u''.join(unichr(c) for c in h5_file[obj_ref]) for obj_ref in h5_file['rawDepthFilenames'][0]] 168 | names = [u''.join(unichr(c) for c in h5_file[obj_ref]) for obj_ref in h5_file['names'][0]] 169 | scenes = [u''.join(unichr(c) for c in h5_file[obj_ref]) for obj_ref in h5_file['sceneTypes'][0]] 170 | rawRgbFilenames = [u''.join(unichr(c) for c in h5_file[obj_ref]) for obj_ref in h5_file['rawRgbFilenames'][0]] 171 | classes = get_structure_classes() 172 | 173 | print("processing images") 174 | if num_threads == 1: 175 | print("single-threaded mode") 176 | for i, image in enumerate(images): 177 | print("image", i + 1, "/", len(images)) 178 | convert_image(i, scenes[i], depth[i, :, :].T, image.T, labels[i, :, :].T) 179 | else: 180 | Parallel(num_threads)(delayed(convert_image)(i, scenes[i], depth[i, :, :].T, images[i, :, :].T, labels[i, :, :].T) for i in range(len(images))) 181 | 182 | print("finished") 183 | -------------------------------------------------------------------------------- /scripts/hyperopt/hyperopt_search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | 28 | from __future__ import print_function 29 | 30 | import sys 31 | import math 32 | 33 | import hyperopt 34 | from hyperopt import fmin, tpe, hp 35 | from hyperopt.mongoexp import MongoTrials 36 | 37 | 38 | def get_space(): 39 | space = (hp.quniform('numTrees', 1, 10, 1), 40 | hp.quniform('samplesPerImage', 10, 7500, 1), 41 | hp.quniform('featureCount', 10, 7500, 1), 42 | hp.quniform('minSampleCount', 1, 1000, 1), 43 | hp.quniform('maxDepth', 5, 25, 1), 44 | hp.quniform('boxRadius', 1, 127, 1), 45 | hp.quniform('regionSize', 1, 127, 1), 46 | hp.quniform('thresholds', 10, 60, 1), 47 | hp.uniform('histogramBias', 0.0, 0.6), 48 | ) 49 | return space 50 | 51 | 52 | def get_exp(mongodb_url, database, exp_key): 53 | trials = MongoTrials('mongo://%s/%s/jobs' % (mongodb_url, database), exp_key=exp_key) 54 | space = get_space() 55 | return trials, space 56 | 57 | def show(mongodb_url, db, exp_key): 58 | print ("Get trials, space...") 59 | trials, space = get_exp(mongodb_url, db, exp_key) 60 | print ("Get bandit...") 61 | bandit = hyperopt.Bandit(expr=space, do_checks=False) 62 | print ("Plotting...") 63 | # from IPython.core.debugger import Tracer; Tracer()() 64 | best_trial = trials.best_trial 65 | values = best_trial['misc']['vals'] 66 | loss = best_trial['result']['loss'] 67 | true_loss = best_trial['result']['true_loss'] 68 | print ("values: ", values) 69 | print ("loss: ", loss) 70 | print ("true_loss: ", true_loss) 71 | hyperopt.plotting.main_plot_history(trials) 72 | hyperopt.plotting.main_plot_vars(trials, bandit, colorize_best=3) 73 | 74 | 75 | if __name__ == "__main__": 76 | 77 | if len(sys.argv) < 4: 78 | print("usage: %s [show]" % sys.argv[0], file=sys.stderr) 79 | sys.exit(1) 80 | 81 | mongodb_url, database, exp_key = sys.argv[1:4] 82 | 83 | if len(sys.argv) == 5: 84 | show(mongodb_url, database, exp_key) 85 | sys.exit(0) 86 | 87 | trials, space = get_exp(mongodb_url, database, exp_key) 88 | best = fmin(fn=math.sin, space=space, trials=trials, algo=tpe.suggest, max_evals=1000) 89 | print("best: %s" % (repr(best))) 90 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | cmake_minimum_required( VERSION 3.1 FATAL_ERROR ) 27 | 28 | FIND_PACKAGE(CUDA REQUIRED) 29 | FIND_PACKAGE(TBB REQUIRED) 30 | FIND_PACKAGE(VIGRA REQUIRED) 31 | FIND_PACKAGE(MDBQ) 32 | 33 | SET(CMAKE_CXX_COMPILER g++-5) 34 | 35 | # need c++11 for isnan 36 | SET(CMAKE_CXX_STANDARD 11) 37 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wformat=2") 38 | 39 | SET(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -std=c++11 -ccbin gcc-5") 40 | SET(CUDA_NVCC_FLAGS_DEBUG "${CUDA_NVCC_FLAGS_DEBUG} -O0 -G") 41 | 42 | # http://stackoverflow.com/questions/8450030/can-modern-c-compilers-inline-functions-that-are-defined-in-a-cpp-file 43 | ADD_DEFINITIONS("-flto") 44 | 45 | # ---------- Find Boost Headers/Libraries ----------------------- 46 | SET (Boost_FIND_REQUIRED ON) 47 | SET (Boost_FIND_QUIETLY OFF) 48 | SET (Boost_USE_MULTITHREADED ON) 49 | SET (Boost_USE_STATIC_LIBS OFF) 50 | FIND_PACKAGE(Boost 1.46 COMPONENTS system filesystem iostreams program_options date_time REQUIRED) 51 | INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) 52 | LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) 53 | add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) 54 | 55 | FIND_PATH(THRUST_PATH thrust/device_vector.h /usr/include /usr/local/include ${CUDA_INCLUDE_DIRS} "$ENV{THRUST_ROOT}") 56 | IF(NOT THRUST_PATH) 57 | MESSAGE(FATAL_ERROR "Could not find the thrust library. Please install in standard locations or set THRUST_ROOT environment variable.") 58 | ENDIF(NOT THRUST_PATH) 59 | 60 | if ( NOT CUDA_ARCHITECTURE ) 61 | SET( CUDA_ARCHITECTURE -gencode;arch=compute_30,code=sm_30;-gencode;arch=compute_35,code=sm_35 ) 62 | endif() 63 | 64 | SET(CUDA_ARCHITECTURE ${CUDA_ARCHITECTURE} CACHE STRING "The CUDA architecture to compile for, i.e. -gencode;arch=compute_2") 65 | SET(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};${CUDA_ARCHITECTURE}") 66 | MESSAGE(STATUS "CUDA_NVCC_FLAGS: ${CUDA_NVCC_FLAGS}") 67 | 68 | CUDA_INCLUDE_DIRECTORIES( ${THRUST_PATH} ) 69 | INCLUDE_DIRECTORIES( ${THRUST_PATH} ) 70 | 71 | CUDA_INCLUDE_DIRECTORIES( ${TBB_INCLUDE_DIRS} ) 72 | INCLUDE_DIRECTORIES( ${TBB_INCLUDE_DIRS} ) 73 | 74 | CUDA_INCLUDE_DIRECTORIES( ${VIGRA_INCLUDE_DIR} ) 75 | INCLUDE_DIRECTORIES( ${VIGRA_INCLUDE_DIR} ) 76 | 77 | CUDA_INCLUDE_DIRECTORIES( ${THRUST_PATH} ) 78 | INCLUDE_DIRECTORIES( ${THRUST_PATH} ) 79 | 80 | CUDA_INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/src/ndarray/src ) 81 | INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/src/ndarray/src ) 82 | 83 | IF(MDBQ_FOUND) 84 | CUDA_INCLUDE_DIRECTORIES( ${MDBQ_INCLUDE_DIRS} ) 85 | INCLUDE_DIRECTORIES( ${MDBQ_INCLUDE_DIRS} ) 86 | ELSE() 87 | SET (MDBQ_FILES ) 88 | ENDIF() 89 | 90 | add_subdirectory(curfil) 91 | add_subdirectory(ndarray/src/cuv) 92 | add_subdirectory(tests) 93 | 94 | # INSTALL(DIRECTORY curfil${LIB_SUFFIX}/ 95 | # DESTINATION "include/curfil" 96 | # FILES_MATCHING PATTERN "*.hpp" 97 | # ) 98 | # IF("${LIB_SUFFIX}" STREQUAL "") 99 | # INSTALL(FILES ndarray.hpp DESTINATION include) 100 | # ENDIF("${LIB_SUFFIX}" STREQUAL "") 101 | 102 | CUDA_BUILD_CLEAN_TARGET() 103 | -------------------------------------------------------------------------------- /src/curfil/0_mainpage.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | 29 | /** 30 | * 31 | * 32 | * @defgroup forest_hierarchy Forest hierarchy 33 | * @defgroup hyperopt Hyperopt 34 | * @defgroup import_export_trees Import and Export trees 35 | * @defgroup image_related Image related classes 36 | * @defgroup LRU_cache LRU Cache 37 | * @defgroup prediction_results Prediction Results 38 | * @defgroup rand_sampling Random Sampling 39 | * @defgroup score_calc Score Calculation 40 | * @defgroup transfer_cpu_gpu Transfer between CPU and GPU 41 | * @defgroup training_helper_classes Training helper classes 42 | * @defgroup unit_testing Unit Testing 43 | * 44 | * 45 | * @mainpage 46 | * CUDA Random Forests for Image Labeling (CURFIL) 47 | * ----------------------------------------------- 48 | * 49 | * This project is an open source implementation with NVIDIA CUDA that accelerates random 50 | * forest training and prediction for image labeling by using the 51 | * massive parallel computing power offered by GPUs. 52 | * 53 | * CURFIL is the result of Benedikt Waldvogel’s master thesis 54 | * [Accelerating Random Forests on CPUs and GPUs for Object-Class Image Segmentation][master-thesis] 55 | * at the University of Bonn, [Autonomous Intelligent Systems][ais-bonn]. 56 | * 57 | * Implemented Visual Features 58 | * --------------------------- 59 | * 60 | * We currently focus on image labelling tasks such as image segmentation or classification applications. 61 | * We implement two types of image features as described in the 62 | * [documentation of visual features][visual-features] in more detail. 63 | * 64 | * Installation 65 | * ------------ 66 | * 67 | * ### Dependencies ### 68 | * 69 | * To build the C++ library and the binaries, you will need: 70 | * 71 | * - cmake (and cmake-curses-gui for easy configuration) 72 | * - [ndarray][ndarray] (included as git submodule) 73 | * - GCC 4.4 or higher 74 | * - Boost 1.46 or higher 75 | * - NVIDIA CUDA™ 5.0 or higher 76 | * - [Thrust][thrust] - included in CUDA since 4.0 77 | * - [Vigra Impex][vigra] 78 | * - Intel TBB 79 | * - [MDBQ][mdbq] (optional, required for [hyperopt][hyperopt] parameter search) 80 | * - A CUDA capable GPU with compute capability 2.0 or higher 81 | * 82 | * 83 | * ### Building ### 84 | * 85 | * @code 86 | * git clone --recursive https://github.com/deeplearningais/curfil.git # --recursive will also init the submodules 87 | * cd curfil 88 | * mkdir -p build 89 | * cd build 90 | * cmake -DCMAKE_BUILD_TYPE=Release .. # change to 'Debug' to build the debugging version 91 | * ccmake . # adjust paths to your system (cuda, thrust, ...)! 92 | * make -j 93 | * ctest # run tests to see if it went well 94 | * sudo make install 95 | * @endcode 96 | * Refer to your local Unix expert if you do not know what to do with this instruction. 97 | * 98 | * Dataset Format 99 | * -------------- 100 | * 101 | * Training and prediction requires to load a set of images from a dataset. We 102 | * currently only support datasets that contain RGB-D images, as for example 103 | * captured by the Microsoft Kinect or the Asus Xtion PRO LIVE. RGB-D images have 104 | * three channels that encode the color information and one channel for the depth 105 | * of each pixel. Depth is the distance of the object to the camera. Note that 106 | * stereo cameras such as the Kinect do not guarantee to deliver a valid depth 107 | * measure for every pixel in the image. Distance cannot be measured if the object 108 | * is occluded for one of the two cameras. Missing or invalid distance is either 109 | * encoded with a zero value or by using the special floating point value `NaN`. 110 | * 111 | * To load images from disk, we use a similar format as the [RGB-D object dataset 112 | * of Kevin Lai et al.][lai-rgbd]. 113 | * 114 | * We expect to find the color image, depth information and the ground truth in three files in the same folder. 115 | * All images must have the same size. Datasets with varying image sizes must be padded manually. 116 | * You can specify to skip the padding color when sampling the dataset by using the `--ignoreColor` parameter. 117 | * 118 | * The filename schema and format is 119 | * 120 | * - `name_colors.png` 121 | * A three-channel `uint8` RGB image where pixels take on values between 0-255 122 | * - `name_depth.png` 123 | * A single-channel `uint16` depth image. Each pixel gives 124 | * the depth in millimeters, with 0 denoting missing depth. The depth image can be 125 | * read using MATLAB with the standard function ([imread][matlab-imread]), and in OpenCV by loading 126 | * it into an image of type `IPL_DEPTH_16U`. 127 | * - `name_ground_truth.png` 128 | * A three-channel `uint8` RGB image where pixels take on values between 0-255. 129 | * Each color represents a different class label. Black indicates "void" or 130 | * "background". 131 | * 132 | * Usage 133 | * ----- 134 | * 135 | * ### Training ### 136 | * 137 | * Use the binary `curfil_train`. 138 | * 139 | * The training process produces a random forest consisting of multiple decision trees 140 | * that are serialized to compressed JSON files, one file per tree. 141 | * 142 | * See the [documentation of training parameters](https://github.com/deeplearningais/curfil/wiki/Training-Parameters). 143 | * 144 | * ### Prediction ### 145 | * 146 | * Use the binary `curfil_predict`. 147 | * 148 | * The program reads the trees from the compresses JSON files and performs a dense 149 | * pixel-wise classification of the specified input images. 150 | * Prediction is accelerated on GPU and runs in real-time speed even on mobile 151 | * GPUs such as the NVIDIA GeForce GTX 675M. 152 | * 153 | * Also see [documentation of prediction parameters](http://github.com/deeplearningais/curfil/wiki/Prediction-Parameters). 154 | * 155 | * ### Hyperopt Parameter Search ### 156 | * 157 | * Use the binary `curfil_hyperopt`. 158 | * 159 | * This [Hyperopt][hyperopt] client is only built if [MDBQ][MDBQ] is installed. 160 | * The client fetches hyperopt trials (jobs) from a MongoDB database and performs 5-fold cross-validation to evaluate the loss. 161 | * You can run the hyperopt client in parallel on as many machines as desired. 162 | * 163 | * The trials need to be inserted into the database in advance. 164 | * We include sample python scripts in [scripts/](scripts/). 165 | * Note that there is only one *new* trial in the database at any given point in time. 166 | * Thus, the python script needs to be running during the entire parameter search. 167 | * 168 | * The procedure: 169 | * 170 | * 1. Make sure the MongoDB database is up an running. 171 | * 2. Run the python script that inserts new trials. Example: `scripts/NYU/hyperopt_search.py` 172 | * 3. Run `curfil_hyperopt` on as many machine as desired. 173 | * 174 | * Also see [documentation of hyperopt parameter search in the wiki](http://github.com/deeplearningais/curfil/wiki/Hyperopt-Parameter-Search). 175 | * 176 | * ### As a `C++` Library ### 177 | * 178 | * See [the example in the wiki](https://github.com/deeplearningais/curfil/wiki/Usage-as-a-Library). 179 | * 180 | * Examples 181 | * -------- 182 | * 183 | * - [Training and Prediction with the NYU Depth v2 Dataset](https://github.com/deeplearningais/curfil/wiki/Training-and-Prediction-with-the-NYU-Depth-v2-Dataset) 184 | * 185 | * 186 | * [master-thesis]: http://www.ais.uni-bonn.de/theses/Benedikt_Waldvogel_Master_Thesis_07_2013.pdf 187 | * [ais-bonn]: http://www.ais.uni-bonn.de 188 | * [visual-features]: https://github.com/deeplearningais/curfil/wiki/Visual-Features 189 | * [lai-rgbd]: http://www.cs.washington.edu/rgbd-dataset/trd5326jglrepxk649ed/rgbd-dataset_full/README.txt 190 | * [ndarray]: https://github.com/deeplearningais/ndarray 191 | * [thrust]: http://code.google.com/p/thrust/ 192 | * [mdbq]: https://github.com/temporaer/MDBQ 193 | * [hyperopt]: https://github.com/jaberg/hyperopt 194 | * [vigra]: http://hci.iwr.uni-heidelberg.de/vigra/ 195 | * [matlab-imread]: http://www.mathworks.de/de/help/matlab/ref/imread.html 196 | 197 | */ 198 | -------------------------------------------------------------------------------- /src/curfil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | # http://stackoverflow.com/questions/1435953/how-can-i-pass-git-sha1-to-compiler-as-definition-using-cmake/4318642#4318642 27 | include(GetGitRevisionDescription) 28 | get_git_head_revision(GIT_REFSPEC GIT_SHA1) 29 | 30 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" @ONLY) 31 | 32 | IF(MDBQ_FOUND) 33 | SET (MDBQ_FILES hyperopt.cpp) 34 | ELSE() 35 | SET (MDBQ_FILES ) 36 | SET (MDBQ_LIBRARIES ) 37 | ENDIF() 38 | 39 | CUDA_ADD_LIBRARY(curfil SHARED random_tree_image_gpu.cu random_tree.cpp image.cpp utils.cpp ndarray_ops.cpp random_tree_image.cpp random_forest_image.cpp import.cpp export.cpp predict.cpp ndarray_ops.cpp train.cpp ${MDBQ_FILES} "${CMAKE_CURRENT_BINARY_DIR}/version.cpp") 40 | 41 | TARGET_LINK_LIBRARIES(curfil ndarray ${VIGRA_IMPEX_LIBRARY} ${TBB_LIBRARIES} Boost::filesystem Boost::iostreams Boost::date_time ${MDBQ_LIBRARIES} pthread ${CUDA_LIBRARIES} ) 42 | 43 | INSTALL(TARGETS curfil 44 | DESTINATION "lib" 45 | ) 46 | 47 | INSTALL(FILES random_tree.h random_tree_image.h random_forest_image.h image.h score.h random_tree_image_gpu.h predict.h import.h export.h utils.h 48 | DESTINATION "include/curfil" 49 | ) 50 | 51 | ADD_EXECUTABLE(curfil_train train_main.cpp) 52 | TARGET_LINK_LIBRARIES(curfil_train curfil Boost::program_options) 53 | 54 | ADD_EXECUTABLE(curfil_predict predict_main.cpp) 55 | TARGET_LINK_LIBRARIES(curfil_predict curfil Boost::program_options) 56 | 57 | INSTALL(TARGETS curfil_train curfil_predict 58 | DESTINATION "bin" 59 | ) 60 | 61 | IF(MDBQ_FOUND) 62 | ADD_EXECUTABLE(curfil_hyperopt hyperopt_main.cpp) 63 | TARGET_LINK_LIBRARIES(curfil_hyperopt curfil) 64 | ENDIF() 65 | -------------------------------------------------------------------------------- /src/curfil/export.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_EXPORT_HPP 29 | #define CURFIL_EXPORT_HPP 30 | 31 | #include 32 | #include 33 | 34 | #include "random_forest_image.h" 35 | 36 | namespace curfil { 37 | 38 | /** 39 | * Helper class to export a random tree or random forest to disk in compressed (gzip) JSON format. 40 | * @ingroup import_export_trees 41 | * 42 | * @see RandomTreeImport 43 | */ 44 | class RandomTreeExport { 45 | 46 | 47 | public: 48 | 49 | /** 50 | * Prepare an export with the given configuration. 51 | * 52 | * @param configuration the configuration the random tree/forest was trained with 53 | * @param outputFolder the folder the JSON file(s) should be written to 54 | * @param trainingFolder the folder the training images were loaded from 55 | * @param verbose if true, the JSON file contains per-node profiling information. Attention: verbose JSON files are significantly larger even if compressed. 56 | */ 57 | RandomTreeExport(const TrainingConfiguration& configuration, const std::string& outputFolder, 58 | const std::string& trainingFolder, bool verbose); 59 | 60 | /** 61 | * Export the given random tree to disk as compressed (gzip) JSON file. 62 | * 63 | * @param tree the random tree which is usually part of a random forest 64 | * @param treeNr the number (id) of the tree in the random forest. Use 0 if the tree is not part of a forest. 65 | */ 66 | void writeJSON(const RandomTreeImage& tree, size_t treeNr) const; 67 | 68 | /** 69 | * Export the given random forest to disk as compressed (gzip) JSON files. 70 | * Each tree of the forest is stored in a separate file. 71 | * 72 | * @param ensemble the random forest that contains several random trees 73 | */ 74 | template 75 | void writeJSON(const TreeEnsemble& ensemble) const { 76 | 77 | CURFIL_INFO("writing tree files to " << outputFolder << " (verbose: " << verbose << ")"); 78 | 79 | for (size_t treeNr = 0; treeNr < ensemble.getTrees().size(); treeNr++) { 80 | writeJSON(*(ensemble.getTree(treeNr)), treeNr); 81 | } 82 | 83 | CURFIL_INFO("wrote JSON files to " << outputFolder); 84 | } 85 | 86 | private: 87 | static std::string spaces(int level); 88 | 89 | static void writeXY(boost::property_tree::ptree& pt, const std::string& name, const XY& xy); 90 | 91 | static void writeFeatureDetails(boost::property_tree::ptree& pt, const ImageFeatureFunction& feature); 92 | 93 | static std::vector > parseProcCpuInfo(); 94 | 95 | static int getPhysicalCores(); 96 | 97 | static int getPhysicalCpus(); 98 | 99 | template 100 | static boost::property_tree::ptree toPropertyTree(const std::vector& input) { 101 | boost::property_tree::ptree propertyTree; 102 | for (const auto& v : input) { 103 | boost::property_tree::ptree c; 104 | c.put("", boost::lexical_cast(v)); 105 | propertyTree.push_back(std::make_pair("", c)); 106 | } 107 | return propertyTree; 108 | } 109 | 110 | static boost::property_tree::ptree getProcessorModelNames(); 111 | 112 | void writeTree(boost::property_tree::ptree& pt, const RandomTree& tree) const; 113 | 114 | void writeTree(boost::property_tree::ptree& pt, const RandomTreeImage& tree) const; 115 | 116 | private: 117 | 118 | const boost::posix_time::ptime date; 119 | const TrainingConfiguration& configuration; 120 | const std::string outputFolder; 121 | const std::string trainingFolder; 122 | const bool verbose; 123 | 124 | }; 125 | 126 | } 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /src/curfil/hyperopt.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_HYPEROPT 29 | #define CURFIL_HYPEROPT 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "image.h" 36 | #include "predict.h" 37 | #include "random_forest_image.h" 38 | #include "random_tree_image.h" 39 | 40 | namespace curfil { 41 | 42 | bool continueSearching(const std::vector& currentBestAccuracies, 43 | const std::vector& currentRunAccuracies); 44 | 45 | enum LossFunctionType { 46 | CLASS_ACCURACY, // 47 | CLASS_ACCURACY_WITHOUT_VOID, // 48 | PIXEL_ACCURACY, // 49 | PIXEL_ACCURACY_WITHOUT_VOID // 50 | }; 51 | 52 | /** 53 | * Class that stores the results of a hyperopt run 54 | * @ingroup hyperopt 55 | */ 56 | class Result { 57 | 58 | private: 59 | ConfusionMatrix confusionMatrix; 60 | double pixelAccuracy; 61 | double pixelAccuracyWithoutVoid; 62 | LossFunctionType lossFunctionType; 63 | int randomSeed; 64 | 65 | public: 66 | /** 67 | * create an instance of prediction result, including the confusion matrix and the different losses 68 | */ 69 | Result(const ConfusionMatrix& confusionMatrix, double pixelAccuracy, 70 | double pixelAccuracyWithoutVoid, const LossFunctionType lossFunctionType) : 71 | confusionMatrix(confusionMatrix), 72 | pixelAccuracy(pixelAccuracy), 73 | pixelAccuracyWithoutVoid(pixelAccuracyWithoutVoid), 74 | lossFunctionType(lossFunctionType), 75 | randomSeed(0) { 76 | } 77 | 78 | /** 79 | * @return the BSON representation of the Result object 80 | */ 81 | mongo::BSONObj toBSON() const; 82 | 83 | /** 84 | * @return the computed confusion matrix 85 | */ 86 | const ConfusionMatrix& getConfusionMatrix() const { 87 | return confusionMatrix; 88 | } 89 | 90 | /** 91 | * set the loss type, can be pixel or class accuracy, with or without void 92 | */ 93 | void setLossFunctionType(const LossFunctionType& lossFunctionType) { 94 | this->lossFunctionType = lossFunctionType; 95 | } 96 | 97 | /** 98 | * @return loss value (1 - accuracy), the value depends on the loss function type 99 | */ 100 | double getLoss() const; 101 | 102 | /** 103 | * @return the average class accuracy including void 104 | */ 105 | double getClassAccuracy() const { 106 | return confusionMatrix.averageClassAccuracy(true); 107 | } 108 | 109 | /** 110 | * @return the average class accuracy excluding void and ignored colors 111 | */ 112 | double getClassAccuracyWithoutVoid() const { 113 | return confusionMatrix.averageClassAccuracy(false); 114 | } 115 | 116 | /** 117 | * @return the overall pixel accuracy including void 118 | */ 119 | double getPixelAccuracy() const { 120 | return pixelAccuracy; 121 | } 122 | 123 | /** 124 | * @return the overall pixel accuracy excluding void and ignored colors 125 | */ 126 | double getPixelAccuracyWithoutVoid() const { 127 | return pixelAccuracyWithoutVoid; 128 | } 129 | 130 | /** 131 | * save the random seed thatt was used in training 132 | */ 133 | void setRandomSeed(int randomSeed) { 134 | this->randomSeed = randomSeed; 135 | } 136 | 137 | /** 138 | * @return the random seed stored 139 | */ 140 | int getRandomSeed() const { 141 | return randomSeed; 142 | } 143 | 144 | }; 145 | 146 | /** 147 | * Client that does a hyperopt parameter search 148 | * @ingroup hyperopt 149 | */ 150 | class HyperoptClient: public mdbq::Client { 151 | 152 | private: 153 | 154 | const std::vector& allRGBDImages; 155 | const std::vector& allTestImages; 156 | 157 | bool useCIELab; 158 | bool useDepthFilling; 159 | std::vector deviceIds; 160 | int maxImages; 161 | int imageCacheSizeMB; 162 | int randomSeed; 163 | int numThreads; 164 | std::string subsamplingType; 165 | std::vector ignoredColors; 166 | bool useDepthImages; 167 | bool horizontalFlipping; 168 | size_t numLabels; 169 | LossFunctionType lossFunction; 170 | bool useLabelsPrior; 171 | 172 | boost::asio::io_service ios; 173 | 174 | RandomForestImage train(size_t trees, 175 | const TrainingConfiguration& configuration, 176 | const std::vector& trainImages); 177 | 178 | void randomSplit(const int randomSeed, const double testRatio, 179 | std::vector& trainImages, 180 | std::vector& testImages); 181 | 182 | double measureTrueLoss(unsigned int numTrees, TrainingConfiguration configuration, 183 | const double histogramBias, double& variance); 184 | 185 | const Result test(const RandomForestImage& randomForest, 186 | const std::vector& testImages); 187 | 188 | double getParameterDouble(const mongo::BSONObj& task, const std::string& field); 189 | 190 | static double getAverageLossAndVariance(const std::vector& results, double& variance); 191 | 192 | static LossFunctionType parseLossFunction(const std::string& lossFunction); 193 | 194 | public: 195 | 196 | /** 197 | * create a hyperopt client using the parameters provided by the user 198 | */ 199 | HyperoptClient( 200 | const std::vector& allRGBDImages, 201 | const std::vector& allTestImages, 202 | bool useCIELab, 203 | bool useDepthFilling, 204 | const std::vector& deviceIds, 205 | int maxImages, 206 | int imageCacheSizeMB, 207 | int randomSeed, 208 | int numThreads, 209 | const std::string& subsamplingType, 210 | const std::vector& ignoredColors, 211 | bool useDepthImages, 212 | bool horizontalFlipping, 213 | size_t numLabels, 214 | const std::string& lossFunction, 215 | bool useLabelsPrior, 216 | const std::string& url, const std::string& db, const mongo::BSONObj& jobSelector) : 217 | Client(url, db, jobSelector), 218 | allRGBDImages(allRGBDImages), 219 | allTestImages(allTestImages), 220 | useCIELab(useCIELab), 221 | useDepthFilling(useDepthFilling), 222 | deviceIds(deviceIds), 223 | maxImages(maxImages), 224 | imageCacheSizeMB(imageCacheSizeMB), 225 | randomSeed(randomSeed), 226 | numThreads(numThreads), 227 | subsamplingType(subsamplingType), 228 | ignoredColors(ignoredColors), 229 | useDepthImages(useDepthImages), 230 | horizontalFlipping(horizontalFlipping), 231 | numLabels(numLabels), 232 | lossFunction(parseLossFunction(lossFunction)), 233 | useLabelsPrior(useLabelsPrior) 234 | { 235 | } 236 | 237 | /** 238 | * do a number of train and test runs using the task parameters 239 | */ 240 | void handle_task(const mongo::BSONObj& task); 241 | 242 | void run(); /**< continuously get the next task and handle it */ 243 | }; 244 | 245 | } 246 | 247 | #endif 248 | -------------------------------------------------------------------------------- /src/curfil/hyperopt_main.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include 29 | #include 30 | 31 | #include "hyperopt.h" 32 | #include "image.h" 33 | #include "utils.h" 34 | #include "version.h" 35 | 36 | namespace po = boost::program_options; 37 | 38 | using namespace curfil; 39 | 40 | int main(int argc, char **argv) { 41 | 42 | std::string url; 43 | std::string db; 44 | std::string experiment; 45 | std::string trainingFolder; 46 | std::string testingFolder; 47 | int maxImages = 0; 48 | int imageCacheSizeMB = 0; 49 | int randomSeed = 4711; 50 | int numThreads; 51 | std::string subsamplingType; 52 | std::vector ignoredColors; 53 | bool useCIELab = true; 54 | bool useDepthFilling = false; 55 | int deviceId = 0; 56 | bool profiling = false; 57 | bool useDepthImages = true; 58 | std::string lossFunction; 59 | bool horizontalFlipping = false; 60 | bool useLabelsPrior = true; 61 | 62 | // Declare the supported options. 63 | po::options_description options("options"); 64 | options.add_options() 65 | ("help", "produce help message") 66 | ("version", "show version and exit") 67 | ("url", po::value(&url)->required(), "MongoDB url") 68 | ("db", po::value(&db)->required(), "database name") 69 | ("deviceId", po::value(&deviceId)->default_value(deviceId), "GPU device id") 70 | ("experiment", po::value(&experiment)->required(), "experiment name") 71 | ("trainingFolder", po::value(&trainingFolder)->required(), "folder with training images") 72 | ("testingFolder", po::value(&testingFolder)->required(), "folder with testing images") 73 | ("maxImages", po::value(&maxImages)->default_value(maxImages), 74 | "maximum number of images to load for training. set to 0 if all images should be loaded") 75 | ("imageCacheSize", po::value(&imageCacheSizeMB)->default_value(imageCacheSizeMB), 76 | "image cache size on GPU in MB. 0 means automatic adjustment") 77 | ("subsamplingType", po::value(&subsamplingType), "subsampling type: 'pixelUniform' or 'classUniform'") 78 | ("useCIELab", po::value(&useCIELab)->default_value(useCIELab), "convert images to CIE lab space") 79 | ("useDepthFilling", po::value(&useDepthFilling)->implicit_value(true)->default_value(useDepthFilling), 80 | "whether to do simple depth filling") 81 | ("randomSeed", po::value(&randomSeed)->default_value(randomSeed), "random seed") 82 | ("profile", po::value(&profiling)->implicit_value(true)->default_value(profiling), "profiling") 83 | ("ignoreColor", po::value >(&ignoredColors), 84 | "do not sample pixels of this color. Format: R,G,B in the range 0-255.") 85 | 86 | ("lossFunction", po::value(&lossFunction)->required(), 87 | "measure the loss function should be based on. one of 'classAccuracy', 'classAccuracyWithoutVoid', 'pixelAccuracy', 'pixelAccuracyWithoutVoid'") 88 | ("numThreads", po::value(&numThreads)->default_value(tbb::task_scheduler_init::default_num_threads()), 89 | "number of threads") 90 | ("useDepthImages", po::value(&useDepthImages)->implicit_value(true)->default_value(useDepthImages), 91 | "whether to use depth images") 92 | ("horizontalFlipping", po::value(&horizontalFlipping)->implicit_value(false)->default_value(horizontalFlipping), 93 | "whether to horizontally flip features") 94 | ("useLabelsPrior", po::value(&useLabelsPrior)->implicit_value(true)->default_value(useLabelsPrior), 95 | "whether to mutliply the trees histograms by labels prior") 96 | ; 97 | 98 | po::variables_map vm; 99 | po::store(po::command_line_parser(argc, argv).options(options).run(), vm); 100 | 101 | if (argc <= 1 || vm.count("help")) { 102 | std::cout << options << std::endl; 103 | return EXIT_FAILURE; 104 | } 105 | 106 | if (argc <= 1 || vm.count("version")) { 107 | std::cout << argv[0] << " version " << getVersion() << std::endl; 108 | return EXIT_FAILURE; 109 | } 110 | 111 | try { 112 | po::notify(vm); 113 | } catch (const std::exception& e) { 114 | std::cerr << e.what() << std::endl; 115 | return EXIT_FAILURE; 116 | } 117 | 118 | logVersionInfo(); 119 | 120 | utils::Profile::setEnabled(profiling); 121 | 122 | CURFIL_INFO("used loss function is " << lossFunction); 123 | 124 | tbb::task_scheduler_init init(numThreads); 125 | 126 | size_t numLabels; 127 | size_t numLabelsTesting; 128 | 129 | const auto trainImages = loadImages(trainingFolder, useCIELab, useDepthImages, useDepthFilling, ignoredColors, numLabels); 130 | const auto testImages = loadImages(testingFolder, useCIELab, useDepthImages, useDepthFilling, ignoredColors, numLabelsTesting); 131 | 132 | // currently training on only on GPU is tested 133 | std::vector deviceIds(1, deviceId); 134 | 135 | HyperoptClient client(trainImages, testImages, useCIELab, useDepthFilling, deviceIds, maxImages, imageCacheSizeMB, 136 | randomSeed, numThreads, subsamplingType, ignoredColors, useDepthImages, horizontalFlipping, numLabels, lossFunction, useLabelsPrior, url, db, 137 | BSON("exp_key" << experiment)); 138 | client.run(); 139 | 140 | CURFIL_INFO("finished"); 141 | return EXIT_SUCCESS; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /src/curfil/import.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include "import.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | namespace curfil { 41 | 42 | XY RandomTreeImport::readXY(const boost::property_tree::ptree& pt) { 43 | if (pt.size() != 2) { 44 | throw std::runtime_error(boost::str(boost::format("unexpected size: %d") % pt.size())); 45 | } 46 | 47 | int x = pt.front().second.get_value(); 48 | int y = pt.back().second.get_value(); 49 | return XY(x, y); 50 | } 51 | 52 | SplitFunction RandomTreeImport::parseSplit(const boost::property_tree::ptree& pt) { 53 | 54 | float threshold = pt.get("threshold"); 55 | ScoreType score = pt.get("score"); 56 | size_t featureId = pt.get("featureId"); 57 | 58 | const boost::property_tree::ptree featureTree = pt.get_child("feature"); 59 | 60 | const std::string featureTypeName = featureTree.get("type"); 61 | FeatureType featureType; 62 | if (featureTypeName == "color") { 63 | featureType = FeatureType::COLOR; 64 | } 65 | else if (featureTypeName == "depth") { 66 | featureType = FeatureType::DEPTH; 67 | } else { 68 | throw std::runtime_error(std::string("illegal feature type: " + featureTypeName)); 69 | } 70 | 71 | Offset offset1, offset2; 72 | Region region1, region2; 73 | 74 | if (featureTypeName == "color" || featureTypeName == "depth") { 75 | offset1 = readXY(featureTree.get_child("offset1")); 76 | offset2 = readXY(featureTree.get_child("offset2")); 77 | 78 | region1 = readXY(featureTree.get_child("region1")); 79 | region2 = readXY(featureTree.get_child("region2")); 80 | } 81 | 82 | uint8_t channel1 = 0; 83 | uint8_t channel2 = 0; 84 | 85 | if (featureType == FeatureType::COLOR) { 86 | channel1 = featureTree.get("channel1"); 87 | channel2 = featureTree.get("channel2"); 88 | } 89 | 90 | ImageFeatureFunction feature(featureType, offset1, region1, channel1, offset2, region2, channel2); 91 | 92 | SplitFunction split(featureId, feature, threshold, score); 93 | return split; 94 | } 95 | 96 | boost::shared_ptr > RandomTreeImport::readTree( 97 | const boost::property_tree::ptree& pt, 98 | const boost::shared_ptr >& parent) { 99 | int id = pt.get("id"); 100 | int level = pt.get("level"); 101 | WeightType numSamples = pt.get("samples"); 102 | 103 | WeightType sumHistogram = 0; 104 | const boost::property_tree::ptree histogramChild = pt.get_child("histogram"); 105 | const size_t numClasses = histogramChild.size(); 106 | 107 | std::vector histogram(numClasses, 0); 108 | 109 | boost::property_tree::ptree::const_iterator it; 110 | for (it = histogramChild.begin(); it != histogramChild.end(); it++) { 111 | 112 | // key is in the format: "255,255,255 (1)" 113 | const std::string& key = it->first; 114 | 115 | RGBColor color; 116 | try { 117 | color = RGBColor(key.substr(0, key.find(" "))); 118 | } catch (const std::exception& e) { 119 | throw std::runtime_error(std::string("failed to parse histogram key: '") + key + "': " + e.what()); 120 | } 121 | 122 | size_t start = key.find(" (") + 2; 123 | size_t stop = key.find(")", start); 124 | const std::string labelString = key.substr(start, stop - start); 125 | 126 | const LabelType label = getOrAddColorId(color, boost::lexical_cast(labelString)); 127 | assert(label < numClasses); 128 | 129 | if (histogram[label] != 0) { 130 | std::ostringstream o; 131 | o << "node: " << id << ": "; 132 | o << "illegal histogram state for " << key <<" (label: " << label << "): " << histogram[label]; 133 | throw std::runtime_error(o.str()); 134 | } 135 | 136 | const WeightType num = histogramChild.get(key); 137 | histogram[label] = num; 138 | 139 | sumHistogram += num; 140 | } 141 | 142 | // This was changed from ne because the histogram sum is larger since at the end of 143 | // training, all pixels were classified (this is the case when using "improveHistograms at the end"). 144 | // Should check if numSamples should be changed to reflect all pixels count, and then can use lt 145 | if (sumHistogram < numSamples) { 146 | throw std::runtime_error("incorrect histogram sum"); 147 | } 148 | 149 | boost::shared_ptr > tree = boost::make_shared< 150 | RandomTree >(id, level, parent, histogram); 151 | 152 | if (pt.find("left") != pt.not_found()) { 153 | const auto split = parseSplit(pt.get_child("split")); 154 | auto left = readTree(pt.get_child("left"), tree); 155 | auto right = readTree(pt.get_child("right"), tree); 156 | tree->addChildren(split, left, right); 157 | } 158 | 159 | return tree; 160 | } 161 | 162 | cuv::ndarray RandomTreeImport::readClassLabelPriorDistribution( 163 | const boost::property_tree::ptree& p) { 164 | cuv::ndarray classLabelPriorDistribution(p.size()); 165 | 166 | boost::property_tree::ptree::const_iterator it; 167 | for (it = p.begin(); it != p.end(); it++) { 168 | const std::string& key = it->first; 169 | classLabelPriorDistribution[boost::lexical_cast(key)] = p.get(key); 170 | } 171 | 172 | return classLabelPriorDistribution; 173 | } 174 | 175 | TrainingConfiguration RandomTreeImport::readJSON(const std::string& filename, 176 | boost::shared_ptr& tree, 177 | std::string& hostname, 178 | boost::filesystem::path& folderTraining, 179 | boost::posix_time::ptime& date) { 180 | 181 | if (!boost::filesystem::is_regular_file(filename)) { 182 | throw std::runtime_error(std::string("failed to read tree file: '") + filename + "' is not a regular file"); 183 | } 184 | 185 | boost::property_tree::ptree pt; 186 | 187 | boost::iostreams::filtering_istream istream; 188 | 189 | if (boost::algorithm::ends_with(filename, ".gz")) { 190 | istream.push(boost::iostreams::gzip_decompressor()); 191 | } 192 | istream.push(boost::iostreams::file_source(filename)); 193 | 194 | boost::property_tree::read_json(istream, pt); 195 | 196 | date = boost::posix_time::time_from_string(pt.get("date")); 197 | folderTraining = pt.get("folderTraining"); 198 | hostname = pt.get("hostname"); 199 | int randomSeed = pt.get("randomSeed"); 200 | unsigned int samplesPerImage = pt.get("samplesPerImage"); 201 | unsigned int featureCount = pt.get("featureCount"); 202 | unsigned int minSampleCount = pt.get("minSampleCount"); 203 | int maxDepth = pt.get("maxDepth"); 204 | uint16_t boxRadius = pt.get("boxRadius"); 205 | uint16_t regionSize = pt.get("regionSize"); 206 | uint16_t thresholds = pt.get("thresholds"); 207 | int numThreads = pt.get("numThreads"); 208 | int imageCacheSize = pt.get("imageCacheSize"); 209 | 210 | bool useCIELab = true; 211 | const boost::optional useCIELabValue = pt.get_optional("useCIELab"); 212 | if (useCIELabValue) { 213 | useCIELab = useCIELabValue.get(); 214 | } 215 | 216 | bool useDepthFilling = false; 217 | const boost::optional useDepthFillingValue = pt.get_optional("useDepthFilling"); 218 | if (useDepthFillingValue) { 219 | useDepthFilling = useDepthFillingValue.get(); 220 | } 221 | 222 | int maxImages = 0; 223 | const boost::optional maxImagesValue = pt.get_optional("maxImages"); 224 | if (maxImagesValue) { 225 | maxImages = maxImagesValue.get(); 226 | } 227 | 228 | const boost::optional subsamplingTypeValue = pt.get_optional("subsamplingType"); 229 | std::string subsamplingType = "pixelUniform"; 230 | if (subsamplingTypeValue) { 231 | subsamplingType = subsamplingTypeValue.get(); 232 | } 233 | 234 | unsigned int maxSamplesPerBatch = pt.get("maxSamplesPerBatch"); 235 | const std::string accelerationModeString = pt.get("accelerationMode"); 236 | 237 | const cuv::ndarray classLabelPriorDistribution = 238 | readClassLabelPriorDistribution( 239 | pt.get_child("classLabelPriorDistribution")); 240 | 241 | const std::vector ignoredColors = fromPropertyTree( 242 | pt.get_child_optional("ignoredColors")); 243 | 244 | const std::vector deviceIds = fromPropertyTree(pt.get_child_optional("deviceIds"), std::vector(1, 0)); 245 | 246 | bool useDepthImages = true; 247 | const boost::optional useDepthImagesValue = pt.get_optional("useDepthImages"); 248 | if (useDepthImagesValue) { 249 | useDepthImages = useDepthImagesValue.get(); 250 | } 251 | 252 | //TODO: remove 253 | //useDepthImages = false; 254 | 255 | TrainingConfiguration configuration(randomSeed, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 256 | regionSize, thresholds, numThreads, maxImages, imageCacheSize, maxSamplesPerBatch, 257 | TrainingConfiguration::parseAccelerationModeString(accelerationModeString), useCIELab, useDepthFilling, 258 | deviceIds, subsamplingType, ignoredColors, useDepthImages); 259 | 260 | boost::shared_ptr > randomTree = readTree(pt.get_child("tree")); 261 | assert(randomTree->isRoot()); 262 | 263 | tree = boost::make_shared(randomTree, configuration, classLabelPriorDistribution); 264 | 265 | return configuration; 266 | } 267 | 268 | } 269 | -------------------------------------------------------------------------------- /src/curfil/import.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_IMPORT_HPP 29 | #define CURFIL_IMPORT_HPP 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "random_forest_image.h" 37 | 38 | namespace curfil { 39 | 40 | /** 41 | * Helper class to import a random tree or random forest from disk in compressed (gzip) JSON format. 42 | * @ingroup import_export_trees 43 | * 44 | * @see RandomTreeExport 45 | */ 46 | class RandomTreeImport { 47 | 48 | 49 | public: 50 | 51 | /** 52 | * load (deserialize) a random tree from disk, stored in compressed JSON format 53 | */ 54 | static TrainingConfiguration readJSON(const std::string& filename, boost::shared_ptr& tree, 55 | std::string& hostname, 56 | boost::filesystem::path& folderTraining, 57 | boost::posix_time::ptime& date); 58 | 59 | private: 60 | 61 | static XY readXY(const boost::property_tree::ptree& pt); 62 | 63 | static SplitFunction parseSplit(const boost::property_tree::ptree& pt); 64 | 65 | static boost::shared_ptr > readTree( 66 | const boost::property_tree::ptree& pt, 67 | const boost::shared_ptr >& parent = boost::shared_ptr< 68 | RandomTree >()); 69 | 70 | template 71 | static std::vector fromPropertyTree(const boost::optional& propertyTree, 72 | const std::vector defaultValue = std::vector()) { 73 | 74 | std::vector values = defaultValue; 75 | 76 | if (propertyTree) { 77 | boost::property_tree::ptree::const_iterator it; 78 | for (it = propertyTree.get().begin(); it != propertyTree.get().end(); it++) { 79 | values.push_back(it->second.get_value()); 80 | } 81 | } 82 | 83 | return values; 84 | } 85 | 86 | static cuv::ndarray readClassLabelPriorDistribution( 87 | const boost::property_tree::ptree& p); 88 | 89 | }; 90 | 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/curfil/ndarray_ops.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include "ndarray_ops.h" 29 | 30 | namespace cuv { 31 | 32 | template 33 | void fill(cuv::ndarray& v, const V& p) { 34 | for (size_t i = 0; i < v.size(); i++) { 35 | v[i] = p; 36 | } 37 | } 38 | 39 | } 40 | 41 | namespace curfil 42 | { 43 | 44 | template 45 | void add_ndarrays( 46 | cuv::ndarray& a, 47 | const cuv::ndarray& b, 48 | cuv::host_memory_space) { 49 | if (a.shape() != b.shape()) { 50 | throw std::runtime_error("can not add tensors with different shapes"); 51 | } 52 | for (size_t i = 0; i < a.size(); i++) { 53 | a[i] += b[i]; 54 | } 55 | } 56 | 57 | template 58 | cuv::ndarray& 59 | operator+=(cuv::ndarray& a, const cuv::ndarray& b) { 60 | add_ndarrays(a, b, memory_space()); 61 | return a; 62 | } 63 | 64 | } 65 | 66 | #define CUV_NDARRAY_OPS_INST(T, M) \ 67 | template cuv::ndarray& curfil::operator+=(cuv::ndarray&, const cuv::ndarray&); \ 68 | template void cuv::fill(cuv::ndarray&, const T&); \ 69 | template void curfil::add_ndarrays(cuv::ndarray&, const cuv::ndarray&, M); 70 | 71 | CUV_NDARRAY_OPS_INST(double, cuv::host_memory_space) 72 | ; 73 | CUV_NDARRAY_OPS_INST(float, cuv::host_memory_space) 74 | ; 75 | CUV_NDARRAY_OPS_INST(int, cuv::host_memory_space) 76 | ; 77 | CUV_NDARRAY_OPS_INST(unsigned int, cuv::host_memory_space) 78 | ; 79 | CUV_NDARRAY_OPS_INST(unsigned char, cuv::host_memory_space) 80 | ; 81 | -------------------------------------------------------------------------------- /src/curfil/ndarray_ops.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_NDARRAY_OPS_H 29 | #define CURFIL_NDARRAY_OPS_H 30 | 31 | #include 32 | 33 | namespace curfil { 34 | 35 | template 36 | void add_ndarrays(cuv::ndarray& a, 37 | const cuv::ndarray& b, cuv::host_memory_space); 38 | 39 | template 40 | cuv::ndarray& 41 | operator+=(cuv::ndarray& a, const cuv::ndarray& b); 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/curfil/predict.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_PREDICT 29 | #define CURFIL_PREDICT 30 | 31 | #include 32 | #include 33 | 34 | #include "random_forest_image.h" 35 | 36 | namespace curfil { 37 | 38 | /** 39 | * Helper class to maintain a n×n confusion matrix. 40 | * @ingroup prediction_results 41 | * 42 | * 43 | * Construction of the confusion matrix is usually a two-phase process. 44 | * 1. Increment the label/prediction counters 45 | * 2. Normalize the confusion matrix such that the sum over the predictions for every class is 1. 46 | */ 47 | class ConfusionMatrix { 48 | 49 | public: 50 | 51 | /** 52 | * Create an empty confusion matrix that can later be resized with resize(). 53 | */ 54 | explicit ConfusionMatrix() : 55 | data(), normalized(false) { 56 | } 57 | 58 | /** 59 | * create a confusion matrix using the attribute values of another matrix 60 | */ 61 | explicit ConfusionMatrix(const ConfusionMatrix& other) : 62 | data(other.data.copy()), normalized(other.normalized), ignoredLabels(other.ignoredLabels) { 63 | } 64 | 65 | /** 66 | * Create a confusion matrix of size numClasses × numClasses with zero initial values. 67 | */ 68 | explicit ConfusionMatrix(size_t numClasses) : 69 | data(numClasses, numClasses), normalized(false) { 70 | assert(numClasses > 0); 71 | reset(); 72 | } 73 | 74 | /** 75 | * Create a confusion matrix of size numClasses x numClasses and sets which labels should be ignored in the calculations 76 | */ 77 | explicit ConfusionMatrix(size_t numClasses, std::vector ignoredLabels) : 78 | data(numClasses, numClasses), normalized(false), ignoredLabels(ignoredLabels) { 79 | assert(numClasses > 0); 80 | reset(); 81 | } 82 | 83 | /** 84 | * copies the attribute values of another confusion matrix 85 | */ 86 | ConfusionMatrix& operator=(const ConfusionMatrix& other) { 87 | data = other.data.copy(); 88 | normalized = other.normalized; 89 | ignoredLabels = other.ignoredLabels; 90 | return *this; 91 | } 92 | 93 | /** 94 | * Reset all per-class counters to zero. 95 | */ 96 | void reset(); 97 | 98 | /** 99 | * Resize the confusion matrix. This operation implies a reset. 100 | * 101 | * @param numClasses resize the confusion matrix to numClasses × numClasses. 102 | */ 103 | void resize(unsigned int numClasses); 104 | 105 | /** 106 | * @return true if and only if the confusion matrix was normalized. 107 | * @see normalize() 108 | */ 109 | bool isNormalized() const { 110 | return normalized; 111 | } 112 | 113 | /** 114 | * adds the data values of another confusion matrix 115 | */ 116 | void operator+=(const ConfusionMatrix& other); 117 | 118 | /** 119 | * @return the probability and host_memory_space associated with the true and predicted classes 120 | */ 121 | cuv::reference 122 | operator()(int label, int prediction) { 123 | return data(label, prediction); 124 | } 125 | 126 | /** 127 | * @return the probability associated with the true and predicted classes 128 | */ 129 | double operator()(int label, int prediction) const { 130 | return data(label, prediction); 131 | } 132 | 133 | /** 134 | * Increment the counter in the matrix for the given label and the prediction. 135 | * Increment can only be used before the confusion matrix is normalized! 136 | */ 137 | void increment(int label, int prediction) { 138 | if (normalized) { 139 | throw std::runtime_error("confusion matrix is already normalized"); 140 | } 141 | assert(label < static_cast(getNumClasses())); 142 | assert(prediction < static_cast(getNumClasses())); 143 | (data(label, prediction))++; 144 | } 145 | 146 | /** 147 | * @return n for a confusion matrix of size n×n 148 | */ 149 | unsigned int getNumClasses() const { 150 | assert(data.ndim() == 2); 151 | assert(data.shape(0) == data.shape(1)); 152 | return data.shape(0); 153 | } 154 | 155 | /** 156 | * Normalizes the confusion matrix such that the sum of the predictions equals one for every label (class). 157 | */ 158 | void normalize(); 159 | 160 | /** 161 | * Calculate the average per-class accuracy which is equal to the average over the diagonal. 162 | * 163 | * @param includeVoid if false, the class 0 is excluded in the calculation. 164 | */ 165 | double averageClassAccuracy(bool includeVoid = true) const; 166 | 167 | private: 168 | cuv::ndarray data; 169 | bool normalized; 170 | std::vector ignoredLabels; 171 | 172 | }; 173 | 174 | /** 175 | * Calculates the average pixel accuracy on 'prediction' according to the ground truth. 176 | * Predictions where the ground truth contains 'void' (black pixels) are not counted if 'includeVoid' is set to false. 177 | * The confusion matrix is stored to 'confusionMatrix' if not NULL. 178 | */ 179 | double calculatePixelAccuracy(const LabelImage& prediction, const LabelImage& groundTruth, 180 | const bool includeVoid = true, const std::vector* ignoredLabels= NULL, ConfusionMatrix* confusionMatrix = 0); 181 | 182 | /** 183 | * Helper method to run a prediction for all images in the given test folder for the given trained random forest. 184 | * 185 | * @param randomForest the random forest that was obtained by a training or loaded from disk. 186 | * @param folderTesting the folder that contains test images. 187 | * @param folderPrediction the folder where to store the prediction images to 188 | * @param useDepthFilling whether to run simple depth filling before prediction 189 | * @param writeProbabilityImages whether to store per-class probability images in the prediction folder 190 | */ 191 | void test(RandomForestImage& randomForest, const std::string& folderTesting, 192 | const std::string& folderPrediction, const bool useDepthFilling, 193 | const bool writeProbabilityImages); 194 | 195 | } 196 | 197 | std::ostream& operator<<(std::ostream& o, const curfil::ConfusionMatrix& confusionMatrix); 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /src/curfil/predict_main.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include "predict.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "import.h" 37 | #include "random_forest_image.h" 38 | #include "random_tree_image.h" 39 | #include "utils.h" 40 | #include "version.h" 41 | 42 | namespace po = boost::program_options; 43 | 44 | using namespace curfil; 45 | 46 | static void initDevice(int deviceId) { 47 | cudaDeviceProp prop; 48 | 49 | int currentDeviceId; 50 | cudaGetDevice(¤tDeviceId); 51 | if (deviceId != currentDeviceId) { 52 | CURFIL_INFO("switching from device " << currentDeviceId << " to " << deviceId) 53 | cudaSafeCall(cudaSetDevice(deviceId)); 54 | } 55 | cudaSafeCall(cudaGetDeviceProperties(&prop, deviceId)); 56 | CURFIL_INFO("GPU Device: " << prop.name); 57 | } 58 | 59 | int main(int argc, char **argv) { 60 | 61 | std::string folderPrediction = ""; 62 | std::string folderTesting; 63 | std::vector treeFiles; 64 | int numThreads; 65 | double histogramBias = 0.0; 66 | bool profiling = false; 67 | std::string modeString = "gpu"; 68 | int deviceId = 0; 69 | bool useDepthFillingOption = false; 70 | bool writeProbabilityImages = false; 71 | bool useLabelsPrior = true; 72 | 73 | // Declare the supported options. 74 | po::options_description options("options"); 75 | options.add_options() 76 | ("help", "produce help message") 77 | ("version", "show version and exit") 78 | ("folderPrediction", po::value(&folderPrediction)->default_value(folderPrediction), 79 | "folder to output prediction images. leave it empty to suppress writing of prediction images") 80 | ("folderTesting", po::value(&folderTesting)->required(), "folder with test images") 81 | ("treeFile", po::value >(&treeFiles)->required(), "serialized tree(s) (JSON)") 82 | ("histogramBias", po::value(&histogramBias)->default_value(histogramBias), "histogram bias") 83 | ("numThreads", po::value(&numThreads)->default_value(tbb::task_scheduler_init::default_num_threads()), 84 | "number of threads") 85 | ("mode", po::value(&modeString)->default_value(modeString), "mode: 'cpu' or 'gpu'") 86 | ("deviceId", po::value(&deviceId)->default_value(deviceId), "GPU device id") 87 | ("profile", po::value(&profiling)->implicit_value(true)->default_value(profiling), "profiling") 88 | ("useDepthFilling", 89 | po::value(&useDepthFillingOption)->implicit_value(true)->default_value(useDepthFillingOption), 90 | "whether to do simple depth filling") 91 | ("writeProbabilityImages", 92 | po::value(&writeProbabilityImages)->implicit_value(true)->default_value(writeProbabilityImages), 93 | "whether to write probability PNGs of the prediction") 94 | ("useLabelsPrior", po::value(&useLabelsPrior)->implicit_value(true)->default_value(useLabelsPrior), 95 | "whether to mulitply the trees histograms by labels prior") 96 | ; 97 | 98 | po::positional_options_description pod; 99 | pod.add("folderPrediction", 1); 100 | pod.add("folderTesting", 1); 101 | pod.add("treeFile", -1); 102 | 103 | po::variables_map vm; 104 | po::store(po::command_line_parser(argc, argv).positional(pod).options(options).run(), vm); 105 | 106 | if (argc <= 1 || vm.count("help")) { 107 | std::cout << options << std::endl; 108 | return EXIT_FAILURE; 109 | } 110 | 111 | if (argc <= 1 || vm.count("version")) { 112 | std::cout << argv[0] << " version " << getVersion() << std::endl; 113 | return EXIT_FAILURE; 114 | } 115 | 116 | try { 117 | po::notify(vm); 118 | } catch (const std::exception& e) { 119 | std::cerr << e.what() << std::endl; 120 | return EXIT_FAILURE; 121 | } 122 | 123 | logVersionInfo(); 124 | 125 | if (histogramBias < 0.0 || histogramBias >= 1.0) { 126 | throw std::runtime_error(boost::str(boost::format("illegal histogram bias: %lf") % histogramBias)); 127 | } 128 | 129 | if (writeProbabilityImages && folderPrediction.empty()) { 130 | throw std::runtime_error("specified to write probability images but prediction folder was not set"); 131 | } 132 | 133 | CURFIL_INFO("histogramBias: " << histogramBias); 134 | CURFIL_INFO("writeProbabilityImages: " << writeProbabilityImages); 135 | CURFIL_INFO("useLabelsPrior: " << useLabelsPrior); 136 | 137 | utils::Profile::setEnabled(profiling); 138 | 139 | tbb::task_scheduler_init init(numThreads); 140 | 141 | std::vector deviceIds(1, deviceId); 142 | 143 | initDevice(deviceId); 144 | 145 | AccelerationMode mode = TrainingConfiguration::parseAccelerationModeString(modeString); 146 | RandomForestImage randomForest(treeFiles, deviceIds, mode, histogramBias, useLabelsPrior); 147 | 148 | bool useDepthFilling = randomForest.getConfiguration().isUseDepthFilling(); 149 | if (vm.count("useDepthFilling")) { 150 | if (useDepthFillingOption != useDepthFilling) { 151 | if (useDepthFilling) { 152 | CURFIL_WARNING("random forest was trained with depth filling. but prediction is performed without!"); 153 | } else { 154 | CURFIL_WARNING( 155 | "random forest was NOT trained with depth filling. but prediction is performed with depth filling!"); 156 | } 157 | } 158 | // override 159 | useDepthFilling = useDepthFillingOption; 160 | } 161 | 162 | test(randomForest, folderTesting, folderPrediction, useDepthFilling, writeProbabilityImages); 163 | 164 | CURFIL_INFO("finished"); 165 | return EXIT_SUCCESS; 166 | } 167 | 168 | -------------------------------------------------------------------------------- /src/curfil/random_features.cu: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include 29 | 30 | namespace curfil { 31 | namespace gpu { 32 | 33 | __global__ 34 | void setup_kernel(int seed, curandState *state) { 35 | int id = blockIdx.x * blockDim.x + threadIdx.x; 36 | /* Each thread gets same seed, a different sequence number, no offset */ 37 | curand_init(seed, id, 0, &state[id]); 38 | } 39 | 40 | __global__ 41 | void generate_uniform_kernel(curandState* state, unsigned int* result) { 42 | int id = blockIdx.x * blockDim.x + threadIdx.x; 43 | unsigned int count = 0; 44 | float x; 45 | 46 | /* Copy state to local memory for efficiency */ 47 | curandState localState = state[id]; 48 | 49 | /* Generate pseudo-random uniforms */ 50 | for (int n = 0; n < 10000; n++) { 51 | x = curand_uniform(&localState); 52 | /* Check if > .5 */ 53 | if (x > .5) { 54 | count++; 55 | } 56 | } 57 | 58 | /* Copy state back to global memory */ 59 | state[id] = localState; 60 | 61 | /* Store results */ 62 | result[id] += count; 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/curfil/random_forest_image.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_RANDOM_FOREST_IMAGE_H 29 | #define CURFIL_RANDOM_FOREST_IMAGE_H 30 | 31 | #include 32 | #include 33 | 34 | #include "random_tree_image.h" 35 | 36 | namespace curfil { 37 | 38 | class TreeNodes; 39 | 40 | /** 41 | * A random forest for RGB-D images. 42 | * @ingroup forest_hierarchy 43 | */ 44 | class RandomForestImage { 45 | 46 | public: 47 | 48 | /** 49 | * Load the random forest from disk. 50 | * 51 | * @param treeFiles paths of JSON tree files 52 | * @param deviceIds the GPU device IDs to use for prediction 53 | * @param accelerationMode the acceleration mode to use for prediction. CPU or GPU. 54 | * @param histogramBias if larger than 0.0, apply a histogram bias (see the Wiki) after loading the forest. 55 | * @param useLabelsPrior whether to multiply histograms by the labels prior 56 | */ 57 | explicit RandomForestImage(const std::vector& treeFiles, 58 | const std::vector& deviceIds = std::vector(1, 0), 59 | const AccelerationMode accelerationMode = GPU_ONLY, 60 | const double histogramBias = 0.0, 61 | const bool useLabelsPrior = true); 62 | 63 | /** 64 | * Prepare a random forest with the given number of trees and the configuration. 65 | * 66 | * @param treeCount the number of trees in the forest 67 | * @param configuration the configuration to use for training 68 | */ 69 | explicit RandomForestImage(unsigned int treeCount, 70 | const TrainingConfiguration& configuration); 71 | 72 | /** 73 | * Construct a random forest from the given list of existing trees 74 | * 75 | * @param ensemble list of trees that should be used to construct the random forest from 76 | * @param configuration the configuration the trees were trained with 77 | */ 78 | explicit RandomForestImage(const std::vector >& ensemble, 79 | const TrainingConfiguration& configuration); 80 | 81 | /** 82 | * Starts the training process of the random forest. 83 | * 84 | * @param trainLabelImages the list of labeled images to train the random forest from 85 | * @param trainTreesSequentially whether to train the trees in the random forest in parallel or sequentially. 86 | * @param numLabels number of classes in the images 87 | */ 88 | void train(const std::vector& trainLabelImages, size_t numLabels = 0, bool trainTreesSequentially = false); 89 | 90 | /** 91 | * @param image the image which should be classified 92 | * @param prediction if not null, probabilities per class in a C×H×W matrix for C classes and an image of size W×H 93 | * @param onGPU whether prediction is done using GPUs 94 | * @param useDepthImages whether depth images are used when classifying images 95 | * @return prediction image which has the same size as 'image' 96 | */ 97 | LabelImage predict(const RGBDImage& image, 98 | cuv::ndarray* prediction = 0, 99 | const bool onGPU = true, bool useDepthImages = true) const; 100 | 101 | 102 | /** 103 | * classifies all images at the end of training - used to improve leaf distributions 104 | */ 105 | LabelImage improveHistograms(const RGBDImage& trainingImage, const LabelImage& labelImage, const bool onGPU = true, bool useDepthImages = true) const; 106 | 107 | /** 108 | * uses the allPixelsHistograms to update the trees leaves histograms - used to improve leaf distributions 109 | */ 110 | void updateTreesHistograms(); 111 | /** 112 | * @return a recursive sum of per-feature type count 113 | */ 114 | std::map countFeatures() const; 115 | 116 | /** 117 | * @return the number of classes (labels) that random forest was trained from 118 | */ 119 | LabelType getNumClasses() const; 120 | 121 | /** 122 | * @return the n-th tree in the forest where 0 ≤ treeNr < numTrees 123 | */ 124 | const boost::shared_ptr getTree(size_t treeNr) const { 125 | #ifdef NDEBUG 126 | return ensemble[treeNr]; 127 | #else 128 | return ensemble.at(treeNr); 129 | #endif 130 | } 131 | 132 | /** 133 | * @return the list of trees in the forest 134 | */ 135 | const std::vector >& getTrees() const { 136 | return ensemble; 137 | } 138 | 139 | /** 140 | * @return the configuration the random forest was trained with 141 | */ 142 | const TrainingConfiguration& getConfiguration() const { 143 | return configuration; 144 | } 145 | 146 | /** 147 | * @return whether the passed label is one of those specified by the user to be ignored 148 | */ 149 | bool shouldIgnoreLabel(const LabelType& label) const; 150 | 151 | /** 152 | * @return a map where keys are the labels and the values are the colors associated with them 153 | */ 154 | std::map getLabelColorMap() const; 155 | 156 | /** 157 | * goes over all trees and normalizes the histograms 158 | */ 159 | void normalizeHistograms(const double histogramBias, const bool useLabelsPrior); 160 | 161 | private: 162 | 163 | TrainingConfiguration configuration; 164 | 165 | std::vector > ensemble; 166 | std::vector > treeData; 167 | boost::shared_ptr m_predictionAllocator; 168 | }; 169 | 170 | } 171 | 172 | std::ostream& operator<<(std::ostream& os, const curfil::RandomForestImage& ensemble); 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /src/curfil/random_tree.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include "random_tree.h" 29 | 30 | #include 31 | #include 32 | 33 | namespace curfil { 34 | 35 | namespace detail { 36 | bool isScoreBetter(const ScoreType bestScore, const ScoreType score, const int featureNr) { 37 | double diff = fabs(score - bestScore); 38 | 39 | #ifndef NDEBUG 40 | if (diff > 0 && diff < 1e-8) { 41 | CURFIL_WARNING(boost::format("close scores: %.15f (feat %d)") % bestScore % featureNr 42 | << boost::format(" vs %.15f, diff: %.15f") % score % diff); 43 | } 44 | #endif 45 | 46 | if (diff < 1e-13) { 47 | // hack to make CPU and GPU results comparable 48 | return false; 49 | } 50 | 51 | return (score > bestScore); 52 | } 53 | 54 | cuv::ndarray normalizeHistogram( 55 | const cuv::ndarray& histogram, 56 | const cuv::ndarray& priorDistribution, 57 | const double histogramBias, 58 | const bool useLabelsPrior) { 59 | 60 | const int numLabels = histogram.size(); 61 | 62 | cuv::ndarray normalizedHistogram(numLabels); 63 | 64 | std::vector labelWeights(numLabels); 65 | { 66 | double sum = 0; 67 | for (int i = 0; i < numLabels; i++) { 68 | sum += priorDistribution[i]; 69 | } 70 | for (int i = 0; i < numLabels; i++) { 71 | labelWeights[i] = priorDistribution[i] / sum; 72 | } 73 | } 74 | 75 | double sum = 0; 76 | for (int i = 0; i < numLabels; i++) { 77 | assert(sum < std::numeric_limits::max() - histogram[i]); 78 | sum += histogram[i]; 79 | } 80 | 81 | for (int i = 0; i < numLabels; i++) { 82 | normalizedHistogram[i] = histogram[i] - histogramBias * sum; 83 | if (normalizedHistogram[i] < 0.0) { 84 | normalizedHistogram[i] = 0.0; 85 | } 86 | } 87 | 88 | sum = 0; 89 | for (int i = 0; i < numLabels; i++) { 90 | assert(sum < std::numeric_limits::max() - histogram[i]); 91 | sum += normalizedHistogram[i]; 92 | } 93 | 94 | if (sum > 0) { 95 | for (int i = 0; i < numLabels; i++) { 96 | if (useLabelsPrior) 97 | normalizedHistogram[i] = normalizedHistogram[i] / sum * labelWeights[i]; 98 | else 99 | normalizedHistogram[i] = normalizedHistogram[i] / sum ; 100 | } 101 | } 102 | 103 | return normalizedHistogram; 104 | } 105 | } 106 | 107 | int Sampler::getNext() { 108 | int value = distribution(rng); 109 | assert(value >= lower); 110 | assert(value <= upper); 111 | return value; 112 | } 113 | 114 | AccelerationMode TrainingConfiguration::parseAccelerationModeString(const std::string& modeString) { 115 | if (modeString == "cpu") { 116 | return AccelerationMode::CPU_ONLY; 117 | } else if (modeString == "gpu") { 118 | return AccelerationMode::GPU_ONLY; 119 | } else if (modeString == "compare") { 120 | return AccelerationMode::GPU_AND_CPU_COMPARE; 121 | } else { 122 | throw std::runtime_error(std::string("illegal acceleration mode: ") + modeString); 123 | } 124 | } 125 | 126 | std::string TrainingConfiguration::getAccelerationModeString() const { 127 | switch (accelerationMode) { 128 | case GPU_ONLY: 129 | return "gpu"; 130 | case CPU_ONLY: 131 | return "cpu"; 132 | case GPU_AND_CPU_COMPARE: 133 | return "compare"; 134 | default: 135 | throw std::runtime_error(boost::str(boost::format("unknown acceleration mode: %d") % accelerationMode)); 136 | } 137 | } 138 | 139 | TrainingConfiguration::TrainingConfiguration(const TrainingConfiguration& other) { 140 | *this = other; 141 | } 142 | 143 | TrainingConfiguration& TrainingConfiguration::operator=(const TrainingConfiguration& other) { 144 | randomSeed = other.randomSeed; 145 | samplesPerImage = other.samplesPerImage; 146 | featureCount = other.featureCount; 147 | minSampleCount = other.minSampleCount; 148 | maxDepth = other.maxDepth; 149 | boxRadius = other.boxRadius; 150 | regionSize = other.regionSize; 151 | thresholds = other.thresholds; 152 | numThreads = other.numThreads; 153 | maxImages = other.maxImages; 154 | imageCacheSize = other.imageCacheSize; 155 | maxSamplesPerBatch = other.maxSamplesPerBatch; 156 | accelerationMode = other.accelerationMode; 157 | useCIELab = other.useCIELab; 158 | useDepthFilling = other.useDepthFilling; 159 | deviceIds = other.deviceIds; 160 | subsamplingType = other.subsamplingType; 161 | ignoredColors = other.ignoredColors; 162 | useDepthImages = other.useDepthImages; 163 | horizontalFlipping = other.horizontalFlipping; 164 | assert(*this == other); 165 | return *this; 166 | } 167 | 168 | bool TrainingConfiguration::equals(const TrainingConfiguration& other, 169 | bool strict) const { 170 | 171 | if (strict && randomSeed != other.randomSeed) 172 | return false; 173 | if (strict && deviceIds != other.deviceIds) 174 | return false; 175 | if (strict && imageCacheSize != other.imageCacheSize) 176 | return false; 177 | if (strict && maxSamplesPerBatch != other.maxSamplesPerBatch) 178 | return false; 179 | 180 | if (samplesPerImage != other.samplesPerImage) 181 | return false; 182 | if (featureCount != other.featureCount) 183 | return false; 184 | if (minSampleCount != other.minSampleCount) 185 | return false; 186 | if (maxDepth != other.maxDepth) 187 | return false; 188 | if (boxRadius != other.boxRadius) 189 | return false; 190 | if (regionSize != other.regionSize) 191 | return false; 192 | if (thresholds != other.thresholds) 193 | return false; 194 | if (numThreads != other.numThreads) 195 | return false; 196 | if (maxImages != other.maxImages) 197 | return false; 198 | if (accelerationMode != other.accelerationMode) 199 | return false; 200 | if (subsamplingType != other.subsamplingType) 201 | return false; 202 | if (ignoredColors != other.ignoredColors) 203 | return false; 204 | if (useCIELab != other.useCIELab) 205 | return false; 206 | if (useDepthFilling != other.useDepthFilling) 207 | return false; 208 | if (useDepthImages != other.useDepthImages) 209 | return false; 210 | if (horizontalFlipping != other.horizontalFlipping) 211 | return false; 212 | 213 | return true; 214 | } 215 | 216 | } 217 | 218 | template 219 | static std::string joinToString(const std::vector& input, const std::string separator = ", ", 220 | const std::string prefix = "[", const std::string postfix = "]") { 221 | std::vector strings; 222 | for (const auto& v : input) { 223 | strings.push_back(boost::lexical_cast(v)); 224 | } 225 | return prefix + boost::algorithm::join(strings, separator) + postfix; 226 | } 227 | 228 | std::ostream& operator<<(std::ostream& os, const curfil::TrainingConfiguration& configuration) { 229 | os << "randomSeed: " << configuration.getRandomSeed() << std::endl; 230 | os << "samplesPerImage: " << configuration.getSamplesPerImage() << std::endl; 231 | os << "featureCount: " << configuration.getFeatureCount() << std::endl; 232 | os << "minSampleCount: " << configuration.getMinSampleCount() << std::endl; 233 | os << "maxDepth: " << configuration.getMaxDepth() << std::endl; 234 | os << "boxRadius: " << configuration.getBoxRadius() << std::endl; 235 | os << "regionSize: " << configuration.getRegionSize() << std::endl; 236 | os << "thresholds: " << configuration.getThresholds() << std::endl; 237 | os << "maxImages: " << configuration.getMaxImages() << std::endl; 238 | os << "imageCacheSize: " << configuration.getImageCacheSize() << std::endl; 239 | os << "accelerationMode: " << configuration.getAccelerationModeString() << std::endl; 240 | os << "maxSamplesPerBatch: " << configuration.getMaxSamplesPerBatch() << std::endl; 241 | os << "subsamplingType: " << configuration.getSubsamplingType() << std::endl; 242 | os << "useCIELab: " << configuration.isUseCIELab() << std::endl; 243 | os << "useDepthFilling: " << configuration.isUseDepthFilling() << std::endl; 244 | os << "deviceIds: " << joinToString(configuration.getDeviceIds()) << std::endl; 245 | os << "ignoredColors: " << joinToString(configuration.getIgnoredColors()) << std::endl; 246 | os << "useDepthImages: " << configuration.isUseDepthImages() << std::endl; 247 | os << "horizontalFlipping: " << configuration.doHorizontalFlipping() << std::endl; 248 | return os; 249 | } 250 | -------------------------------------------------------------------------------- /src/curfil/score.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_SCORE_H 29 | #define CURFIL_SCORE_H 30 | 31 | #include 32 | #include 33 | 34 | #include "utils.h" 35 | 36 | namespace curfil 37 | { 38 | 39 | typedef double ScoreType; 40 | 41 | /** 42 | * Information Gain calculation using Shannon entropy of the parent and child nodes 43 | * @ingroup score_calc 44 | */ 45 | class InformationGainScore { 46 | 47 | protected: 48 | 49 | /** 50 | * @return entropy calculated using the given probability 51 | */ 52 | __host__ __device__ 53 | static ScoreType entropy(const ScoreType prob) { 54 | if (prob == 0.0) { 55 | return 0.0; 56 | } 57 | return -prob * log2(prob); 58 | } 59 | 60 | /** 61 | * @return score in the interval [0,1] 62 | */ 63 | __host__ __device__ 64 | static ScoreType normalizeScore(const ScoreType score) { 65 | 66 | assert(!isnan(score)); 67 | 68 | if (score > 1.0) { 69 | assert(fabs(score - 1) < 1e-6); 70 | return 1; 71 | } 72 | 73 | if (score < 0.0) { 74 | assert(fabs(score - 0) < 1e-6); 75 | return 0; 76 | } 77 | 78 | assertProbability(score); 79 | return score; 80 | } 81 | 82 | public: 83 | 84 | /** 85 | * @return normalized score calculated after splitting 86 | */ 87 | template 88 | __host__ __device__ 89 | static ScoreType calculateScore(const size_t numLabels, const W* leftClasses, const W* rightClasses, 90 | const unsigned int leftRightStride, const W* allClasses, const ScoreType totalLeft, 91 | const ScoreType totalRight) { 92 | 93 | const ScoreType total = totalLeft + totalRight; 94 | 95 | const ScoreType leftProb = totalLeft / total; 96 | const ScoreType rightProb = totalRight / total; 97 | 98 | #ifndef NDEBUG 99 | W totalLeftTest = 0; 100 | W totalRightTest = 0; 101 | #endif 102 | 103 | ScoreType score = 0; 104 | 105 | for (size_t label = 0; label < numLabels; label++) { 106 | const size_t offset = label * leftRightStride; 107 | const W& leftValue = leftClasses[offset]; 108 | const W& rightValue = rightClasses[offset]; 109 | 110 | #ifndef NDEBUG 111 | assert(leftValue <= allClasses[label]); 112 | assert(rightValue <= allClasses[label]); 113 | assert(leftValue <= total); 114 | assert(rightValue <= total); 115 | totalLeftTest += leftValue; 116 | totalRightTest += rightValue; 117 | #endif 118 | 119 | const ScoreType classProb = allClasses[label] / total; 120 | assertProbability(classProb); 121 | 122 | if (leftValue > 0) { 123 | ScoreType classProbLeft = leftValue / total; 124 | assertProbability(classProbLeft); 125 | score += classProbLeft * log2(classProbLeft / (leftProb * classProb)); 126 | } 127 | 128 | if (rightValue > 0) { 129 | ScoreType classProbRight = rightValue / total; 130 | assertProbability(classProbRight); 131 | score += classProbRight * log2(classProbRight / (rightProb * classProb)); 132 | } 133 | } 134 | 135 | assert(totalLeftTest == totalLeft); 136 | assert(totalRightTest == totalRight); 137 | 138 | return normalizeScore(score); 139 | } 140 | }; 141 | 142 | /** 143 | * Information gain normalized by the sum of the classification and split entropies 144 | * see formula (11) in [Wehenkel1991] and appendix A in [Geurts2006] 145 | * @ingroup score_calc 146 | */ 147 | class NormalizedInformationGainScore: public InformationGainScore { 148 | protected: 149 | 150 | /** 151 | * @return H_s: "split entropy", i.e. a measure of the split balancedness 152 | */ 153 | __host__ __device__ 154 | static ScoreType splitEntropy(const ScoreType total, const ScoreType totalLeft, const ScoreType totalRight) { 155 | ScoreType H_s = (entropy(totalLeft) + entropy(totalRight) - entropy(total)) / total; 156 | 157 | assert(!isnan(H_s)); 158 | assert(H_s >= 0); 159 | 160 | return H_s; 161 | } 162 | 163 | /** 164 | * @return classification entropy 165 | */ 166 | template 167 | __host__ __device__ 168 | static ScoreType classificationEntropy(const size_t numLabels, const W* allClasses, const ScoreType total) { 169 | 170 | ScoreType H_c = 0; 171 | 172 | for (size_t label = 0; label < numLabels; label++) { 173 | const W& value = allClasses[label]; 174 | assert(value <= total); 175 | if (value > 0) { 176 | H_c += entropy(value); 177 | } 178 | } 179 | 180 | H_c -= entropy(total); 181 | H_c /= total; 182 | 183 | assert(!isnan(H_c)); 184 | assert(H_c >= 0); 185 | 186 | return H_c; 187 | } 188 | 189 | public: 190 | 191 | template 192 | __host__ __device__ 193 | static ScoreType calculateScore(const size_t numClasses, const W* leftClasses, const W* rightClasses, 194 | const unsigned int leftRightStride, const W* allClasses, const ScoreType totalLeft, 195 | const ScoreType totalRight) { 196 | 197 | // Compute information gain due to split decision 198 | const ScoreType informationGain = InformationGainScore::calculateScore(numClasses, 199 | leftClasses, rightClasses, leftRightStride, 200 | allClasses, totalLeft, totalRight); 201 | 202 | if (informationGain == 0) { 203 | // skip calculation of split entropy 204 | return 0; 205 | } 206 | 207 | ScoreType total = totalLeft + totalRight; 208 | assert(total > 0); 209 | 210 | const ScoreType H_s = splitEntropy(total, totalLeft, totalRight); 211 | const ScoreType H_c = classificationEntropy(numClasses, allClasses, total); 212 | 213 | ScoreType score = (2 * informationGain) / (H_s + H_c); 214 | return normalizeScore(score); 215 | } 216 | }; 217 | 218 | /// @cond DEV 219 | class NoOpScore: public InformationGainScore { 220 | 221 | public: 222 | template 223 | __host__ __device__ 224 | static ScoreType calculateScore(const size_t numLabels, const W* leftClasses, const W* rightClasses, 225 | const unsigned int leftRightStride, const W* allClasses, const ScoreType totalLeft, 226 | const ScoreType totalRight) { 227 | 228 | const ScoreType total = totalLeft + totalRight; 229 | 230 | ScoreType score = 0; 231 | 232 | for (size_t label = 0; label < numLabels; label++) { 233 | const size_t offset = label * leftRightStride; 234 | const W& leftValue = leftClasses[offset]; 235 | const W& rightValue = rightClasses[offset]; 236 | 237 | score += leftValue; 238 | score += rightValue; 239 | score += allClasses[label]; 240 | } 241 | 242 | return score / (3.0 * total); 243 | } 244 | }; 245 | 246 | /// @endcond 247 | 248 | } 249 | 250 | #endif 251 | -------------------------------------------------------------------------------- /src/curfil/train.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include "train.h" 29 | 30 | #include 31 | #include 32 | 33 | #include "image.h" 34 | #include "random_forest_image.h" 35 | #include "random_tree_image.h" 36 | #include "utils.h" 37 | 38 | namespace curfil 39 | { 40 | 41 | void determineImageCacheSizeAndSamplesPerBatch(const std::vector& images, 42 | const std::vector& deviceIds, const size_t featureCount, const size_t numThresholds, 43 | size_t imageCacheSizeMB, unsigned int& imageCacheSize, unsigned int& maxSamplesPerBatch) { 44 | 45 | if (deviceIds.empty()) { 46 | throw std::runtime_error("got no device IDs"); 47 | } 48 | 49 | if (deviceIds.size() != 1) { 50 | throw std::runtime_error("only one device ID supported currently"); 51 | } 52 | 53 | size_t freeMemoryOnGPU = utils::getFreeMemoryOnGPU(deviceIds[0]); 54 | 55 | if (imageCacheSizeMB == 0) { 56 | imageCacheSizeMB = freeMemoryOnGPU * 0.66 / 1024 / 1024; 57 | } 58 | 59 | // very defensive estimate to avoid out of memory errors 60 | long remainingMemoryOnGPU = (freeMemoryOnGPU - imageCacheSizeMB * 1024lu * 1024lu) / 3; 61 | // size for histogram counters 62 | remainingMemoryOnGPU -= 10 * (2 * sizeof(WeightType) * featureCount * numThresholds); 63 | size_t sizePerSample = 2 * sizeof(FeatureResponseType) * featureCount; 64 | 65 | maxSamplesPerBatch = remainingMemoryOnGPU / sizePerSample; 66 | maxSamplesPerBatch = std::min(maxSamplesPerBatch, 50000u); 67 | 68 | if (maxSamplesPerBatch < 1000) { 69 | throw std::runtime_error("memory headroom on GPU too low. try to decrease image cache size manually"); 70 | } 71 | 72 | CURFIL_INFO("max samples per batch: " << maxSamplesPerBatch); 73 | 74 | if (images.size() * images[0].getSizeInMemory() <= imageCacheSizeMB * 1024lu * 1024lu) { 75 | imageCacheSize = images.size(); 76 | } else { 77 | imageCacheSize = imageCacheSizeMB * 1024lu * 1024lu / images[0].getSizeInMemory(); 78 | } 79 | 80 | CURFIL_INFO((boost::format("image cache size: %d images (%.1f MB)") 81 | % imageCacheSize 82 | % (imageCacheSize * images[0].getSizeInMemory() / 1024.0 / 1024.0)).str()); 83 | 84 | if (imageCacheSizeMB * 1024lu * 1024lu >= freeMemoryOnGPU) { 85 | throw std::runtime_error("image cache size too large"); 86 | } 87 | } 88 | 89 | RandomForestImage train(std::vector& images, size_t trees, 90 | const TrainingConfiguration& configuration, size_t numLabels, bool trainTreesInParallel) { 91 | 92 | CURFIL_INFO("trees: " << trees); 93 | CURFIL_INFO("training trees in parallel: " << trainTreesInParallel); 94 | CURFIL_INFO(configuration); 95 | 96 | // Train 97 | 98 | RandomForestImage randomForest(trees, configuration); 99 | 100 | utils::Timer trainTimer; 101 | randomForest.train(images, numLabels, !trainTreesInParallel); 102 | trainTimer.stop(); 103 | 104 | CURFIL_INFO("training took " << trainTimer.format(2) << 105 | " (" << std::setprecision(3) << trainTimer.getSeconds() / 60.0 << " min)"); 106 | 107 | /* // This feature is only experimental, it should be rewritten in a much faster way, and a CPU version should be added 108 | bool onGPU = randomForest.getConfiguration().getAccelerationMode() == GPU_ONLY; 109 | bool useDepthImages = randomForest.getConfiguration().isUseDepthImages(); 110 | 111 | size_t grainSize = 1; 112 | if (!onGPU) { 113 | grainSize = images.size(); 114 | } 115 | 116 | //should get the correct histogram bias 117 | randomForest.normalizeHistograms(0.0); 118 | 119 | tbb::parallel_for(tbb::blocked_range(0, images.size(), grainSize), 120 | [&](const tbb::blocked_range& range) { 121 | for(size_t imageNr = range.begin(); imageNr != range.end(); imageNr++) { 122 | const LabeledRGBDImage imagePair = images[imageNr]; 123 | const RGBDImage& trainingImage = imagePair.getRGBDImage(); 124 | const LabelImage& groundTruth = imagePair.getLabelImage(); 125 | LabelImage prediction(trainingImage.getWidth(), trainingImage.getHeight()); 126 | prediction = randomForest.improveHistograms(trainingImage, groundTruth, true, useDepthImages); 127 | } 128 | }); 129 | randomForest.updateTreesHistograms(); 130 | */ 131 | std::cout << randomForest; 132 | for (const auto& featureCount : randomForest.countFeatures()) { 133 | const std::string featureType = featureCount.first; 134 | CURFIL_INFO("feature " << featureType << ": " << featureCount.second); 135 | } 136 | 137 | return randomForest; 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/curfil/train.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_TRAIN_H 29 | #define CURFIL_TRAIN_H 30 | 31 | #include "random_forest_image.h" 32 | 33 | namespace curfil 34 | { 35 | 36 | /** 37 | * Helper function to automatically determine the best configuration for the image cache and the number of samples (pixels) per batch, depending on the available GPU. 38 | */ 39 | void determineImageCacheSizeAndSamplesPerBatch(const std::vector& images, 40 | const std::vector& deviceId, const size_t featureCount, const size_t numThresholds, 41 | size_t imageCacheSizeMB, unsigned int& imageCacheSize, unsigned int& maxSamplesPerBatch); 42 | 43 | /** 44 | * Train a random forest with the given training images and configuration. 45 | * 46 | * @param images list of training images 47 | * @param trees number of trees to train 48 | * @param configuration the training configuration 49 | * @param trainTreeInParallel whether to train each tree in sequential order or in parallel. 50 | */ 51 | RandomForestImage train(std::vector& images, size_t trees, 52 | const TrainingConfiguration& configuration, size_t numLabels, bool trainTreesInParallel); 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/curfil/train_main.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include 29 | #include 30 | 31 | #include "export.h" 32 | #include "train.h" 33 | #include "utils.h" 34 | #include "version.h" 35 | 36 | namespace po = boost::program_options; 37 | 38 | using namespace curfil; 39 | 40 | int main(int argc, char **argv) { 41 | 42 | std::string folderTraining; 43 | std::string outputFolder; 44 | int trees; 45 | unsigned int samplesPerImage; 46 | unsigned int featureCount; 47 | unsigned int minSampleCount; 48 | int maxDepth; 49 | uint16_t boxRadius; 50 | uint16_t regionSize; 51 | uint16_t numThresholds; 52 | std::string modeString; 53 | int numThreads; 54 | std::string subsamplingType; 55 | bool profiling; 56 | bool useCIELab = true; 57 | bool useDepthFilling = false; 58 | int deviceId = 0; 59 | int maxImages = 0; 60 | int randomSeed = 4711; 61 | std::vector ignoredColors; 62 | bool trainTreesInParallel = false; // parallel tree training on GPU is considered to be an experimental feature 63 | bool verboseTree = false; 64 | int imageCacheSizeMB = 0; 65 | bool useDepthImages = true; 66 | bool horizontalFlipping = false; 67 | 68 | // Declare the supported options. 69 | po::options_description options("options"); 70 | options.add_options() 71 | ("help", "produce help message") 72 | ("version", "show version and exit") 73 | ("folderTraining", po::value(&folderTraining)->required(), "folder with training images") 74 | ("trees", po::value(&trees)->required(), "number of trees to train") 75 | ("samplesPerImage", po::value(&samplesPerImage)->required(), "samples per image") 76 | ("featureCount", po::value(&featureCount)->required(), "feature count") 77 | ("minSampleCount", po::value(&minSampleCount)->required(), "min samples count") 78 | ("maxDepth", po::value(&maxDepth)->required(), "maximum tree depth") 79 | ("boxRadius", po::value(&boxRadius)->required(), "box radius") 80 | ("regionSize", po::value(®ionSize)->required(), "region size") 81 | ("numThresholds", po::value(&numThresholds)->required(), "number of thresholds to evaluate") 82 | ("outputFolder", po::value(&outputFolder)->default_value(outputFolder), 83 | "folder to output predictions and trees") 84 | ("numThreads", po::value(&numThreads)->default_value(tbb::task_scheduler_init::default_num_threads()), 85 | "number of threads") 86 | ("useCIELab", po::value(&useCIELab)->implicit_value(true)->default_value(useCIELab), 87 | "convert images to CIElab color space") 88 | ("useDepthFilling", po::value(&useDepthFilling)->implicit_value(true)->default_value(useDepthFilling), 89 | "whether to do simple depth filling") 90 | ("deviceId", po::value(&deviceId)->default_value(deviceId), "GPU device id") 91 | ("subsamplingType", po::value(&subsamplingType)->default_value("classUniform"), 92 | "subsampling type: 'pixelUniform' or 'classUniform'") 93 | ("maxImages", po::value(&maxImages)->default_value(maxImages), 94 | "maximum number of images to load for training. set to 0 if all images should be loaded") 95 | ("imageCacheSize", po::value(&imageCacheSizeMB)->default_value(imageCacheSizeMB), 96 | "image cache size on GPU in MB. 0 means automatic adjustment") 97 | ("mode", po::value(&modeString)->default_value("gpu"), "mode: 'gpu' (default), 'cpu' or 'compare'") 98 | ("profile", po::value(&profiling)->implicit_value(true)->default_value(false), "profiling") 99 | ("randomSeed", po::value(&randomSeed)->default_value(randomSeed), "random seed") 100 | ("ignoreColor", po::value >(&ignoredColors), 101 | "do not sample pixels of this color. format: R,G,B where 0 <= R,G,B <= 255") 102 | ("verboseTree", po::value(&verboseTree)->implicit_value(true)->default_value(verboseTree), 103 | "whether to write verbose tree include profiling and debugging information") 104 | ("trainTreesInParallel", 105 | po::value(&trainTreesInParallel)->implicit_value(true)->default_value(trainTreesInParallel), 106 | "whether to train multiple trees sequentially (default) or in parallel (experimental)") 107 | ("useDepthImages", po::value(&useDepthImages)->implicit_value(true)->default_value(useDepthImages), 108 | "whether to use depth images") 109 | ("horizontalFlipping", po::value(&horizontalFlipping)->implicit_value(false)->default_value(horizontalFlipping), 110 | "whether to horizontally flip features"); 111 | ; 112 | 113 | po::positional_options_description pod; 114 | pod.add("folderTraining", 1); 115 | pod.add("trees", 1); 116 | pod.add("samplesPerImage", 1); 117 | pod.add("featureCount", 1); 118 | pod.add("minSampleCount", 1); 119 | pod.add("maxDepth", 1); 120 | pod.add("boxRadius", 1); 121 | pod.add("regionSize", 1); 122 | pod.add("numThresholds", 1); 123 | pod.add("outputFolder", 1); 124 | 125 | po::variables_map vm; 126 | po::store(po::command_line_parser(argc, argv).positional(pod).options(options).run(), vm); 127 | 128 | if (argc <= 1 || vm.count("help")) { 129 | std::cout << options << std::endl; 130 | return EXIT_FAILURE; 131 | } 132 | 133 | if (argc <= 1 || vm.count("version")) { 134 | std::cout << argv[0] << " version " << getVersion() << std::endl; 135 | return EXIT_FAILURE; 136 | } 137 | 138 | try { 139 | po::notify(vm); 140 | } catch (const std::exception& e) { 141 | std::cerr << e.what() << std::endl; 142 | return EXIT_FAILURE; 143 | } 144 | 145 | logVersionInfo(); 146 | 147 | CURFIL_INFO("acceleration mode: " << modeString); 148 | CURFIL_INFO("CIELab: " << useCIELab); 149 | CURFIL_INFO("DepthFilling: " << useDepthFilling); 150 | 151 | utils::Profile::setEnabled(profiling); 152 | 153 | tbb::task_scheduler_init init(numThreads); 154 | 155 | size_t numLabels; //added because otherwise when hyperopt randomly splits the training images, the number of classes is wrong 156 | 157 | std::vector images = loadImages(folderTraining, useCIELab, useDepthImages, useDepthFilling, ignoredColors, numLabels); 158 | if (images.empty()) { 159 | throw std::runtime_error(std::string("found no files in ") + folderTraining); 160 | } 161 | 162 | // currently training on only on GPU is tested 163 | std::vector deviceIds(1, deviceId); 164 | 165 | unsigned int imageCacheSize = 0; 166 | unsigned int maxSamplesPerBatch = 0; 167 | 168 | determineImageCacheSizeAndSamplesPerBatch(images, deviceIds, featureCount, numThresholds, imageCacheSizeMB, 169 | imageCacheSize, maxSamplesPerBatch); 170 | 171 | TrainingConfiguration configuration(randomSeed, samplesPerImage, featureCount, minSampleCount, 172 | maxDepth, boxRadius, regionSize, numThresholds, numThreads, maxImages, imageCacheSize, maxSamplesPerBatch, 173 | TrainingConfiguration::parseAccelerationModeString(modeString), useCIELab, useDepthFilling, deviceIds, 174 | subsamplingType, ignoredColors, useDepthImages, horizontalFlipping); 175 | 176 | RandomForestImage forest = train(images, trees, configuration, numLabels, trainTreesInParallel); 177 | 178 | if (!outputFolder.empty()) { 179 | RandomTreeExport treeExport(configuration, outputFolder, folderTraining, verboseTree); 180 | treeExport.writeJSON(forest); 181 | } else { 182 | CURFIL_WARNING("no output folder given. skipping JSON export"); 183 | } 184 | 185 | CURFIL_INFO("finished"); 186 | return EXIT_SUCCESS; 187 | } 188 | -------------------------------------------------------------------------------- /src/curfil/utils.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #include "utils.h" 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "version.h" 35 | 36 | namespace curfil { 37 | 38 | void logVersionInfo() { 39 | #ifdef NDEBUG 40 | CURFIL_INFO("release version " << getVersion()); 41 | #else 42 | CURFIL_WARNING("this is the debugging version " << getVersion()); 43 | #endif 44 | } 45 | 46 | namespace utils { 47 | 48 | bool Profile::enabled = false; 49 | 50 | void Timer::reset() { 51 | stop(); 52 | start(); 53 | } 54 | 55 | void Timer::start() { 56 | started = boost::posix_time::microsec_clock::local_time(); 57 | isStopped = false; 58 | } 59 | void Timer::stop() { 60 | stopped = boost::posix_time::microsec_clock::local_time(); 61 | isStopped = true; 62 | } 63 | 64 | std::string Timer::format(int precision) { 65 | std::ostringstream o; 66 | o.precision(precision); 67 | if (getSeconds() <= 1.0) { 68 | o << std::fixed << getMilliseconds() << " ms"; 69 | } else { 70 | o << std::fixed << getSeconds() << " s"; 71 | } 72 | return o.str(); 73 | } 74 | 75 | double Timer::getSeconds() { 76 | if (!isStopped) 77 | stop(); 78 | boost::posix_time::time_duration duration = (stopped - started); 79 | return duration.total_microseconds() / static_cast(1e6); 80 | } 81 | 82 | double Timer::getMilliseconds() { 83 | if (!isStopped) 84 | stop(); 85 | boost::posix_time::time_duration duration = (stopped - started); 86 | return duration.total_microseconds() / static_cast(1e3); 87 | } 88 | 89 | void logMessage(const std::string& msg, std::ostream& os) { 90 | boost::posix_time::ptime date_time = boost::posix_time::microsec_clock::local_time(); 91 | 92 | std::string out = boost::str(boost::format("%s %s") % date_time % msg); 93 | std::ostringstream endlStream; 94 | endlStream << std::endl; 95 | std::string endl = endlStream.str(); 96 | 97 | // append newline if it’s not already there 98 | if (!boost::ends_with(out, endl)) { 99 | out += endl; 100 | } 101 | os << out << std::flush; 102 | } 103 | 104 | void checkCudaError(const char* msg) { 105 | cudaError_t lastError = cudaGetLastError(); 106 | if (lastError == cudaSuccess) 107 | return; 108 | 109 | throw std::runtime_error(std::string(msg) + ": " + cudaGetErrorString(lastError)); 110 | } 111 | 112 | size_t getFreeMemoryOnGPU(int deviceId) { 113 | size_t freeMemory = 0; 114 | size_t totalMemory = 0; 115 | cudaSafeCall(cudaSetDevice(deviceId)); 116 | cudaSafeCall(cudaMemGetInfo(&freeMemory, &totalMemory)); 117 | return freeMemory; 118 | } 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/curfil/utils.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_UTILS_H 29 | #define CURFIL_UTILS_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef __CUDACC__ 37 | // results in a warning, though thrust seems to have gone that route in 38 | // https://github.com/jaredhoberock/thrust/commit/e13dbc444566ea8589d1c02e6df1c5a5533efb79 39 | // using ::isnan; 40 | #else 41 | using std::isnan; 42 | #endif 43 | 44 | namespace curfil { 45 | 46 | void logVersionInfo(); 47 | 48 | #define cudaSafeCall(X) X; curfil::utils::checkCudaError(#X); 49 | 50 | // for debugging purposes 51 | template 52 | static inline void assert_equals(const T a, const T b) { 53 | if (a != b) { 54 | assert(a == b); 55 | } 56 | } 57 | 58 | #ifndef NDEBUG 59 | #define assertProbability(probability) { \ 60 | if (probability < 0.0 || probability > 1.0) { \ 61 | printf("illegal probability: %lf\n", static_cast(probability)); \ 62 | } \ 63 | assert(probability >= 0.0); \ 64 | assert(probability <= 1.0); \ 65 | } 66 | #else 67 | #define assertProbability(probability) {} 68 | #endif 69 | 70 | namespace utils { 71 | 72 | void checkCudaError(const char* msg); 73 | 74 | /** 75 | * Used to get seconds or milliseconds passed for profiling purposes 76 | */ 77 | class Timer { 78 | public: 79 | Timer() : 80 | isStopped(false) { 81 | start(); 82 | } 83 | 84 | void reset(); /**< stop then start the timer */ 85 | void start(); /**< start the timer */ 86 | void stop(); /**< stop the timer */ 87 | 88 | std::string format(int precision); /**< @return duration in seconds or milliseconds using the precision passed */ 89 | 90 | double getSeconds(); /**< @return duration in seconds */ 91 | double getMilliseconds(); /**< @return duration in milliseconds */ 92 | 93 | private: 94 | bool isStopped; 95 | boost::posix_time::ptime started; 96 | boost::posix_time::ptime stopped; 97 | 98 | }; 99 | 100 | /** 101 | * A simple class used for averaging 102 | */ 103 | class Average { 104 | public: 105 | Average() : 106 | sum(0), count(0) { 107 | } 108 | 109 | /** 110 | * add the value passed to the running sum and increments the counter 111 | */ 112 | void addValue(const double& value) { 113 | sum += value; 114 | count++; 115 | } 116 | 117 | /** 118 | * @return the average of the values that were previously added 119 | */ 120 | double getAverage() const { 121 | if (count == 0) 122 | return 0; 123 | return sum / count; 124 | } 125 | 126 | private: 127 | double sum; 128 | size_t count; 129 | }; 130 | 131 | void logMessage(const std::string& message, std::ostream& os); 132 | 133 | #define CURFIL_LOG(level, message, os) { \ 134 | std::ostringstream o; \ 135 | o << boost::format("%-8s") % level; \ 136 | o << message; \ 137 | curfil::utils::logMessage(o.str(), os); \ 138 | } 139 | 140 | #define CURFIL_INFO(x) CURFIL_LOG("INFO", x, std::cout) 141 | 142 | #define CURFIL_WARNING(x) CURFIL_LOG("WARNING", x, std::cout) 143 | 144 | #define CURFIL_ERROR(x) CURFIL_LOG("ERROR", x, std::cout) 145 | 146 | #ifdef CURFIL_DEBUG 147 | #undef CURFIL_DEBUG 148 | #endif 149 | 150 | #ifdef NDEBUG 151 | #define CURFIL_DEBUG(x) {} 152 | #else 153 | #define CURFIL_DEBUG(x) CURFIL_LOG("DEBUG", x, std::cout) 154 | #endif 155 | 156 | /** 157 | * Used to profile different stages of training and prediction 158 | */ 159 | class Profile { 160 | public: 161 | /** 162 | * @param name profile name 163 | */ 164 | Profile(const std::string& name) : 165 | name(name), timer() { 166 | } 167 | 168 | ~Profile() { 169 | if (isEnabled()) { 170 | timer.stop(); 171 | CURFIL_INFO("PROFILING('" << name << "'): " << timer.format(3)); 172 | } 173 | } 174 | 175 | /** 176 | * @return the timer duration in seconds 177 | */ 178 | double getSeconds() { 179 | return timer.getSeconds(); 180 | } 181 | 182 | /** 183 | * @return whether the profile is enabled 184 | */ 185 | static bool isEnabled() { 186 | return enabled; 187 | } 188 | 189 | /** 190 | * enabling the profile 191 | */ 192 | static void setEnabled(bool enable) { 193 | enabled = enable; 194 | CURFIL_INFO("profiling " << ((enabled) ? "enabled" : "disabled")); 195 | } 196 | 197 | private: 198 | 199 | static bool enabled; 200 | 201 | std::string name; 202 | Timer timer; 203 | }; 204 | 205 | size_t getFreeMemoryOnGPU(int deviceId); 206 | 207 | } 208 | } 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /src/curfil/version.cpp.in: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #define GIT_SHA1 "@GIT_SHA1@" 29 | 30 | #include 31 | 32 | namespace curfil { 33 | 34 | const std::string getVersion() { 35 | return GIT_SHA1; 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/curfil/version.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_VERSION_H 29 | #define CURFIL_VERSION_H 30 | 31 | #include 32 | 33 | namespace curfil { 34 | 35 | const std::string getVersion(); 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/testdata/testing1_colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/testing1_colors.png -------------------------------------------------------------------------------- /src/testdata/testing1_depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/testing1_depth.png -------------------------------------------------------------------------------- /src/testdata/testing1_ground_truth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/testing1_ground_truth.png -------------------------------------------------------------------------------- /src/testdata/training1_colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training1_colors.png -------------------------------------------------------------------------------- /src/testdata/training1_depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training1_depth.png -------------------------------------------------------------------------------- /src/testdata/training1_ground_truth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training1_ground_truth.png -------------------------------------------------------------------------------- /src/testdata/training2_colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training2_colors.png -------------------------------------------------------------------------------- /src/testdata/training2_depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training2_depth.png -------------------------------------------------------------------------------- /src/testdata/training2_ground_truth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training2_ground_truth.png -------------------------------------------------------------------------------- /src/testdata/training3_colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training3_colors.png -------------------------------------------------------------------------------- /src/testdata/training3_depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training3_depth.png -------------------------------------------------------------------------------- /src/testdata/training3_ground_truth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deeplearningais/curfil/65172142db4b2fd469028d5083da97454d4332c1/src/testdata/training3_ground_truth.png -------------------------------------------------------------------------------- /src/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # The MIT License 3 | 4 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 5 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 6 | # Copyright (c) 2008-2009 Sebastian Nowozin 7 | 8 | # Permission is hereby granted, free of charge, to any person obtaining a copy 9 | # of this software and associated documentation files (the "Software"), to deal 10 | # in the Software without restriction, including without limitation the rights 11 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | # copies of the Software, and to permit persons to whom the Software is 13 | # furnished to do so, subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be included in all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | ####################################################################################### 26 | INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) 27 | INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/curfil) 28 | INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) 29 | 30 | SET (TEST_LINK_LIBS curfil) 31 | 32 | ADD_EXECUTABLE(image_test image_test.cpp) 33 | TARGET_LINK_LIBRARIES(image_test ${TEST_LINK_LIBS}) 34 | 35 | CUDA_ADD_EXECUTABLE(random_tree_test random_tree_test.cpp) 36 | TARGET_LINK_LIBRARIES(random_tree_test ${TEST_LINK_LIBS}) 37 | 38 | CUDA_ADD_EXECUTABLE(random_tree_image_gpu_test random_tree_image_gpu_test.cu) 39 | TARGET_LINK_LIBRARIES(random_tree_image_gpu_test ${TEST_LINK_LIBS}) 40 | 41 | CUDA_ADD_EXECUTABLE(image_cache_test image_cache_test.cu) 42 | TARGET_LINK_LIBRARIES(image_cache_test ${TEST_LINK_LIBS}) 43 | 44 | ADD_EXECUTABLE(feature_generation_test feature_generation_test.cpp) 45 | TARGET_LINK_LIBRARIES(feature_generation_test ${TEST_LINK_LIBS}) 46 | 47 | ADD_EXECUTABLE(import_export_test import_export_test.cpp) 48 | TARGET_LINK_LIBRARIES(import_export_test ${TEST_LINK_LIBS}) 49 | 50 | ADD_EXECUTABLE(random_tree_image_test random_tree_image_test.cpp) 51 | TARGET_LINK_LIBRARIES(random_tree_image_test ${TEST_LINK_LIBS}) 52 | 53 | ADD_TEST(image_test "${CMAKE_BINARY_DIR}/src/tests/image_test") 54 | ADD_TEST(feature_generation_test "${CMAKE_BINARY_DIR}/src/tests/feature_generation_test") 55 | ADD_TEST(random_tree_test "${CMAKE_BINARY_DIR}/src/tests/random_tree_test") 56 | ADD_TEST(random_tree_image_gpu_test "${CMAKE_BINARY_DIR}/src/tests/random_tree_image_gpu_test") 57 | ADD_TEST(image_cache_test "${CMAKE_BINARY_DIR}/src/tests/image_cache_test") 58 | 59 | ADD_TEST(NAME import_export_test 60 | COMMAND "${CMAKE_BINARY_DIR}/src/tests/import_export_test" "${CMAKE_SOURCE_DIR}/src/testdata") 61 | 62 | ADD_TEST(NAME random_tree_image_test 63 | COMMAND "${CMAKE_BINARY_DIR}/src/tests/random_tree_image_test" "${CMAKE_SOURCE_DIR}/src/testdata") 64 | 65 | IF(MDBQ_FOUND) 66 | ADD_EXECUTABLE(hyperopt_test hyperopt_test.cpp) 67 | TARGET_LINK_LIBRARIES(hyperopt_test ${TEST_LINK_LIBS}) 68 | 69 | ADD_TEST(hyperopt_test "${CMAKE_BINARY_DIR}/src/tests/hyperopt_test") 70 | ENDIF() 71 | -------------------------------------------------------------------------------- /src/tests/hyperopt_test.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #define BOOST_TEST_MODULE example 29 | 30 | #include 31 | #include 32 | 33 | #include "hyperopt.h" 34 | #include "test_common.h" 35 | #include "utils.h" 36 | 37 | using namespace curfil; 38 | 39 | BOOST_AUTO_TEST_SUITE(HyperoptTest) 40 | 41 | BOOST_AUTO_TEST_CASE(testContinueSearching) { 42 | 43 | std::vector currentBest; 44 | currentBest.push_back(1.0 - 0.681); 45 | currentBest.push_back(1.0 - 0.686); 46 | currentBest.push_back(1.0 - 0.683); 47 | currentBest.push_back(1.0 - 0.679); 48 | 49 | std::vector currentRun; 50 | currentRun.push_back(1.0 - 0.6293); 51 | currentRun.push_back(1.0 - 0.6212); 52 | currentRun.push_back(1.0 - 0.6210); 53 | 54 | // no need to continue searching 55 | BOOST_CHECK(!continueSearching(currentBest, currentRun)); 56 | BOOST_CHECK(continueSearching(currentRun, currentBest)); 57 | 58 | currentRun.clear(); 59 | currentRun.push_back(1.0 - 0.20); 60 | currentRun.push_back(1.0 - 0.60); 61 | currentRun.push_back(1.0 - 0.65); 62 | 63 | // we do not know anything (high variance). continue searching 64 | BOOST_CHECK(continueSearching(currentBest, currentRun)); 65 | 66 | for (int i = 0; i < 20; i++) { 67 | currentRun.push_back(1.0 - 0.55); 68 | } 69 | // okay. stop 70 | BOOST_CHECK(!continueSearching(currentBest, currentRun)); 71 | 72 | currentRun.clear(); 73 | currentRun.push_back(1.0 - 0.20); 74 | currentRun.push_back(1.0 - 0.21); 75 | currentRun.push_back(1.0 - 0.215); 76 | currentRun.push_back(1.0 - 0.912); 77 | 78 | // we are pretty bad. but there is one outlier which is very good. continue searching 79 | BOOST_CHECK(continueSearching(currentBest, currentRun)); 80 | 81 | currentRun.clear(); 82 | currentRun.push_back(1.0 - 0.20); 83 | currentRun.push_back(1.0 - 0.21); 84 | 85 | // too few samples. continue searching 86 | BOOST_CHECK(continueSearching(currentBest, currentRun)); 87 | 88 | currentRun.clear(); 89 | currentRun.push_back(1.0 - 0.659); 90 | currentRun.push_back(1.0 - 0.674); 91 | currentRun.push_back(1.0 - 0.672); 92 | 93 | // not better so far. but who knows if we get better. continue searching. 94 | BOOST_CHECK(continueSearching(currentBest, currentRun)); 95 | 96 | currentRun.push_back(1.0 - 0.678); 97 | 98 | BOOST_CHECK(continueSearching(currentBest, currentRun)); 99 | 100 | currentRun.push_back(1.0 - 0.671); 101 | 102 | BOOST_CHECK(continueSearching(currentBest, currentRun)); 103 | 104 | currentRun.push_back(1.0 - 0.673); 105 | 106 | BOOST_CHECK(!continueSearching(currentBest, currentRun)); 107 | } 108 | 109 | BOOST_AUTO_TEST_CASE(testResultToBSON) { 110 | ConfusionMatrix confusionMatrix(3); 111 | confusionMatrix(0, 0) = 1.0; 112 | confusionMatrix(0, 1) = 0.0; 113 | confusionMatrix(0, 2) = 0.0; 114 | confusionMatrix(1, 0) = 0.0; 115 | confusionMatrix(1, 1) = 0.5; 116 | confusionMatrix(1, 2) = 0.5; 117 | confusionMatrix(2, 0) = 0.0; 118 | confusionMatrix(2, 1) = 0.25; 119 | confusionMatrix(2, 2) = 0.75; 120 | 121 | double pixelAccuracy = 0.95; 122 | double pixelAccuracyWithoutVoid = 0.85; 123 | 124 | Result result(confusionMatrix, pixelAccuracy, pixelAccuracyWithoutVoid, LossFunctionType::CLASS_ACCURACY); 125 | result.setRandomSeed(4711); 126 | 127 | const mongo::BSONObj obj = result.toBSON(); 128 | CURFIL_INFO(obj.jsonString(mongo::JsonStringFormat::Strict, 1)); 129 | 130 | BOOST_REQUIRE_EQUAL(obj.getIntField("randomSeed"), 4711); 131 | BOOST_REQUIRE_EQUAL(obj.getField("loss").Double(), 0.25); 132 | BOOST_REQUIRE_EQUAL(obj.getField("classAccuracy").Double(), 0.75); 133 | BOOST_REQUIRE_EQUAL(obj.getField("pixelAccuracy").Double(), pixelAccuracy); 134 | BOOST_REQUIRE_EQUAL(obj.getField("pixelAccuracyWithoutVoid").Double(), pixelAccuracyWithoutVoid); 135 | BOOST_REQUIRE_EQUAL(obj.getField("confusionMatrix").toString(false), 136 | "[ [ 1.0, 0.0, 0.0 ], [ 0.0, 0.5, 0.5 ], [ 0.0, 0.25, 0.75 ] ]"); 137 | } 138 | 139 | BOOST_AUTO_TEST_CASE(testResultGetLoss) { 140 | 141 | std::vector ignoredLabels; 142 | ignoredLabels.push_back(0); 143 | 144 | ConfusionMatrix confusionMatrix(3, ignoredLabels); 145 | confusionMatrix(0, 0) = 1.0; 146 | confusionMatrix(0, 1) = 0.0; 147 | confusionMatrix(0, 2) = 0.0; 148 | confusionMatrix(1, 0) = 0.0; 149 | confusionMatrix(1, 1) = 0.5; 150 | confusionMatrix(1, 2) = 0.5; 151 | confusionMatrix(2, 0) = 0.0; 152 | confusionMatrix(2, 1) = 0.25; 153 | confusionMatrix(2, 2) = 0.75; 154 | 155 | double pixelAccuracy = 0.95; 156 | double pixelAccuracyWithoutVoid = 0.85; 157 | 158 | Result result(confusionMatrix, pixelAccuracy, pixelAccuracyWithoutVoid, LossFunctionType::CLASS_ACCURACY); 159 | 160 | BOOST_CHECK_EQUAL(result.getLoss(), 1.0 - (1.0 + 0.5 + 0.75) / 3.0); 161 | 162 | result.setLossFunctionType(LossFunctionType::CLASS_ACCURACY_WITHOUT_VOID); 163 | BOOST_CHECK_EQUAL(result.getLoss(), 1.0 - (0.5 + 0.75) / 2.0); 164 | 165 | result.setLossFunctionType(LossFunctionType::PIXEL_ACCURACY); 166 | BOOST_CHECK_EQUAL(result.getLoss(), 1.0 - pixelAccuracy); 167 | 168 | result.setLossFunctionType(LossFunctionType::PIXEL_ACCURACY_WITHOUT_VOID); 169 | BOOST_CHECK_EQUAL(result.getLoss(), 1.0 - pixelAccuracyWithoutVoid); 170 | 171 | } 172 | BOOST_AUTO_TEST_SUITE_END() 173 | -------------------------------------------------------------------------------- /src/tests/image_cache_test.cu: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #define BOOST_TEST_MODULE example 29 | 30 | #include 31 | #include 32 | 33 | #include "image.h" 34 | #include "random_tree_image_gpu.h" 35 | #include "test_common.h" 36 | #include "utils.h" 37 | 38 | BOOST_AUTO_TEST_SUITE(ImageCacheTest) 39 | 40 | using namespace curfil; 41 | 42 | BOOST_AUTO_TEST_CASE(testImageCacheSimple) { 43 | 44 | int width = 41; 45 | int height = 33; 46 | const int imageCacheSize = 3; 47 | 48 | std::vector images(10, RGBDImage(width, height)); 49 | 50 | ImageCache imageCache; 51 | 52 | std::map& map = imageCache.getIdMap(); 53 | 54 | BOOST_CHECK(map.empty()); 55 | 56 | std::vector samples; 57 | imageCache.copyImages(imageCacheSize, getPointers(samples)); 58 | 59 | BOOST_CHECK(map.empty()); 60 | 61 | samples.clear(); 62 | samples.push_back(PixelInstance(&images[0], 0, Depth(1.0), 0, 0)); 63 | samples.push_back(PixelInstance(&images[1], 0, Depth(1.0), 0, 0)); 64 | 65 | imageCache.copyImages(imageCacheSize, getPointers(samples)); 66 | BOOST_CHECK_EQUAL(2lu, map.size()); 67 | 68 | samples.clear(); 69 | samples.push_back(PixelInstance(&images[2], 0, Depth(1.0), 0, 0)); 70 | samples.push_back(PixelInstance(&images[1], 0, Depth(1.0), 0, 0)); 71 | 72 | imageCache.copyImages(imageCacheSize, getPointers(samples)); 73 | BOOST_CHECK_EQUAL(3lu, map.size()); 74 | 75 | samples.clear(); 76 | samples.push_back(PixelInstance(&images[1], 0, Depth(1.0), 0, 0)); 77 | samples.push_back(PixelInstance(&images[2], 0, Depth(1.0), 0, 0)); 78 | samples.push_back(PixelInstance(&images[3], 0, Depth(1.0), 0, 0)); 79 | 80 | CURFIL_INFO("now, image 0 must be dropped. image 3 must be transferred"); 81 | 82 | imageCache.copyImages(imageCacheSize, getPointers(samples)); 83 | 84 | BOOST_CHECK_EQUAL(3lu, map.size()); 85 | BOOST_CHECK(map.find(&images[0]) == map.end()); 86 | BOOST_CHECK(map.find(&images[1]) != map.end()); 87 | BOOST_CHECK(map.find(&images[2]) != map.end()); 88 | BOOST_CHECK(map.find(&images[3]) != map.end()); 89 | 90 | // use image 1 and 3 but not 2, so 2 must be removed next 91 | 92 | samples.clear(); 93 | samples.push_back(PixelInstance(&images[1], 0, Depth(1.0), 0, 0)); 94 | samples.push_back(PixelInstance(&images[3], 0, Depth(1.0), 0, 0)); 95 | samples.push_back(PixelInstance(&images[3], 0, Depth(1.0), 0, 0)); 96 | samples.push_back(PixelInstance(&images[1], 0, Depth(1.0), 0, 0)); 97 | 98 | imageCache.copyImages(imageCacheSize, getPointers(samples)); 99 | 100 | // still all 3 images must be in there 101 | BOOST_CHECK_EQUAL(3lu, map.size()); 102 | BOOST_CHECK(map.find(&images[0]) == map.end()); 103 | BOOST_CHECK(map.find(&images[1]) != map.end()); 104 | BOOST_CHECK(map.find(&images[2]) != map.end()); 105 | BOOST_CHECK(map.find(&images[3]) != map.end()); 106 | 107 | samples.clear(); 108 | samples.push_back(PixelInstance(&images[4], 0, Depth(1.0), 0, 0)); 109 | 110 | imageCache.copyImages(imageCacheSize, getPointers(samples)); 111 | 112 | // image 2 must be evicted 113 | BOOST_CHECK_EQUAL(3lu, map.size()); 114 | BOOST_CHECK(map.find(&images[0]) == map.end()); 115 | BOOST_CHECK(map.find(&images[1]) != map.end()); 116 | BOOST_CHECK(map.find(&images[2]) == map.end()); 117 | BOOST_CHECK(map.find(&images[3]) != map.end()); 118 | BOOST_CHECK(map.find(&images[4]) != map.end()); 119 | 120 | CURFIL_INFO("done"); 121 | } 122 | BOOST_AUTO_TEST_SUITE_END() 123 | -------------------------------------------------------------------------------- /src/tests/import_export_test.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #define BOOST_TEST_MODULE example 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "export.h" 44 | #include "image.h" 45 | #include "import.h" 46 | #include "random_forest_image.h" 47 | #include "random_tree_image.h" 48 | #include "test_common.h" 49 | 50 | using namespace curfil; 51 | 52 | static const int NUM_THREADS = 4; 53 | static const std::string folderOutput("test.out"); 54 | 55 | BOOST_AUTO_TEST_SUITE(ImportExportTest) 56 | 57 | template 58 | static void checkEquals(const cuv::ndarray& a, const cuv::ndarray& b) { 59 | BOOST_CHECK_EQUAL(a.size(), b.size()); 60 | BOOST_CHECK_EQUAL(a.ndim(), b.ndim()); 61 | for (size_t i = 0; i < a.size(); i++) { 62 | BOOST_CHECK_EQUAL(a[i], b[i]); 63 | } 64 | } 65 | 66 | static void checkTrees(const boost::shared_ptr >& a, 67 | const boost::shared_ptr >& b) { 68 | 69 | BOOST_CHECK_EQUAL(a->getNodeId(), b->getNodeId()); 70 | BOOST_CHECK_EQUAL(a->getLevel(), b->getLevel()); 71 | 72 | BOOST_CHECK_EQUAL(a->countNodes(), b->countNodes()); 73 | BOOST_CHECK_EQUAL(a->countLeafNodes(), b->countLeafNodes()); 74 | 75 | BOOST_CHECK_EQUAL(a->isRoot(), b->isRoot()); 76 | BOOST_CHECK_EQUAL(a->isLeaf(), b->isLeaf()); 77 | 78 | BOOST_CHECK_EQUAL(a->getNumClasses(), b->getNumClasses()); 79 | BOOST_CHECK_EQUAL(a->getTreeDepth(), b->getTreeDepth()); 80 | 81 | checkEquals(a->getHistogram(), b->getHistogram()); 82 | 83 | if (!a->isLeaf()) { 84 | BOOST_CHECK_EQUAL(a->getSplit().getFeatureId(), b->getSplit().getFeatureId()); 85 | BOOST_CHECK_CLOSE(a->getSplit().getThreshold(), b->getSplit().getThreshold(), 1e-4); 86 | BOOST_CHECK_CLOSE(a->getSplit().getScore(), b->getSplit().getScore(), 1e-5); 87 | 88 | checkTrees(a->getLeft(), b->getLeft()); 89 | checkTrees(a->getRight(), b->getRight()); 90 | } else { 91 | BOOST_CHECK(a->getLeft() == NULL); 92 | BOOST_CHECK(b->getLeft() == NULL); 93 | BOOST_CHECK(a->getRight() == NULL); 94 | BOOST_CHECK(b->getRight() == NULL); 95 | } 96 | } 97 | static void checkTrees(const boost::shared_ptr& a, 98 | const boost::shared_ptr& b) { 99 | BOOST_CHECK(a->getClassLabelPriorDistribution() == b->getClassLabelPriorDistribution()); 100 | checkTrees(a->getTree(), b->getTree()); 101 | } 102 | 103 | BOOST_AUTO_TEST_CASE(testExportImport) { 104 | std::vector trainImages; 105 | const bool useCIELab = true; 106 | const bool useDepthFilling = false; 107 | const bool useDepthImages = true; 108 | 109 | if (boost::unit_test::framework::master_test_suite().argc < 2) { 110 | throw std::runtime_error("please specify folder with testdata"); 111 | } 112 | const std::string folderTraining(boost::unit_test::framework::master_test_suite().argv[1]); 113 | 114 | trainImages.push_back(loadImagePair(folderTraining + "/training1_colors.png", useCIELab, useDepthImages,useDepthFilling)); 115 | 116 | // Train 117 | 118 | size_t trees = 3; 119 | 120 | unsigned int samplesPerImage = 500; 121 | unsigned int featureCount = 500; 122 | unsigned int minSampleCount = 32; 123 | int maxDepth = 10; 124 | uint16_t boxRadius = 50; 125 | uint16_t regionSize = 10; 126 | uint16_t thresholds = 10; 127 | int numThreads = NUM_THREADS; 128 | int maxImages = 10; 129 | int imageCacheSize = 10; 130 | unsigned int maxSamplesPerBatch = 5000; 131 | AccelerationMode accelerationMode = AccelerationMode::GPU_AND_CPU_COMPARE; 132 | 133 | const int SEED = 4711; 134 | 135 | std::vector ignoredColors; 136 | ignoredColors.push_back("50,205,50"); // this color must exist. otherwise an exception will be thrown 137 | 138 | std::vector deviceIds; 139 | deviceIds.push_back(0); 140 | 141 | TrainingConfiguration configuration(SEED, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 142 | regionSize, thresholds, numThreads, maxImages, imageCacheSize, maxSamplesPerBatch, accelerationMode, 143 | true, false, deviceIds, "classUniform", ignoredColors); 144 | 145 | RandomForestImage randomForest(trees, configuration); 146 | randomForest.train(trainImages); 147 | 148 | for (const bool verbose : { true, false }) { 149 | boost::filesystem::create_directory(folderOutput); 150 | RandomTreeExport treeExport(configuration, folderOutput, folderTraining, verbose); 151 | treeExport.writeJSON(randomForest); 152 | 153 | for (size_t treeNr = 0; treeNr < trees; treeNr++) { 154 | const std::string filename = boost::str(boost::format("%s/tree%d.json.gz") % folderOutput % treeNr); 155 | boost::shared_ptr tree; 156 | std::string hostname; 157 | boost::filesystem::path trainingFolder; 158 | boost::posix_time::ptime date; 159 | TrainingConfiguration readConfiguration = RandomTreeImport::readJSON(filename, tree, hostname, 160 | trainingFolder, date); 161 | BOOST_CHECK(readConfiguration == configuration); 162 | BOOST_CHECK(tree); 163 | checkTrees(tree, randomForest.getTree(treeNr)); 164 | } 165 | } 166 | 167 | } 168 | BOOST_AUTO_TEST_SUITE_END() 169 | -------------------------------------------------------------------------------- /src/tests/random_tree_image_test.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #define BOOST_TEST_MODULE example 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "export.h" 43 | #include "image.h" 44 | #include "predict.h" 45 | #include "random_forest_image.h" 46 | #include "random_tree_image.h" 47 | 48 | using namespace curfil; 49 | 50 | static const int NUM_THREADS = 4; 51 | static const std::string folderOutput("test.out"); 52 | 53 | BOOST_AUTO_TEST_SUITE(RandomTreeImageTest) 54 | 55 | static std::string getFolderTraining() { 56 | if (boost::unit_test::framework::master_test_suite().argc < 2) { 57 | throw std::runtime_error("please specify folder with testdata"); 58 | } 59 | return boost::unit_test::framework::master_test_suite().argv[1]; 60 | } 61 | 62 | static double predict(RandomForestImage& randomForest) { 63 | 64 | const bool useCIELab = true; 65 | const bool useDepthFilling = false; 66 | const bool useDepthImages = true; 67 | const auto testing = loadImagePair(getFolderTraining() + "/testing1_colors.png", useCIELab, useDepthImages, useDepthFilling); 68 | const LabelImage& groundTruth = testing.getLabelImage(); 69 | 70 | randomForest.normalizeHistograms(0.0, true); 71 | 72 | LabelImage prediction = randomForest.predict(testing.getRGBDImage()); 73 | 74 | boost::filesystem::create_directory(folderOutput); 75 | 76 | groundTruth.save(folderOutput + "/testing1_groundTruth.png"); 77 | prediction.save(folderOutput + "/testing1_prediction_singletree_cpu_gpu.png"); 78 | 79 | std::vector ignoredLabels; 80 | for (const std::string colorString : randomForest.getConfiguration().getIgnoredColors()) { 81 | ignoredLabels.push_back(LabelImage::encodeColor(RGBColor(colorString))); 82 | } 83 | 84 | ConfusionMatrix confusionMatrix(randomForest.getNumClasses()); 85 | double accuracy = 100 * calculatePixelAccuracy(prediction, groundTruth, true, &ignoredLabels); 86 | double accuracyWithoutVoid = 100 * calculatePixelAccuracy(prediction, groundTruth, false, &ignoredLabels, &confusionMatrix); 87 | 88 | CURFIL_INFO("accuracy (no void): " << accuracy << " (" << accuracyWithoutVoid << ")"); 89 | 90 | return accuracy; 91 | } 92 | 93 | BOOST_AUTO_TEST_CASE(trainTest) { 94 | const bool useCIELab = true; 95 | const bool useDepthFilling = false; 96 | const bool useDepthImages = true; 97 | 98 | std::vector trainImages; 99 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training1_colors.png", useCIELab, useDepthImages, useDepthFilling)); 100 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training2_colors.png", useCIELab, useDepthImages, useDepthFilling)); 101 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training3_colors.png", useCIELab, useDepthImages, useDepthFilling)); 102 | 103 | tbb::task_scheduler_init init(NUM_THREADS); 104 | 105 | // Train 106 | 107 | unsigned int samplesPerImage = 500; 108 | unsigned int featureCount = 500; 109 | unsigned int minSampleCount = 100; 110 | int maxDepth = 10; 111 | uint16_t boxRadius = 127; 112 | uint16_t regionSize = 16; 113 | uint16_t thresholds = 50; 114 | int numThreads = NUM_THREADS; 115 | int maxImages = 10; 116 | int imageCacheSize = 10; 117 | unsigned int maxSamplesPerBatch = 5000; 118 | AccelerationMode accelerationMode = AccelerationMode::GPU_AND_CPU_COMPARE; 119 | 120 | const int SEED = 4713; 121 | 122 | TrainingConfiguration configuration(SEED, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 123 | regionSize, thresholds, numThreads, maxImages, imageCacheSize, maxSamplesPerBatch, accelerationMode); 124 | 125 | RandomForestImage randomForest(1, configuration); 126 | randomForest.train(trainImages); 127 | 128 | double accuracy = predict(randomForest); 129 | 130 | BOOST_CHECK_CLOSE_FRACTION(73, accuracy, 10.0); 131 | } 132 | 133 | BOOST_AUTO_TEST_CASE(trainTestGPU) { 134 | const bool useCIELab = true; 135 | const bool useDepthFilling = false; 136 | const bool useDepthImages = true; 137 | 138 | std::vector trainImages; 139 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training1_colors.png", useCIELab, useDepthImages, useDepthFilling)); 140 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training2_colors.png", useCIELab, useDepthImages, useDepthFilling)); 141 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training3_colors.png", useCIELab, useDepthImages, useDepthFilling)); 142 | 143 | tbb::task_scheduler_init init(NUM_THREADS); 144 | 145 | // Train 146 | 147 | unsigned int samplesPerImage = 500; 148 | unsigned int featureCount = 500; 149 | unsigned int minSampleCount = 100; 150 | int maxDepth = 10; 151 | uint16_t boxRadius = 127; 152 | uint16_t regionSize = 16; 153 | uint16_t thresholds = 50; 154 | int maxImages = 10; 155 | int imageCacheSize = 10; 156 | unsigned int maxSamplesPerBatch = 5000; 157 | AccelerationMode accelerationMode = AccelerationMode::GPU_ONLY; 158 | 159 | const int SEED = 4711; 160 | 161 | TrainingConfiguration configuration(SEED, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 162 | regionSize, thresholds, NUM_THREADS, maxImages, imageCacheSize, maxSamplesPerBatch, accelerationMode); 163 | 164 | RandomForestImage randomForest(1, configuration); 165 | randomForest.train(trainImages); 166 | 167 | double accuracy = predict(randomForest); 168 | 169 | BOOST_CHECK_CLOSE_FRACTION(73, accuracy, 10.0); 170 | } 171 | 172 | BOOST_AUTO_TEST_CASE(trainTestEnsemble) { 173 | 174 | const bool useCIELab = true; 175 | const bool useDepthFilling = false; 176 | const bool useDepthImages = true; 177 | 178 | std::vector trainImages; 179 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training1_colors.png", useCIELab, useDepthImages, useDepthFilling)); 180 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training2_colors.png", useCIELab, useDepthImages, useDepthFilling)); 181 | trainImages.push_back(loadImagePair(getFolderTraining() + "/training3_colors.png", useCIELab, useDepthImages, useDepthFilling)); 182 | 183 | // Train 184 | 185 | unsigned int samplesPerImage = 2000; 186 | unsigned int featureCount = 500; 187 | unsigned int minSampleCount = 32; 188 | int maxDepth = 14; 189 | uint16_t boxRadius = 120; 190 | uint16_t regionSize = 10; 191 | uint16_t thresholds = 50; 192 | int maxImages = 3; 193 | int imageCacheSize = 3; 194 | unsigned int maxSamplesPerBatch = 5000; 195 | AccelerationMode accelerationMode = AccelerationMode::GPU_AND_CPU_COMPARE; 196 | 197 | const int SEED = 64684263; 198 | 199 | TrainingConfiguration configuration(SEED, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 200 | regionSize, thresholds, NUM_THREADS, maxImages, imageCacheSize, maxSamplesPerBatch, accelerationMode); 201 | 202 | size_t trees = 3; 203 | 204 | RandomForestImage randomForest(trees, configuration); 205 | randomForest.train(trainImages); 206 | 207 | double accuracy = predict(randomForest); 208 | 209 | BOOST_CHECK_CLOSE_FRACTION(76, accuracy, 5.0); 210 | 211 | // 2nd attempt on GPU 212 | accelerationMode = AccelerationMode::GPU_ONLY; 213 | double accuracy2; 214 | { 215 | TrainingConfiguration configuration(SEED, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 216 | regionSize, thresholds, NUM_THREADS, maxImages, imageCacheSize, maxSamplesPerBatch, accelerationMode); 217 | RandomForestImage randomForest(trees, configuration); 218 | randomForest.train(trainImages); 219 | 220 | accuracy2 = predict(randomForest); 221 | 222 | BOOST_CHECK_CLOSE_FRACTION(accuracy, accuracy2, 2.5); 223 | } 224 | 225 | // 3rd attempt on GPU 226 | { 227 | TrainingConfiguration configuration(SEED, samplesPerImage, featureCount, minSampleCount, maxDepth, boxRadius, 228 | regionSize, thresholds, NUM_THREADS, maxImages, imageCacheSize, maxSamplesPerBatch, accelerationMode); 229 | RandomForestImage randomForest(trees, configuration); 230 | randomForest.train(trainImages); 231 | 232 | double accuracy3 = predict(randomForest); 233 | 234 | BOOST_CHECK_CLOSE_FRACTION(accuracy2, accuracy3, 1.0); 235 | } 236 | 237 | } 238 | BOOST_AUTO_TEST_SUITE_END() 239 | -------------------------------------------------------------------------------- /src/tests/random_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #define BOOST_TEST_MODULE example 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "random_tree.h" 39 | #include "test_common.h" 40 | 41 | using namespace curfil; 42 | using namespace cuv; 43 | 44 | BOOST_AUTO_TEST_SUITE(RandomTreeTest) 45 | 46 | BOOST_AUTO_TEST_CASE(testNormalizeHistogramEqualPriorDistribution) { 47 | 48 | const LabelType NUM_LABELS = 3; 49 | 50 | cuv::ndarray histogram(NUM_LABELS); 51 | histogram[0] = 850; 52 | histogram[1] = 50; 53 | histogram[2] = 100; 54 | 55 | cuv::ndarray priorDistribution(NUM_LABELS); 56 | for (LabelType label = 0; label < NUM_LABELS; label++) { 57 | priorDistribution[label] = 100; 58 | } 59 | 60 | ndarray normalizedHistogram = curfil::detail::normalizeHistogram(histogram, 61 | priorDistribution, 0.0, true); 62 | 63 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[0]), 0.850 / 3.0, 1e-15); 64 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[1]), 0.050 / 3.0, 1e-15); 65 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[2]), 0.100 / 3.0, 1e-15); 66 | } 67 | 68 | BOOST_AUTO_TEST_CASE(testNormalizeHistogramEqualHistogramUnequalPriorDistribution) { 69 | 70 | const LabelType NUM_LABELS = 3; 71 | 72 | cuv::ndarray histogram(NUM_LABELS); 73 | histogram[0] = 50; 74 | histogram[1] = 50; 75 | histogram[2] = 50; 76 | 77 | cuv::ndarray priorDistribution(NUM_LABELS); 78 | priorDistribution[0] = 80; 79 | priorDistribution[1] = 10; 80 | priorDistribution[2] = 10; 81 | 82 | ndarray normalizedHistogram = curfil::detail::normalizeHistogram(histogram, 83 | priorDistribution, 0.0, true); 84 | 85 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[0]), (1 / 3.0) * 0.8, 1e-15); 86 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[1]), (1 / 3.0) * 0.1, 1e-15); 87 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[2]), (1 / 3.0) * 0.1, 1e-15); 88 | } 89 | 90 | BOOST_AUTO_TEST_CASE(testNormalizeHistogramHighBias) { 91 | 92 | const LabelType NUM_LABELS = 3; 93 | 94 | cuv::ndarray histogram(NUM_LABELS); 95 | histogram[0] = 50; 96 | histogram[1] = 50; 97 | histogram[2] = 50; 98 | 99 | cuv::ndarray priorDistribution(NUM_LABELS); 100 | priorDistribution[0] = 80; 101 | priorDistribution[1] = 10; 102 | priorDistribution[2] = 10; 103 | 104 | ndarray normalizedHistogram = curfil::detail::normalizeHistogram(histogram, 105 | priorDistribution, 0.5, true); 106 | 107 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[0]), 0.0, 1e-15); 108 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[1]), 0.0, 1e-15); 109 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[2]), 0.0, 1e-15); 110 | } 111 | 112 | BOOST_AUTO_TEST_CASE(testNormalizeHistogramMediumBias) { 113 | 114 | const LabelType NUM_LABELS = 3; 115 | 116 | cuv::ndarray histogram(NUM_LABELS); 117 | histogram[0] = 60; 118 | histogram[1] = 20; 119 | histogram[2] = 20; 120 | 121 | cuv::ndarray priorDistribution(NUM_LABELS); 122 | priorDistribution[0] = 50; 123 | priorDistribution[1] = 25; 124 | priorDistribution[2] = 25; 125 | 126 | ndarray normalizedHistogram = curfil::detail::normalizeHistogram(histogram, 127 | priorDistribution, 0.5, true); 128 | 129 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[0]), 0.5, 1e-15); 130 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[1]), 0.0, 1e-15); 131 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[2]), 0.0, 1e-15); 132 | } 133 | 134 | BOOST_AUTO_TEST_CASE(testNormalizeHistogramLowBias) { 135 | 136 | const LabelType NUM_LABELS = 3; 137 | 138 | cuv::ndarray histogram(NUM_LABELS); 139 | histogram[0] = 20; 140 | histogram[1] = 40; 141 | histogram[2] = 40; 142 | 143 | cuv::ndarray priorDistribution(NUM_LABELS); 144 | priorDistribution[0] = 20; 145 | priorDistribution[1] = 10; 146 | priorDistribution[2] = 10; 147 | 148 | ndarray normalizedHistogram = curfil::detail::normalizeHistogram(histogram, 149 | priorDistribution, 0.2, true); 150 | 151 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[0]), 0.0, 1e-15); 152 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[1]), 0.5 * 0.25, 1e-15); 153 | BOOST_CHECK_CLOSE(static_cast(normalizedHistogram[2]), 0.5 * 0.25, 1e-15); 154 | } 155 | 156 | BOOST_AUTO_TEST_CASE(testReservoirSampler) { 157 | 158 | size_t sampleSize = 1000; 159 | const int MAX = 100000; 160 | 161 | RandomSource randomSource(4711); 162 | Sampler sampler = randomSource.uniformSampler(0, 10 * MAX); 163 | 164 | ReservoirSampler reservoirSampler(sampleSize); 165 | for (int i = 0; i < MAX; i++) { 166 | reservoirSampler.sample(sampler, i); 167 | } 168 | 169 | const auto& reservoir = reservoirSampler.getReservoir(); 170 | BOOST_REQUIRE_EQUAL(reservoir.size(), sampleSize); 171 | 172 | boost::accumulators::accumulator_set > acc; 178 | 179 | acc = std::for_each(reservoir.begin(), reservoir.end(), acc); 180 | 181 | double min = boost::accumulators::min(acc); 182 | double max = boost::accumulators::max(acc); 183 | double mean = boost::accumulators::mean(acc); 184 | double stddev = std::sqrt(static_cast(boost::accumulators::variance(acc))); 185 | 186 | /* 187 | * values are empirically determined with python and numpy 188 | * 189 | * >>> import random, numpy as np 190 | * >>> a = np.arange(100000) 191 | * >>> random.shuffle(a) 192 | * >>> b = a[:10000] 193 | * >>> b.mean() 194 | * 50271.870999999999 195 | * 196 | * >>> np.sqrt(b.var()) 197 | * 28804.962206705768 198 | * 199 | * >>> b.min() 200 | * 12.0 201 | * 202 | * >>> b.max() 203 | * 99996.0 204 | */ 205 | BOOST_REQUIRE_LT(min, 0.01 * MAX); 206 | BOOST_REQUIRE_GT(max, 0.99 * MAX); 207 | BOOST_REQUIRE_CLOSE(mean, 50000.0, 0.05); 208 | BOOST_REQUIRE_CLOSE(stddev, 28000.0, 2.0); 209 | } 210 | BOOST_AUTO_TEST_SUITE_END() 211 | -------------------------------------------------------------------------------- /src/tests/test_common.h: -------------------------------------------------------------------------------- 1 | #if 0 2 | ####################################################################################### 3 | # The MIT License 4 | 5 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 6 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 7 | # Copyright (c) 2008-2009 Sebastian Nowozin 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in all 17 | # copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | ####################################################################################### 27 | #endif 28 | #ifndef CURFIL_TEST_COMMON_H 29 | #define CURFIL_TEST_COMMON_H 30 | 31 | #include 32 | 33 | template 34 | std::vector getPointers(const std::vector& v) { 35 | std::vector r(v.size()); 36 | for (size_t i = 0; i < v.size(); i++) { 37 | r[i] = &v[i]; 38 | } 39 | return r; 40 | } 41 | 42 | template 43 | bool operator==(const cuv::ndarray& a, 44 | const cuv::ndarray& b) { 45 | 46 | if (a.ndim() != b.ndim()) { 47 | return false; 48 | } 49 | 50 | if (a.shape() != b.shape()) { 51 | return false; 52 | } 53 | 54 | for (size_t i = 0; i < a.size(); i++) { 55 | if (a.ptr()[i] != b.ptr()[i]) { 56 | return false; 57 | } 58 | } 59 | 60 | return true; 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /util/add_license.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | ####################################################################################### 4 | # The MIT License 5 | 6 | # Copyright (c) 2014 Hannes Schulz, University of Bonn 7 | # Copyright (c) 2013 Benedikt Waldvogel, University of Bonn 8 | # Copyright (c) 2008-2009 Sebastian Nowozin 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | # 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | ####################################################################################### 28 | 29 | use File::Find; 30 | use Carp::Assert; 31 | use Cwd; 32 | 33 | 34 | sub get_license{ 35 | $is_python = shift; 36 | open LIC, "<$basedir/LICENSE.txt" or die $!; 37 | my @lines; 38 | while(){ 39 | next if $is_python and /^#if 0$/; 40 | next if $is_python and /^#endif$/; 41 | push @lines, $_; 42 | } 43 | return join "", @lines; 44 | } 45 | 46 | sub add_license{ 47 | $file = shift; 48 | open FH, "<$file" or die $!; 49 | open OUT, ">$file.new" or die $!; 50 | 51 | $is_python = $file =~ /\.py$/; 52 | 53 | $firstline = ""; 54 | if($is_python){ 55 | $firstline = ; 56 | if($firstline =~ /python/){ 57 | print OUT $firstline; 58 | $firstline = ""; 59 | } 60 | } 61 | print OUT get_license($is_python); 62 | print OUT $firstline; 63 | while(){ 64 | print OUT $_; 65 | } 66 | close OUT; 67 | close FH; 68 | $ret = system("mv '$file.new' '$file'"); 69 | assert($ret == 0); 70 | } 71 | 72 | sub has_license{ 73 | $filename = shift; 74 | return 0 == system("grep -q Copyright $filename"); 75 | } 76 | 77 | sub wanted{ 78 | $filename = $_; 79 | return if $filename !~ /\.(py|h|hpp|cuh|c|cpp|cu)$/; 80 | #`git checkout $filename`; 81 | return if has_license($filename); 82 | $cwd = cwd(); 83 | print "Adding license to $filename ($cwd)\n"; 84 | add_license($filename); 85 | `git add $filename`; 86 | } 87 | 88 | $basedir = cwd(); 89 | sub main{ 90 | find(\&wanted, $basedir); 91 | } 92 | 93 | main() 94 | --------------------------------------------------------------------------------