diff --git a/.gitignore b/.gitignore index 53c1fb056bb..8e20be3bbbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ ## General +# Fuse files +*.fuse* + # Compiled Object files *.slo *.lo @@ -69,6 +72,7 @@ models/* *lmdb # build, distribute, and bins (+ python proto bindings) +cmake_build build .build_debug/* .build_release/* @@ -78,6 +82,7 @@ distribute/* python/caffe/proto/ cmake_build .cmake_build +*.gen.cmake # Generated documentation docs/_site diff --git a/CMakeLists.txt b/CMakeLists.txt index 32cc42ac9de..c13d2db852c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,8 +26,13 @@ include(cmake/Summary.cmake) include(cmake/ConfigGen.cmake) # ---[ Options -caffe_option(CPU_ONLY "Build Caffe without CUDA support" OFF) # TODO: rename to USE_CUDA -caffe_option(USE_CUDNN "Build Caffe with cuDNN library support" ON IF NOT CPU_ONLY) +caffe_option(CPU_ONLY "Build Caffe without CUDA and OpenCL support" OFF) +caffe_option(USE_INDEX_64 "Build Caffe with 64 bit indexing" OFF) +caffe_option(USE_CUDA "Build Caffe with CUDA support" ON) +caffe_option(USE_GREENTEA "Build Caffe with OpenCL support" ON) +caffe_option(USE_CLBLAS "Build Caffe with clBLAS support (instead of using ViennaClBLAS)" OFF) +caffe_option(USE_ISAAC "Build Caffe with ISAAC support (instead of using ViennaClBLAS)" OFF) +caffe_option(USE_CUDNN "Build Caffe with cuDNN libary support" OFF) caffe_option(BUILD_SHARED_LIBS "Build shared libraries" ON) caffe_option(BUILD_python "Build Python wrapper" ON) set(python_version "2" CACHE STRING "Specify which Python version to use") @@ -39,16 +44,28 @@ caffe_option(USE_LEVELDB "Build with levelDB" ON) caffe_option(USE_LMDB "Build with lmdb" ON) caffe_option(ALLOW_LMDB_NOLOCK "Allow MDB_NOLOCK when reading LMDB files (only if necessary)" OFF) +# ---[ Flag consistency check +if(CPU_ONLY) + set(USE_CUDA OFF) + set(USE_GREENTEA OFF) + set(USE_CUDNN OFF) + set(USE_CLBLAS OFF) +endif() + +if(USE_ISAAC) + set(USE_CLBLAS ON) +endif() + # ---[ Dependencies include(cmake/Dependencies.cmake) # ---[ Flags if(UNIX OR APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -std=c++11 -DCMAKE_BUILD") endif() if(USE_libstdcpp) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -std=c++11") message("-- Warning: forcing libstdc++ (controlled by USE_libstdcpp option in cmake)") endif() diff --git a/Makefile b/Makefile index 76d51ad8bd0..916d9973ffe 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,15 @@ $(error $(CONFIG_FILE) not found. See $(CONFIG_FILE).example.) endif include $(CONFIG_FILE) +ifeq ($(CPU_ONLY),1) + USE_CUDA := 0 + USE_GREENTEA := 0 +endif + +CXXFLAGS += -std=c++11 -fopenmp -Wno-deprecated-declarations +LINKFLAGS += -std=c++11 -fopenmp -Wno-deprecated-declarations +NVCCFLAGS += -Xcompiler "-Wno-deprecated-declarations" -Xlinker "-Wno-deprecated-declarations" -Xarchive "-Wno-deprecated-declarations" -Xnvlink "-Wno-deprecated-declarations" + BUILD_DIR_LINK := $(BUILD_DIR) ifeq ($(RELEASE_BUILD_DIR),) RELEASE_BUILD_DIR := .$(BUILD_DIR)_release @@ -24,6 +33,7 @@ else OTHER_BUILD_DIR := $(DEBUG_BUILD_DIR) endif + # All of the directories containing code. SRC_DIRS := $(shell find * -type d -exec bash -c "find {} -maxdepth 1 \ \( -name '*.cpp' -o -name '*.proto' \) | grep -q ." \; -print) @@ -159,6 +169,82 @@ ALL_WARNS := $(ALL_CXX_WARNS) $(ALL_CU_WARNS) EMPTY_WARN_REPORT := $(BUILD_DIR)/.$(WARNS_EXT) NONEMPTY_WARN_REPORT := $(BUILD_DIR)/$(WARNS_EXT) +############################## +# GreenTea backend related include and lib +############################## + +ifeq ($(USE_INDEX_64),1) + COMMON_FLAGS += -DUSE_INDEX_64 +endif + +ifeq ($(USE_GREENTEA),1) + # Find a valid OpenCL library + # TODO: Validate and complete this based on different SDKs + ifdef OPENCL_INC + CLLINC = '$(OPENCL_INC)' + endif + + ifdef OPENCL_LIB + CLLIBS = '$(OPENCL_LIB)' + endif + + ifdef OPENCLROOT + CLLIBS = '$(OPENCLROOT)' + endif + + ifdef CUDA_PATH + CLLIBS = '$(CUDA_PATH)/lib/x64' + endif + + ifdef INTELOCLSDKROOT + CLLIBS = '$(INTELOCLSDKROOT)/lib/x64' + endif + + ifdef AMDAPPSDKROOT + CLLIBS = '$(AMDAPPSDKROOT)/lib/x86_64' + CLLINC = '$(AMDAPPSDKROOT)/include' + endif + + # Use AMD clBLAS + ifeq ($(USE_CLBLAS), 1) + LIBRARIES += clBLAS + COMMON_FLAGS += -DUSE_CLBLAS + endif + + # Use ISAAC clBLAS replacement + ifeq ($(USE_ISAAC), 1) + LIBRARIES += isaac + COMMON_FLAGS += -DUSE_CLBLAS + endif + + # Requires valid OpenCL library + LIBRARY_DIRS += $(CLLIBS) + # Requires valid OpenCL headers and valid ViennaCL + INCLUDE_DIRS += $(CLLINC) $(VIENNACL_DIR) + # Requires OpenCL compile library flag and librt + ifeq ($(OS_X), 1) + LDFLAGS += -framework OpenCL + else + LIBRARIES += OpenCL rt + endif + # Additional flags + COMMON_FLAGS += -DUSE_GREENTEA -DVIENNACL_WITH_OPENCL + + # Viennacl runtime debug output + ifeq ($(VIENNACL_DEBUG), 1) + COMMON_FLAGS += -DVIENNACL_DEBUG_ALL + endif + + CL_KERNELS_CPP = src/caffe/greentea/cl_kernels.cpp + CL_KERNELS = src/caffe/greentea/cl_kernels/*.cl + CL_HEADERS = src/caffe/greentea/cl_headers/*.cl + CL_KERNELS_SH = src/caffe/greentea/cl_kernels.sh +endif + +ifeq ($(USE_CUDA), 1) + COMMON_FLAGS += -DUSE_CUDA +endif + ############################## # Derive include and lib directories ############################## @@ -172,10 +258,10 @@ endif CUDA_LIB_DIR += $(CUDA_DIR)/lib INCLUDE_DIRS += $(BUILD_INCLUDE_DIR) ./src ./include -ifneq ($(CPU_ONLY), 1) +ifeq ($(USE_CUDA), 1) INCLUDE_DIRS += $(CUDA_INCLUDE_DIR) LIBRARY_DIRS += $(CUDA_LIB_DIR) - LIBRARIES := cudart cublas curand + LIBRARIES += cudart cublas curand endif LIBRARIES += glog gflags protobuf boost_system boost_filesystem m hdf5_hl hdf5 @@ -206,7 +292,6 @@ WARNINGS := -Wall -Wno-sign-compare # Set build directories ############################## -DISTRIBUTE_DIR ?= distribute DISTRIBUTE_SUBDIRS := $(DISTRIBUTE_DIR)/bin $(DISTRIBUTE_DIR)/lib DIST_ALIASES := dist ifneq ($(strip $(DISTRIBUTE_DIR)),distribute) @@ -278,6 +363,8 @@ ifeq ($(OSX), 1) # clang throws this warning for cuda headers WARNINGS += -Wno-unneeded-internal-declaration endif + # clang throws this warning for cuda headers + WARNINGS += -Wno-unneeded-internal-declaration # gtest needs to use its own tuple to not conflict with clang COMMON_FLAGS += -DGTEST_USE_OWN_TR1_TUPLE=1 # boost::thread is called boost_thread-mt to mark multithreading on OS X @@ -434,7 +521,7 @@ endif py mat py$(PROJECT) mat$(PROJECT) proto runtest \ superclean supercleanlist supercleanfiles warn everything -all: lib tools examples +all: $(CL_KERNELS_CPP) lib tools examples lib: $(STATIC_NAME) $(DYNAMIC_NAME) @@ -573,12 +660,19 @@ $(PROTO_BUILD_DIR)/%.pb.o: $(PROTO_BUILD_DIR)/%.pb.cc $(PROTO_GEN_HEADER) \ @ cat $@.$(WARNS_EXT) $(BUILD_DIR)/cuda/%.o: %.cu | $(ALL_BUILD_DIRS) +ifeq ($(USE_CUDA), 1) @ echo NVCC $< $(Q)$(CUDA_DIR)/bin/nvcc $(NVCCFLAGS) $(CUDA_ARCH) -M $< -o ${@:.o=.d} \ -odir $(@D) $(Q)$(CUDA_DIR)/bin/nvcc $(NVCCFLAGS) $(CUDA_ARCH) -c $< -o $@ 2> $@.$(WARNS_EXT) \ || (cat $@.$(WARNS_EXT); exit 1) @ cat $@.$(WARNS_EXT) +else + @ echo CXX $< + $(Q)$(CXX) $(CXXFLAGS) -c -x c++ $< -o $@ 2> $@.$(WARNS_EXT) \ + || (cat $@.$(WARNS_EXT); exit 1) + @ cat $@.$(WARNS_EXT) +endif $(TEST_ALL_BIN): $(TEST_MAIN_SRC) $(TEST_OBJS) $(GTEST_OBJ) \ | $(DYNAMIC_NAME) $(TEST_BIN_DIR) @@ -613,6 +707,11 @@ $(EXAMPLE_BINS): %.bin : %.o | $(DYNAMIC_NAME) $(Q)$(CXX) $< -o $@ $(LINKFLAGS) -l$(LIBRARY_NAME) $(LDFLAGS) \ -Wl,-rpath,$(ORIGIN)/../../lib +# Copy the OpenCL kernels into C++ char strings +$(CL_KERNELS_CPP) : $(CL_HEADERS) $(CL_KERNELS) + chmod +x $(CL_KERNELS_SH) + $(CL_KERNELS_SH) + proto: $(PROTO_GEN_CC) $(PROTO_GEN_HEADER) $(PROTO_BUILD_DIR)/%.pb.cc $(PROTO_BUILD_DIR)/%.pb.h : \ diff --git a/Makefile.config.example b/Makefile.config.example index 8fd49c9c1a7..c1d4bbdf07a 100644 --- a/Makefile.config.example +++ b/Makefile.config.example @@ -1,6 +1,26 @@ ## Refer to http://caffe.berkeleyvision.org/installation.html # Contributions simplifying and improving our build system are welcome! +# 32 bit / 64 bit indexing +# USE_INDEX_64 := 1 + +# GreenTea (ViennaCL/OpenCL) backend switch + +# Enable the CUDA backend +USE_CUDA := 1 + +# Enable the OpenCL/Greentea backend +USE_GREENTEA := 0 + +# Folder of the ViennaCL header-only library +VIENNACL_DIR = ../ViennaCL + +# Override BLAS, use clBLAS insead of ViennaclBLAS. +# USE_CLBLAS := 1 + +# Override BLAS, use ISAAC instead of ViennaclBLAS. +# USE_ISAAC := 1 + # cuDNN acceleration switch (uncomment to build with cuDNN). # USE_CUDNN := 1 @@ -103,6 +123,7 @@ DISTRIBUTE_DIR := distribute # Uncomment for debugging. Does not work on OSX due to https://github.com/BVLC/caffe/issues/171 # DEBUG := 1 +# VIENNACL_DEBUG := 0 # The ID of the GPU that 'make runtest' will use to run unit tests. TEST_GPUID := 0 diff --git a/README.md b/README.md index 44b9e62c157..5732cd73dd4 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,25 @@ Please cite Caffe in your publications if it helps your research: Title = {Caffe: Convolutional Architecture for Fast Feature Embedding}, Year = {2014} } + +## Additional Notes +This fork of Caffe contains an OpenCL backend and additional layers for fast image segmentation. +This work is partially supported by: +- AMD +- HHMI Janelia +- UZH, INI +- ETH Zurich + +For a C++ frontend and models to use for image segmentation with this fork, see: +- Frontend: https://github.com/naibaf7/caffe_neural_tool +- Models: https://github.com/naibaf7/caffe_neural_models + +## OpenCL Backend +The backend is supposed to work with all vendors. Note however there may be problems with libOpenCL.so provided by nVidia. +It is therefore recommended to install another OpenCL implementation after installing nVidia drivers. Possibilities are: +- Intel OpenCL, recommended if you have an Intel CPU along the nVidia GPU. +- AMD APP SDK (OpenCL), recommended if you have an AMD GPU or CPU. + +## Technical Report +Available on arXiv: +http://arxiv.org/abs/1509.03371 diff --git a/cmake/ConfigGen.cmake b/cmake/ConfigGen.cmake index 056371110b5..ceb94f11ce7 100644 --- a/cmake/ConfigGen.cmake +++ b/cmake/ConfigGen.cmake @@ -53,7 +53,6 @@ function(caffe_generate_export_configs) set(Caffe_DEFINITIONS "") if(NOT HAVE_CUDA) set(HAVE_CUDA FALSE) - list(APPEND Caffe_DEFINITIONS -DCPU_ONLY) endif() if(USE_OPENCV) @@ -73,8 +72,6 @@ function(caffe_generate_export_configs) if(NOT HAVE_CUDNN) set(HAVE_CUDNN FALSE) - else() - list(APPEND DEFINITIONS -DUSE_CUDNN) endif() if(BLAS STREQUAL "MKL" OR BLAS STREQUAL "mkl") diff --git a/cmake/Cuda.cmake b/cmake/Cuda.cmake index 286a42802b4..22da3420872 100644 --- a/cmake/Cuda.cmake +++ b/cmake/Cuda.cmake @@ -1,4 +1,4 @@ -if(CPU_ONLY) +if(CPU_ONLY OR NOT USE_CUDA) return() endif() @@ -145,11 +145,11 @@ macro(caffe_cuda_compile objlist_variable) endforeach() if(UNIX OR APPLE) - list(APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC) + list(APPEND CUDA_NVCC_FLAGS -Xcompiler -fPIC -std=c++11) endif() if(APPLE) - list(APPEND CUDA_NVCC_FLAGS -Xcompiler -Wno-unused-function) + list(APPEND CUDA_NVCC_FLAGS -std=c++11 -Xcompiler -Wno-unused-function) endif() cuda_compile(cuda_objcs ${ARGN}) @@ -239,9 +239,10 @@ list(APPEND Caffe_LINKER_LIBS ${CUDA_CUDART_LIBRARY} if(USE_CUDNN) detect_cuDNN() if(HAVE_CUDNN) - add_definitions(-DUSE_CUDNN) include_directories(SYSTEM ${CUDNN_INCLUDE}) list(APPEND Caffe_LINKER_LIBS ${CUDNN_LIBRARY}) + else() + message(FATAL_ERROR "CuDNN requested, but not found.") endif() endif() diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index c7b6a17aa69..62b775264dd 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -57,14 +57,45 @@ endif() # ---[ CUDA include(cmake/Cuda.cmake) if(NOT HAVE_CUDA) - if(CPU_ONLY) + if(CPU_ONLY OR NOT USE_CUDA) message(STATUS "-- CUDA is disabled. Building without it...") else() message(WARNING "-- CUDA is not detected by cmake. Building without it...") endif() +endif() - # TODO: remove this not cross platform define in future. Use caffe_config.h instead. - add_definitions(-DCPU_ONLY) +# ---[ ViennaCL +if (USE_GREENTEA) + find_package(ViennaCL) + if (NOT ViennaCL_FOUND) + message(FATAL_ERROR "ViennaCL required for GREENTEA but not found.") + endif() + include_directories(SYSTEM ${ViennaCL_INCLUDE_DIRS}) + list(APPEND Caffe_LINKER_LIBS ${ViennaCL_LIBRARIES}) + set(HAVE_VIENNACL TRUE) + set(VIENNACL_WITH_OPENCL ${ViennaCL_WITH_OPENCL}) +endif() + +# ---[ clBLAS +if (USE_CLBLAS AND NOT USE_ISAAC) + find_package(clBLAS) + if (NOT CLBLAS_FOUND) + message(FATAL_ERROR "clBLAS required but not found.") + endif() + include_directories(SYSTEM ${CLBLAS_INCLUDE_DIR}) + list(APPEND Caffe_LINKER_LIBS ${CLBLAS_LIBRARY}) + set(HAVE_CLBLAS TRUE) +endif() + +# ---[ ISAAC +if (USE_ISAAC) + find_package(ISAAC) + if (NOT ISAAC_FOUND) + message(FATAL_ERROR "ISAAC required but not found.") + endif() + # include_directories(SYSTEM ${CLBLAS_INCLUDE_DIR}) + list(APPEND Caffe_LINKER_LIBS ${ISAAC_LIBRARY}) + set(HAVE_ISAAC TRUE) endif() # ---[ OpenCV @@ -79,6 +110,11 @@ if(USE_OPENCV) add_definitions(-DUSE_OPENCV) endif() +# ---[ OpenMP +find_package(OpenMP QUIET) +# If OpenMP is not found then OpenMP_CXX_FLAGS will be empty +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + # ---[ BLAS if(NOT APPLE) set(BLAS "Atlas" CACHE STRING "Selected BLAS library") diff --git a/cmake/Modules/FindISAAC.cmake b/cmake/Modules/FindISAAC.cmake new file mode 100644 index 00000000000..d7edabae632 --- /dev/null +++ b/cmake/Modules/FindISAAC.cmake @@ -0,0 +1,47 @@ +SET(ISAAC_INCLUDE_SEARCH_PATHS + /usr/include + /usr/local/include + /opt/isaac/include + $ENV{ISAAC_HOME} + $ENV{ISAAC_HOME}/include +) + +SET(ISAAC_LIB_SEARCH_PATHS + /lib + /lib64 + /usr/lib + /usr/lib64 + /usr/local/lib + /usr/local/lib64 + /opt/isaac/lib + $ENV{ISAAC_HOME} + $ENV{ISAAC_HOME}/lib + ) + +FIND_PATH(ISAAC_INCLUDE_DIR NAMES isaac.h PATHS ${ISAAC_INCLUDE_SEARCH_PATHS}) +FIND_LIBRARY(ISAAC_LIBRARY NAMES isaac PATHS ${ISAAC_LIB_SEARCH_PATHS}) + +SET(ISAAC_FOUND ON) + +# Check libraries +IF(NOT ISAAC_LIBRARY) + SET(ISAAC_FOUND OFF) + MESSAGE(STATUS "Could not find ISAAC lib. Turning ISAAC_FOUND off") +ENDIF() + +IF (ISAAC_FOUND) + IF (NOT ISAAC_FIND_QUIETLY) + MESSAGE(STATUS "Found ISAAC libraries: ${ISAAC_LIBRARY}") + MESSAGE(STATUS "Found ISAAC include: ${ISAAC_INCLUDE_DIR}") + ENDIF (NOT ISAAC_FIND_QUIETLY) +ELSE (ISAAC_FOUND) + IF (ISAAC_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find ISAAC") + ENDIF (ISAAC_FIND_REQUIRED) +ENDIF (ISAAC_FOUND) + +MARK_AS_ADVANCED( + ISAAC_INCLUDE_DIR + ISAAC_LIBRARY +) + diff --git a/cmake/Modules/FindOpenCL.cmake b/cmake/Modules/FindOpenCL.cmake new file mode 100644 index 00000000000..cc7a0a2a2dc --- /dev/null +++ b/cmake/Modules/FindOpenCL.cmake @@ -0,0 +1,90 @@ +# This file taken from FindOpenCL project @ http://gitorious.com/findopencl +# +# - Try to find OpenCL +# This module tries to find an OpenCL implementation on your system. It supports +# AMD / ATI, Apple and NVIDIA implementations, but shoudl work, too. +# +# Once done this will define +# OPENCL_FOUND - system has OpenCL +# OPENCL_INCLUDE_DIRS - the OpenCL include directory +# OPENCL_LIBRARIES - link these to use OpenCL +# +# WIN32 should work, but is untested + +FIND_PACKAGE( PackageHandleStandardArgs ) + +SET (OPENCL_VERSION_STRING "0.1.0") +SET (OPENCL_VERSION_MAJOR 0) +SET (OPENCL_VERSION_MINOR 1) +SET (OPENCL_VERSION_PATCH 0) + +IF (APPLE) + + FIND_LIBRARY(OPENCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX") + FIND_PATH(OPENCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX") + FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX") + +ELSE (APPLE) + + IF (WIN32) + + FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h) + FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp) + + # The AMD SDK currently installs both x86 and x86_64 libraries + # This is only a hack to find out architecture + IF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) + SET(OPENCL_LIB_DIR "$ENV{AMDAPPSDKROOT}/lib/x86_64") + SET(OPENCL_LIB_DIR "$ENV{AMDAPPSDKROOT}/lib/x86_64") + ELSE (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") + SET(OPENCL_LIB_DIR "$ENV{AMDAPPSDKROOT}/lib/x86") + SET(OPENCL_LIB_DIR "$ENV{AMDAPPSDKROOT}/lib/x86") + ENDIF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) + + # find out if the user asked for a 64-bit build, and use the corresponding + # 64 or 32 bit NVIDIA library paths to the search: + STRING(REGEX MATCH "Win64" ISWIN64 ${CMAKE_GENERATOR}) + IF("${ISWIN64}" STREQUAL "Win64") + FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR} $ENV{CUDA_LIB_PATH} $ENV{CUDA_PATH}/lib/x64) + ELSE("${ISWIN64}" STREQUAL "Win64") + FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR} $ENV{CUDA_LIB_PATH} $ENV{CUDA_PATH}/lib/Win32) + ENDIF("${ISWIN64}" STREQUAL "Win64") + + GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) + + # On Win32 search relative to the library + FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS "${_OPENCL_INC_CAND}" $ENV{CUDA_INC_PATH} $ENV{CUDA_PATH}/include) + FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "${_OPENCL_INC_CAND}" $ENV{CUDA_INC_PATH} $ENV{CUDA_PATH}/include) + + ELSE (WIN32) + + # Unix style platforms + FIND_LIBRARY(OPENCL_LIBRARIES OpenCL + ENV LD_LIBRARY_PATH + ) + + GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH) + GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) + + # The AMD SDK currently does not place its headers + # in /usr/include, therefore also search relative + # to the library + FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include") + FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include") + + ENDIF (WIN32) + +ENDIF (APPLE) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS( OpenCL DEFAULT_MSG OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS ) + +IF( _OPENCL_CPP_INCLUDE_DIRS ) + SET( OPENCL_HAS_CPP_BINDINGS TRUE ) + LIST( APPEND OPENCL_INCLUDE_DIRS ${_OPENCL_CPP_INCLUDE_DIRS} ) + # This is often the same, so clean up + LIST( REMOVE_DUPLICATES OPENCL_INCLUDE_DIRS ) +ENDIF( _OPENCL_CPP_INCLUDE_DIRS ) + +MARK_AS_ADVANCED( + OPENCL_INCLUDE_DIRS +) diff --git a/cmake/Modules/FindViennaCL.cmake b/cmake/Modules/FindViennaCL.cmake new file mode 100644 index 00000000000..d9aa4b91b3f --- /dev/null +++ b/cmake/Modules/FindViennaCL.cmake @@ -0,0 +1,43 @@ +SET(ViennaCL_WITH_OPENCL TRUE) + +SET(VIENNACL_INCLUDE_SEARCH_PATHS + .. + /usr/include + /usr/local/include + /opt/ViennaCL/include + $ENV{VIENNACL_HOME} + $ENV{VIENNACL_HOME}/include +) + +FIND_PATH(ViennaCL_INCLUDE_DIR NAMES viennacl/forwards.h PATHS ${VIENNACL_INCLUDE_SEARCH_PATHS}) + +SET(ViennaCL_FOUND ON) + +# Check include files +IF(NOT ViennaCL_INCLUDE_DIR) + SET(ViennaCL_FOUND OFF) + MESSAGE(STATUS "Could not find ViennaCL include. Turning ViennaCL_FOUND off") +ENDIF() + +IF (ViennaCL_FOUND) + IF (NOT ViennaCL_FIND_QUIETLY) + MESSAGE(STATUS "Found ViennaCL include: ${ViennaCL_INCLUDE_DIR}") + ENDIF (NOT ViennaCL_FIND_QUIETLY) +ELSE (ViennaCL_FOUND) + IF (ViennaCL_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find ViennaCL") + ENDIF (ViennaCL_FIND_REQUIRED) +ENDIF (ViennaCL_FOUND) + +IF(ViennaCL_WITH_OPENCL) + find_package(OpenCL REQUIRED) +ENDIF(ViennaCL_WITH_OPENCL) + +set(ViennaCL_INCLUDE_DIRS ${ViennaCL_INCLUDE_DIR} ${OPENCL_INCLUDE_DIRS}) +set(ViennaCL_LIBRARIES ${OPENCL_LIBRARIES}) + +MARK_AS_ADVANCED( + ViennaCL_INCLUDE_DIR + ViennaCL_INCLUDE_DIRS + ViennaCL_LIBRARIES +) diff --git a/cmake/Modules/FindclBLAS.cmake b/cmake/Modules/FindclBLAS.cmake new file mode 100644 index 00000000000..b9766fb6854 --- /dev/null +++ b/cmake/Modules/FindclBLAS.cmake @@ -0,0 +1,53 @@ +SET(CLBLAS_INCLUDE_SEARCH_PATHS + /usr/include + /usr/local/include + /opt/clBLAS/include + $ENV{CLBLAS_HOME} + $ENV{CLBLAS_HOME}/include +) + +SET(CLBLAS_LIB_SEARCH_PATHS + /lib/ + /lib64/ + /usr/lib + /usr/lib64 + /usr/local/lib + /usr/local/lib64 + /opt/clBLAS/lib + $ENV{CLBLAS_HOME} + $ENV{CLBLAS_HOME}/lib + ) + +FIND_PATH(CLBLAS_INCLUDE_DIR NAMES clBLAS.h PATHS ${CLBLAS_INCLUDE_SEARCH_PATHS}) +FIND_LIBRARY(CLBLAS_LIBRARY NAMES clBLAS PATHS ${CLBLAS_LIB_SEARCH_PATHS}) + +SET(CLBLAS_FOUND ON) + +# Check include files +IF(NOT CLBLAS_INCLUDE_DIR) + SET(CLBLAS_FOUND OFF) + MESSAGE(STATUS "Could not find CLBLAS include. Turning CLBLAS_FOUND off") +ENDIF() + +# Check libraries +IF(NOT CLBLAS_LIBRARY) + SET(CLBLAS_FOUND OFF) + MESSAGE(STATUS "Could not find CLBLAS lib. Turning CLBLAS_FOUND off") +ENDIF() + +IF (CLBLAS_FOUND) + IF (NOT CLBLAS_FIND_QUIETLY) + MESSAGE(STATUS "Found CLBLAS libraries: ${CLBLAS_LIBRARY}") + MESSAGE(STATUS "Found CLBLAS include: ${CLBLAS_INCLUDE_DIR}") + ENDIF (NOT CLBLAS_FIND_QUIETLY) +ELSE (CLBLAS_FOUND) + IF (CLBLAS_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find CLBLAS") + ENDIF (CLBLAS_FIND_REQUIRED) +ENDIF (CLBLAS_FOUND) + +MARK_AS_ADVANCED( + CLBLAS_INCLUDE_DIR + CLBLAS_LIBRARY +) + diff --git a/cmake/Targets.cmake b/cmake/Targets.cmake index 2401f252e93..25fa76b852e 100644 --- a/cmake/Targets.cmake +++ b/cmake/Targets.cmake @@ -54,12 +54,14 @@ function(caffe_pickup_caffe_sources root) caffe_source_group("Include" GLOB "${root}/include/caffe/*.h*") caffe_source_group("Include\\Util" GLOB "${root}/include/caffe/util/*.h*") caffe_source_group("Include" GLOB "${PROJECT_BINARY_DIR}/caffe_config.h*") + caffe_source_group("Include" GLOB "${root}/include/caffe/greentea/*.hpp") caffe_source_group("Source" GLOB "${root}/src/caffe/*.cpp") caffe_source_group("Source\\Util" GLOB "${root}/src/caffe/util/*.cpp") caffe_source_group("Source\\Layers" GLOB "${root}/src/caffe/layers/*.cpp") caffe_source_group("Source\\Cuda" GLOB "${root}/src/caffe/layers/*.cu") caffe_source_group("Source\\Cuda" GLOB "${root}/src/caffe/util/*.cu") caffe_source_group("Source\\Proto" GLOB "${root}/src/caffe/proto/*.proto") + caffe_source_group("Source" GLOB "${root}/src/caffe/greentea*.cpp") # source groups for test target caffe_source_group("Include" GLOB "${root}/include/caffe/test/test_*.h*") @@ -87,6 +89,16 @@ function(caffe_pickup_caffe_sources root) file(GLOB_RECURSE proto_files ${root}/src/caffe/*.proto) list(APPEND srcs ${proto_files}) + # OpenCL but not CUDA backend tweak + if(USE_GREENTEA AND NOT USE_CUDA) + SET_SOURCE_FILES_PROPERTIES(${cuda} PROPERTIES LANGUAGE CXX) + SET_SOURCE_FILES_PROPERTIES(${cuda} PROPERTIES COMPILE_FLAGS "-x c++") + SET_SOURCE_FILES_PROPERTIES(${test_cuda} PROPERTIES LANGUAGE CXX) + SET_SOURCE_FILES_PROPERTIES(${test_cuda} PROPERTIES COMPILE_FLAGS "-x c++") + list(APPEND srcs ${cuda}) + list(APPEND test_srcs ${test_cuda}) + endif() + # convet to absolute paths caffe_convert_absolute_paths(srcs) caffe_convert_absolute_paths(cuda) diff --git a/cmake/Templates/caffe_config.h.in b/cmake/Templates/caffe_config.h.in index 8a31b43cabf..fe695345a76 100644 --- a/cmake/Templates/caffe_config.h.in +++ b/cmake/Templates/caffe_config.h.in @@ -1,32 +1,40 @@ +#ifndef CAFFE_CONFIG_HPP_ +#define CAFFE_CONFIG_HPP_ + /* Sources directory */ #define SOURCE_FOLDER "${PROJECT_SOURCE_DIR}" /* Binaries directory */ #define BINARY_FOLDER "${PROJECT_BINARY_DIR}" +/* 64 bit indexing */ +#cmakedefine USE_INDEX_64 + /* NVIDA Cuda */ #cmakedefine HAVE_CUDA +#cmakedefine USE_CUDA + +/* OpenCl kernels */ +#cmakedefine USE_GREENTEA +#cmakedefine VIENNACL_WITH_OPENCL + +/* clBLAS */ +#cmakedefine HAVE_CLBLAS +#cmakedefine USE_CLBLAS /* NVIDA cuDNN */ #cmakedefine HAVE_CUDNN #cmakedefine USE_CUDNN -/* NVIDA cuDNN */ +/* Disable CUDA and OpenCL */ #cmakedefine CPU_ONLY /* Test device */ #define CUDA_TEST_DEVICE ${CUDA_TEST_DEVICE} -/* Temporary (TODO: remove) */ -#if 1 - #define CMAKE_SOURCE_DIR SOURCE_FOLDER "/src/" - #define EXAMPLES_SOURCE_DIR BINARY_FOLDER "/examples/" - #define CMAKE_EXT ".gen.cmake" -#else - #define CMAKE_SOURCE_DIR "src/" - #define EXAMPLES_SOURCE_DIR "examples/" - #define CMAKE_EXT "" -#endif +#define CMAKE_SOURCE_DIR "src/" +#define EXAMPLES_SOURCE_DIR "examples/" +#define CMAKE_EXT "" /* Matlab */ #cmakedefine HAVE_MATLAB @@ -36,3 +44,5 @@ #cmakedefine USE_LEVELDB #cmakedefine USE_LMDB #cmakedefine ALLOW_LMDB_NOLOCK + +#endif // CAFFE_CONFIG_HPP_ diff --git a/docs/tutorial/solver.md b/docs/tutorial/solver.md index b719f715a4b..b150f6487bc 100644 --- a/docs/tutorial/solver.md +++ b/docs/tutorial/solver.md @@ -8,12 +8,12 @@ The responsibilities of learning are divided between the Solver for overseeing t The Caffe solvers are: -- Stochastic Gradient Descent (`type: "SGD"`), -- AdaDelta (`type: "AdaDelta"`), -- Adaptive Gradient (`type: "AdaGrad"`), -- Adam (`type: "Adam"`), -- Nesterov's Accelerated Gradient (`type: "Nesterov"`) and -- RMSprop (`type: "RMSProp"`) +- Stochastic Gradient Descent (`SGD`), +- AdaDelta (`ADADELTA`), +- Adaptive Gradient (`ADAGRAD`), +- Adam (`ADAM`), +- Nesterov's Accelerated Gradient (`NESTEROV`) and +- RMSprop (`RMSPROP`) The solver @@ -51,7 +51,7 @@ The parameter update $$\Delta W$$ is formed by the solver from the error gradien ### SGD -**Stochastic gradient descent** (`type: "SGD"`) updates the weights $$ W $$ by a linear combination of the negative gradient $$ \nabla L(W) $$ and the previous weight update $$ V_t $$. +**Stochastic gradient descent** (`solver_type: SGD`) updates the weights $$ W $$ by a linear combination of the negative gradient $$ \nabla L(W) $$ and the previous weight update $$ V_t $$. The **learning rate** $$ \alpha $$ is the weight of the negative gradient. The **momentum** $$ \mu $$ is the weight of the previous update. @@ -113,7 +113,7 @@ If learning diverges (e.g., you start to see very large or `NaN` or `inf` loss v ### AdaDelta -The **AdaDelta** (`type: "AdaDelta"`) method (M. Zeiler [1]) is a "robust learning rate method". It is a gradient-based optimization method (like SGD). The update formulas are +The **AdaDelta** (`solver_type: ADADELTA`) method (M. Zeiler [1]) is a "robust learning rate method". It is a gradient-based optimization method (like SGD). The update formulas are $$ \begin{align} @@ -125,7 +125,7 @@ E[g^2]_t &= \delta{E[g^2]_{t-1} } + (1-\delta)g_{t}^2 \end{align} $$ -and +and $$ (W_{t+1})_i = @@ -139,7 +139,7 @@ $$ ### AdaGrad -The **adaptive gradient** (`type: "AdaGrad"`) method (Duchi et al. [1]) is a gradient-based optimization method (like SGD) that attempts to "find needles in haystacks in the form of very predictive but rarely seen features," in Duchi et al.'s words. +The **adaptive gradient** (`solver_type: ADAGRAD`) method (Duchi et al. [1]) is a gradient-based optimization method (like SGD) that attempts to "find needles in haystacks in the form of very predictive but rarely seen features," in Duchi et al.'s words. Given the update information from all previous iterations $$ \left( \nabla L(W) \right)_{t'} $$ for $$ t' \in \{1, 2, ..., t\} $$, the update formulas proposed by [1] are as follows, specified for each component $$i$$ of the weights $$W$$: @@ -159,7 +159,7 @@ Note that in practice, for weights $$ W \in \mathcal{R}^d $$, AdaGrad implementa ### Adam -The **Adam** (`type: "Adam"`), proposed in Kingma et al. [1], is a gradient-based optimization method (like SGD). This includes an "adaptive moment estimation" ($$m_t, v_t$$) and can be regarded as a generalization of AdaGrad. The update formulas are +The **Adam** (`solver_type: ADAM`), proposed in Kingma et al. [1], is a gradient-based optimization method (like SGD). This includes an "adaptive moment estimation" ($$m_t, v_t$$) and can be regarded as a generalization of AdaGrad. The update formulas are $$ (m_t)_i = \beta_1 (m_{t-1})_i + (1-\beta_1)(\nabla L(W_t))_i,\\ @@ -181,7 +181,7 @@ Kingma et al. [1] proposed to use $$\beta_1 = 0.9, \beta_2 = 0.999, \varepsilon ### NAG -**Nesterov's accelerated gradient** (`type: "Nesterov"`) was proposed by Nesterov [1] as an "optimal" method of convex optimization, achieving a convergence rate of $$ \mathcal{O}(1/t^2) $$ rather than the $$ \mathcal{O}(1/t) $$. +**Nesterov's accelerated gradient** (`solver_type: NESTEROV`) was proposed by Nesterov [1] as an "optimal" method of convex optimization, achieving a convergence rate of $$ \mathcal{O}(1/t^2) $$ rather than the $$ \mathcal{O}(1/t) $$. Though the required assumptions to achieve the $$ \mathcal{O}(1/t^2) $$ convergence typically will not hold for deep networks trained with Caffe (e.g., due to non-smoothness and non-convexity), in practice NAG can be a very effective method for optimizing certain types of deep learning architectures, as demonstrated for deep MNIST autoencoders by Sutskever et al. [2]. The weight update formulas look very similar to the SGD updates given above: @@ -206,10 +206,10 @@ What distinguishes the method from SGD is the weight setting $$ W $$ on which we ### RMSprop -The **RMSprop** (`type: "RMSProp"`), suggested by Tieleman in a Coursera course lecture, is a gradient-based optimization method (like SGD). The update formulas are +The **RMSprop** (`solver_type: RMSPROP`), suggested by Tieleman in a Coursera course lecture, is a gradient-based optimization method (like SGD). The update formulas are $$ -(v_t)_i = +(v_t)_i = \begin{cases} (v_{t-1})_i + \delta, &(\nabla L(W_t))_i(\nabla L(W_{t-1}))_i > 0\\ (v_{t-1})_i \cdot (1-\delta), & \text{else} diff --git a/examples/cifar10/convert_cifar_data.cpp b/examples/cifar10/convert_cifar_data.cpp index e1b89f42fb6..5e47a0d6747 100644 --- a/examples/cifar10/convert_cifar_data.cpp +++ b/examples/cifar10/convert_cifar_data.cpp @@ -23,12 +23,12 @@ using boost::scoped_ptr; using std::string; namespace db = caffe::db; -const int kCIFARSize = 32; -const int kCIFARImageNBytes = 3072; -const int kCIFARBatchSize = 10000; -const int kCIFARTrainBatches = 5; +const int_tp kCIFARSize = 32; +const int_tp kCIFARImageNBytes = 3072; +const int_tp kCIFARBatchSize = 10000; +const int_tp kCIFARTrainBatches = 5; -void read_image(std::ifstream* file, int* label, char* buffer) { +void read_image(std::ifstream* file, int_tp* label, char* buffer) { char label_char; file->read(&label_char, 1); *label = label_char; @@ -42,7 +42,7 @@ void convert_dataset(const string& input_folder, const string& output_folder, train_db->Open(output_folder + "/cifar10_train_" + db_type, db::NEW); scoped_ptr txn(train_db->NewTransaction()); // Data buffer - int label; + int_tp label; char str_buffer[kCIFARImageNBytes]; Datum datum; datum.set_channels(3); @@ -50,7 +50,7 @@ void convert_dataset(const string& input_folder, const string& output_folder, datum.set_width(kCIFARSize); LOG(INFO) << "Writing Training data"; - for (int fileid = 0; fileid < kCIFARTrainBatches; ++fileid) { + for (int_tp fileid = 0; fileid < kCIFARTrainBatches; ++fileid) { // Open files LOG(INFO) << "Training Batch " << fileid + 1; string batchFileName = input_folder + "/data_batch_" @@ -58,7 +58,7 @@ void convert_dataset(const string& input_folder, const string& output_folder, std::ifstream data_file(batchFileName.c_str(), std::ios::in | std::ios::binary); CHECK(data_file) << "Unable to open train file #" << fileid + 1; - for (int itemid = 0; itemid < kCIFARBatchSize; ++itemid) { + for (int_tp itemid = 0; itemid < kCIFARBatchSize; ++itemid) { read_image(&data_file, &label, str_buffer); datum.set_label(label); datum.set_data(str_buffer, kCIFARImageNBytes); @@ -78,7 +78,7 @@ void convert_dataset(const string& input_folder, const string& output_folder, std::ifstream data_file((input_folder + "/test_batch.bin").c_str(), std::ios::in | std::ios::binary); CHECK(data_file) << "Unable to open test file."; - for (int itemid = 0; itemid < kCIFARBatchSize; ++itemid) { + for (int_tp itemid = 0; itemid < kCIFARBatchSize; ++itemid) { read_image(&data_file, &label, str_buffer); datum.set_label(label); datum.set_data(str_buffer, kCIFARImageNBytes); diff --git a/examples/cpp_classification/classification.cpp b/examples/cpp_classification/classification.cpp index 974662e59da..19a6b885e65 100644 --- a/examples/cpp_classification/classification.cpp +++ b/examples/cpp_classification/classification.cpp @@ -25,7 +25,7 @@ class Classifier { const string& mean_file, const string& label_file); - std::vector Classify(const cv::Mat& img, int N = 5); + std::vector Classify(const cv::Mat& img, int_tp N = 5); private: void SetMean(const string& mean_file); @@ -40,7 +40,7 @@ class Classifier { private: shared_ptr > net_; cv::Size input_geometry_; - int num_channels_; + int_tp num_channels_; cv::Mat mean_; std::vector labels_; }; @@ -56,7 +56,7 @@ Classifier::Classifier(const string& model_file, #endif /* Load the network. */ - net_.reset(new Net(model_file, TEST)); + net_.reset(new Net(model_file, TEST, Caffe::GetDefaultDevice())); net_->CopyTrainedLayersFrom(trained_file); CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input."; @@ -83,33 +83,33 @@ Classifier::Classifier(const string& model_file, << "Number of labels is different from the output layer dimension."; } -static bool PairCompare(const std::pair& lhs, - const std::pair& rhs) { +static bool PairCompare(const std::pair& lhs, + const std::pair& rhs) { return lhs.first > rhs.first; } /* Return the indices of the top N values of vector v. */ -static std::vector Argmax(const std::vector& v, int N) { - std::vector > pairs; - for (size_t i = 0; i < v.size(); ++i) +static std::vector Argmax(const std::vector& v, int_tp N) { + std::vector > pairs; + for (uint_tp i = 0; i < v.size(); ++i) pairs.push_back(std::make_pair(v[i], i)); std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare); - std::vector result; - for (int i = 0; i < N; ++i) + std::vector result; + for (int_tp i = 0; i < N; ++i) result.push_back(pairs[i].second); return result; } /* Return the top N predictions. */ -std::vector Classifier::Classify(const cv::Mat& img, int N) { +std::vector Classifier::Classify(const cv::Mat& img, int_tp N) { std::vector output = Predict(img); - N = std::min(labels_.size(), N); - std::vector maxN = Argmax(output, N); + N = std::min(labels_.size(), N); + std::vector maxN = Argmax(output, N); std::vector predictions; - for (int i = 0; i < N; ++i) { - int idx = maxN[i]; + for (int_tp i = 0; i < N; ++i) { + int_tp idx = maxN[i]; predictions.push_back(std::make_pair(labels_[idx], output[idx])); } @@ -130,7 +130,7 @@ void Classifier::SetMean(const string& mean_file) { /* The format of the mean file is planar 32-bit float BGR or grayscale. */ std::vector channels; float* data = mean_blob.mutable_cpu_data(); - for (int i = 0; i < num_channels_; ++i) { + for (int_tp i = 0; i < num_channels_; ++i) { /* Extract an individual channel. */ cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data); channels.push_back(channel); @@ -176,10 +176,10 @@ std::vector Classifier::Predict(const cv::Mat& img) { void Classifier::WrapInputLayer(std::vector* input_channels) { Blob* input_layer = net_->input_blobs()[0]; - int width = input_layer->width(); - int height = input_layer->height(); + int_tp width = input_layer->width(); + int_tp height = input_layer->height(); float* input_data = input_layer->mutable_cpu_data(); - for (int i = 0; i < input_layer->channels(); ++i) { + for (int_tp i = 0; i < input_layer->channels(); ++i) { cv::Mat channel(height, width, CV_32FC1, input_data); input_channels->push_back(channel); input_data += width * height; @@ -252,14 +252,14 @@ int main(int argc, char** argv) { std::vector predictions = classifier.Classify(img); /* Print the top N predictions. */ - for (size_t i = 0; i < predictions.size(); ++i) { + for (uint_tp i = 0; i < predictions.size(); ++i) { Prediction p = predictions[i]; std::cout << std::fixed << std::setprecision(4) << p.second << " - \"" << p.first << "\"" << std::endl; } } #else -int main(int argc, char** argv) { +int_tp main(int_tp argc, char** argv) { LOG(FATAL) << "This example requires OpenCV; compile with USE_OPENCV."; } #endif // USE_OPENCV diff --git a/examples/mnist/convert_mnist_data.cpp b/examples/mnist/convert_mnist_data.cpp index 16d28093dd5..a42bd9951fa 100644 --- a/examples/mnist/convert_mnist_data.cpp +++ b/examples/mnist/convert_mnist_data.cpp @@ -22,6 +22,7 @@ #include // NOLINT(readability/streams) #include +#include "caffe/definitions.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/util/format.hpp" @@ -108,7 +109,7 @@ void convert_dataset(const char* image_filename, const char* label_filename, // Storing to db char label; char* pixels = new char[rows * cols]; - int count = 0; + int_tp count = 0; string value; Datum datum; @@ -117,7 +118,7 @@ void convert_dataset(const char* image_filename, const char* label_filename, datum.set_width(cols); LOG(INFO) << "A total of " << num_items << " items."; LOG(INFO) << "Rows: " << rows << " Cols: " << cols; - for (int item_id = 0; item_id < num_items; ++item_id) { + for (int_tp item_id = 0; item_id < num_items; ++item_id) { image_file.read(pixels, rows * cols); label_file.read(&label, 1); datum.set_data(pixels, rows*cols); diff --git a/examples/mnist/lenet_adadelta_solver.prototxt b/examples/mnist/lenet_adadelta_solver.prototxt index 16176c0ffae..776d1e06139 100644 --- a/examples/mnist/lenet_adadelta_solver.prototxt +++ b/examples/mnist/lenet_adadelta_solver.prototxt @@ -20,5 +20,5 @@ snapshot: 5000 snapshot_prefix: "examples/mnist/lenet_adadelta" # solver mode: CPU or GPU solver_mode: GPU -type: "AdaDelta" +solver_type: ADADELTA delta: 1e-6 diff --git a/examples/mnist/lenet_solver_adam.prototxt b/examples/mnist/lenet_solver_adam.prototxt index 4b5336b1a04..d22c5718f3f 100644 --- a/examples/mnist/lenet_solver_adam.prototxt +++ b/examples/mnist/lenet_solver_adam.prototxt @@ -22,5 +22,5 @@ max_iter: 10000 snapshot: 5000 snapshot_prefix: "examples/mnist/lenet" # solver mode: CPU or GPU -type: "Adam" +solver_type: ADAM solver_mode: GPU diff --git a/examples/mnist/lenet_solver_rmsprop.prototxt b/examples/mnist/lenet_solver_rmsprop.prototxt index 924b72d306e..74dadc51069 100644 --- a/examples/mnist/lenet_solver_rmsprop.prototxt +++ b/examples/mnist/lenet_solver_rmsprop.prototxt @@ -23,5 +23,5 @@ snapshot: 5000 snapshot_prefix: "examples/mnist/lenet_rmsprop" # solver mode: CPU or GPU solver_mode: GPU -type: "RMSProp" +solver_type: RMSPROP rms_decay: 0.98 diff --git a/examples/mnist/mnist_autoencoder_solver_adadelta.prototxt b/examples/mnist/mnist_autoencoder_solver_adadelta.prototxt index 26c4084a374..065647df31b 100644 --- a/examples/mnist/mnist_autoencoder_solver_adadelta.prototxt +++ b/examples/mnist/mnist_autoencoder_solver_adadelta.prototxt @@ -16,4 +16,4 @@ snapshot: 10000 snapshot_prefix: "examples/mnist/mnist_autoencoder_adadelta_train" # solver mode: CPU or GPU solver_mode: GPU -type: "AdaDelta" +solver_type: ADADELTA diff --git a/examples/mnist/mnist_autoencoder_solver_adagrad.prototxt b/examples/mnist/mnist_autoencoder_solver_adagrad.prototxt index 065cdb20ddc..cc0ed9e310a 100644 --- a/examples/mnist/mnist_autoencoder_solver_adagrad.prototxt +++ b/examples/mnist/mnist_autoencoder_solver_adagrad.prototxt @@ -14,4 +14,4 @@ snapshot: 10000 snapshot_prefix: "examples/mnist/mnist_autoencoder_adagrad_train" # solver mode: CPU or GPU solver_mode: GPU -type: "AdaGrad" +solver_type: ADAGRAD diff --git a/examples/mnist/mnist_autoencoder_solver_nesterov.prototxt b/examples/mnist/mnist_autoencoder_solver_nesterov.prototxt index c95e3fe7e49..2a59fd45c8d 100644 --- a/examples/mnist/mnist_autoencoder_solver_nesterov.prototxt +++ b/examples/mnist/mnist_autoencoder_solver_nesterov.prototxt @@ -17,4 +17,4 @@ snapshot_prefix: "examples/mnist/mnist_autoencoder_nesterov_train" momentum: 0.95 # solver mode: CPU or GPU solver_mode: GPU -type: "Nesterov" +solver_type: NESTEROV diff --git a/examples/siamese/convert_mnist_siamese_data.cpp b/examples/siamese/convert_mnist_siamese_data.cpp index 928b3fbf4d5..705c6daae03 100644 --- a/examples/siamese/convert_mnist_siamese_data.cpp +++ b/examples/siamese/convert_mnist_siamese_data.cpp @@ -77,16 +77,15 @@ void convert_dataset(const char* image_filename, const char* label_filename, char label_j; char* pixels = new char[2 * rows * cols]; std::string value; - caffe::Datum datum; datum.set_channels(2); // one channel for each image in the pair datum.set_height(rows); datum.set_width(cols); LOG(INFO) << "A total of " << num_items << " items."; LOG(INFO) << "Rows: " << rows << " Cols: " << cols; - for (int itemid = 0; itemid < num_items; ++itemid) { - int i = caffe::caffe_rng_rand() % num_items; // pick a random pair - int j = caffe::caffe_rng_rand() % num_items; + for (int_tp itemid = 0; itemid < num_items; ++itemid) { + int_tp i = caffe::caffe_rng_rand() % num_items; // pick a random pair + int_tp j = caffe::caffe_rng_rand() % num_items; read_image(&image_file, &label_file, i, rows, cols, pixels, &label_i); read_image(&image_file, &label_file, j, rows, cols, @@ -123,7 +122,7 @@ int main(int argc, char** argv) { return 0; } #else -int main(int argc, char** argv) { +int_tp main(int_tp argc, char** argv) { LOG(FATAL) << "This example requires LevelDB; compile with USE_LEVELDB."; } #endif // USE_LEVELDB diff --git a/include/caffe/blob.hpp b/include/caffe/blob.hpp index af360ac24bd..b623ed4e338 100644 --- a/include/caffe/blob.hpp +++ b/include/caffe/blob.hpp @@ -6,13 +6,24 @@ #include #include "caffe/common.hpp" +#include "caffe/definitions.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/syncedmem.hpp" -const int kMaxBlobAxes = 32; +#ifdef USE_CUDA +#include "caffe/util/math_functions.hpp" +#endif + +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + +const int_tp kMaxBlobAxes = 32; namespace caffe { +class device; + /** * @brief A wrapper around SyncedMemory holders serving as the basic * computational unit through which Layer%s, Net%s, and Solver%s @@ -20,20 +31,29 @@ namespace caffe { * * TODO(dox): more thorough description. */ -template +template class Blob { public: Blob() - : data_(), diff_(), count_(0), capacity_(0) {} - - /// @brief Deprecated; use Blob(const vector& shape). - explicit Blob(const int num, const int channels, const int height, - const int width); - explicit Blob(const vector& shape); + : data_(), + diff_(), + count_(0), + capacity_(0), + device_(Caffe::GetDefaultDevice()) { + } + explicit Blob(device *device_context) + : data_(), + diff_(), + count_(0), + capacity_(0), + device_(device_context) { + } + explicit Blob(const int_tp num, const int_tp channels, const int_tp height, + const int_tp width, device *device_context = + Caffe::GetDefaultDevice()); + explicit Blob(const vector& shape, device *device_context = + Caffe::GetDefaultDevice()); - /// @brief Deprecated; use Reshape(const vector& shape). - void Reshape(const int num, const int channels, const int height, - const int width); /** * @brief Change the dimensions of the blob, allocating new memory if * necessary. @@ -47,19 +67,25 @@ class Blob { * Note that reshaping an input blob and immediately calling Net::Backward is * an error; either Net::Forward or Net::Reshape need to be called to * propagate the new input shape to higher layers. + * + * Reshape returns true if new memory was allocated. */ - void Reshape(const vector& shape); - void Reshape(const BlobShape& shape); - void ReshapeLike(const Blob& other); + bool Reshape(const vector& shape); + bool Reshape(const BlobShape& shape); + bool Reshape(const int_tp num, const int_tp channels, const int_tp height, + const int_tp width); + bool ReshapeLike(const Blob& other); inline string shape_string() const { ostringstream stream; - for (int i = 0; i < shape_.size(); ++i) { + for (int_tp i = 0; i < shape_.size(); ++i) { stream << shape_[i] << " "; } stream << "(" << count_ << ")"; return stream.str(); } - inline const vector& shape() const { return shape_; } + inline const vector& shape() const { + return shape_; + } /** * @brief Returns the dimension of the index-th axis (or the negative index-th * axis from the end, if index is negative). @@ -68,11 +94,15 @@ class Blob { * "canonicalized" using CanonicalAxisIndex. * Dies on out of range index. */ - inline int shape(int index) const { + inline int_tp shape(int_tp index) const { return shape_[CanonicalAxisIndex(index)]; } - inline int num_axes() const { return shape_.size(); } - inline int count() const { return count_; } + inline int_tp num_axes() const { + return shape_.size(); + } + inline int_tp count() const { + return count_; + } /** * @brief Compute the volume of a slice; i.e., the product of dimensions @@ -82,14 +112,14 @@ class Blob { * * @param end_axis The first axis to exclude from the slice. */ - inline int count(int start_axis, int end_axis) const { + inline int_tp count(int_tp start_axis, int_tp end_axis) const { CHECK_LE(start_axis, end_axis); CHECK_GE(start_axis, 0); CHECK_GE(end_axis, 0); CHECK_LE(start_axis, num_axes()); CHECK_LE(end_axis, num_axes()); - int count = 1; - for (int i = start_axis; i < end_axis; ++i) { + int_tp count = 1; + for (int_tp i = start_axis; i < end_axis; ++i) { count *= shape(i); } return count; @@ -100,7 +130,7 @@ class Blob { * * @param start_axis The first axis to include in the slice. */ - inline int count(int start_axis) const { + inline int_tp count(int_tp start_axis) const { return count(start_axis, num_axes()); } @@ -115,13 +145,14 @@ class Blob { * the second to last if index == -2, etc. * Dies on out of range index. */ - inline int CanonicalAxisIndex(int axis_index) const { + inline int_tp CanonicalAxisIndex(int_tp axis_index) const { CHECK_GE(axis_index, -num_axes()) - << "axis " << axis_index << " out of range for " << num_axes() - << "-D Blob with shape " << shape_string(); + <<"axis " << axis_index + << " out of range for " << num_axes() + << "-D Blob with shape " << shape_string(); CHECK_LT(axis_index, num_axes()) - << "axis " << axis_index << " out of range for " << num_axes() - << "-D Blob with shape " << shape_string(); + << "axis " << axis_index << " out of range for " << num_axes() + << "-D Blob with shape " << shape_string(); if (axis_index < 0) { return axis_index + num_axes(); } @@ -129,16 +160,16 @@ class Blob { } /// @brief Deprecated legacy shape accessor num: use shape(0) instead. - inline int num() const { return LegacyShape(0); } + inline int_tp num() const {return LegacyShape(0);} /// @brief Deprecated legacy shape accessor channels: use shape(1) instead. - inline int channels() const { return LegacyShape(1); } + inline int_tp channels() const {return LegacyShape(1);} /// @brief Deprecated legacy shape accessor height: use shape(2) instead. - inline int height() const { return LegacyShape(2); } + inline int_tp height() const {return LegacyShape(2);} /// @brief Deprecated legacy shape accessor width: use shape(3) instead. - inline int width() const { return LegacyShape(3); } - inline int LegacyShape(int index) const { + inline int_tp width() const {return LegacyShape(3);} + inline int_tp LegacyShape(int_tp index) const { CHECK_LE(num_axes(), 4) - << "Cannot use legacy accessors on Blobs with > 4 axes."; + << "Cannot use legacy accessors on Blobs with > 4 axes."; CHECK_LT(index, 4); CHECK_GE(index, -4); if (index >= num_axes() || index < -num_axes()) { @@ -149,9 +180,8 @@ class Blob { } return shape(index); } - - inline int offset(const int n, const int c = 0, const int h = 0, - const int w = 0) const { + inline int_tp offset(const int_tp n, const int_tp c = 0, const int_tp h = 0, + const int_tp w = 0) const { CHECK_GE(n, 0); CHECK_LE(n, num()); CHECK_GE(channels(), 0); @@ -163,10 +193,10 @@ class Blob { return ((n * channels() + c) * height() + h) * width() + w; } - inline int offset(const vector& indices) const { + inline int_tp offset(const vector& indices) const { CHECK_LE(indices.size(), num_axes()); - int offset = 0; - for (int i = 0; i < num_axes(); ++i) { + int_tp offset = 0; + for (int_tp i = 0; i < num_axes(); ++i) { offset *= shape(i); if (indices.size() > i) { CHECK_GE(indices[i], 0); @@ -188,21 +218,21 @@ class Blob { void CopyFrom(const Blob& source, bool copy_diff = false, bool reshape = false); - inline Dtype data_at(const int n, const int c, const int h, - const int w) const { + inline Dtype data_at(const int_tp n, const int_tp c, const int_tp h, + const int_tp w) const { return cpu_data()[offset(n, c, h, w)]; } - inline Dtype diff_at(const int n, const int c, const int h, - const int w) const { + inline Dtype diff_at(const int_tp n, const int_tp c, const int_tp h, + const int_tp w) const { return cpu_diff()[offset(n, c, h, w)]; } - inline Dtype data_at(const vector& index) const { + inline Dtype data_at(const vector& index) const { return cpu_data()[offset(index)]; } - inline Dtype diff_at(const vector& index) const { + inline Dtype diff_at(const vector& index) const { return cpu_diff()[offset(index)]; } @@ -218,7 +248,7 @@ class Blob { const Dtype* cpu_data() const; void set_cpu_data(Dtype* data); - const int* gpu_shape() const; + const int_tp* gpu_shape() const; const Dtype* gpu_data() const; const Dtype* cpu_diff() const; const Dtype* gpu_diff() const; @@ -246,7 +276,7 @@ class Blob { /** * @brief Set the data_ shared_ptr to point to the SyncedMemory holding the - * data_ of Blob other -- useful in Layer%s which simply perform a copy + * data_ of Blob other -- useful in Layer&s which simply perform a copy * in their Forward pass. * * This deallocates the SyncedMemory holding this Blob's data_, as @@ -255,7 +285,7 @@ class Blob { void ShareData(const Blob& other); /** * @brief Set the diff_ shared_ptr to point to the SyncedMemory holding the - * diff_ of Blob other -- useful in Layer%s which simply perform a copy + * diff_ of Blob other -- useful in Layer&s which simply perform a copy * in their Forward pass. * * This deallocates the SyncedMemory holding this Blob's diff_, as @@ -265,16 +295,23 @@ class Blob { bool ShapeEquals(const BlobProto& other); + /** + * @brief Return the device context to which this blob and shared memory belongs + */ + device *get_device(); + protected: shared_ptr data_; shared_ptr diff_; shared_ptr shape_data_; - vector shape_; - int count_; - int capacity_; + vector shape_; + uint_tp count_; + uint_tp capacity_; + device *device_; DISABLE_COPY_AND_ASSIGN(Blob); -}; // class Blob +}; +// class Blob } // namespace caffe diff --git a/include/caffe/caffe.hpp b/include/caffe/caffe.hpp index 06882096c55..63f554b1856 100644 --- a/include/caffe/caffe.hpp +++ b/include/caffe/caffe.hpp @@ -6,7 +6,10 @@ #include "caffe/blob.hpp" #include "caffe/common.hpp" +#include "caffe/definitions.hpp" +#include "caffe/device.hpp" #include "caffe/filler.hpp" +#include "caffe/greentea/greentea.hpp" #include "caffe/layer.hpp" #include "caffe/layer_factory.hpp" #include "caffe/net.hpp" @@ -18,4 +21,6 @@ #include "caffe/util/io.hpp" #include "caffe/util/upgrade_proto.hpp" + + #endif // CAFFE_CAFFE_HPP_ diff --git a/include/caffe/common.hpp b/include/caffe/common.hpp index 6b902a42e2d..0d67735a3f1 100644 --- a/include/caffe/common.hpp +++ b/include/caffe/common.hpp @@ -1,10 +1,15 @@ #ifndef CAFFE_COMMON_HPP_ #define CAFFE_COMMON_HPP_ +#ifdef CMAKE_BUILD + #include "caffe_config.h" +#endif + #include #include #include +#include #include #include #include // NOLINT(readability/streams) @@ -16,6 +21,8 @@ #include // pair #include +#include "caffe/definitions.hpp" +#include "caffe/greentea/greentea.hpp" #include "caffe/util/device_alternate.hpp" // Convert macro to string @@ -70,10 +77,12 @@ private:\ #define NOT_IMPLEMENTED LOG(FATAL) << "Not Implemented Yet" // See PR #1236 -namespace cv { class Mat; } +namespace cv {class Mat;} namespace caffe { +class device; + // We will use the boost shared_ptr instead of the new C++11 one mainly // because cuda does not work (at least now) well with C++11 features. using boost::shared_ptr; @@ -101,6 +110,8 @@ void GlobalInit(int* pargc, char*** pargv); // caffe is going to use for cublas, curand, etc. class Caffe { public: + Caffe(); + Caffe(const Caffe &obj); ~Caffe(); // Thread local context for Caffe. Moved to common.cpp instead of @@ -115,7 +126,7 @@ class Caffe { class RNG { public: RNG(); - explicit RNG(unsigned int seed); + explicit RNG(size_t); explicit RNG(const RNG&); RNG& operator=(const RNG&); void* generator(); @@ -132,11 +143,16 @@ class Caffe { return *(Get().random_generator_); } #ifndef CPU_ONLY +#ifdef USE_CUDA inline static cublasHandle_t cublas_handle() { return Get().cublas_handle_; } inline static curandGenerator_t curand_generator() { return Get().curand_generator_; } -#endif + inline static curandGenerator_t curand_generator64() { + return Get().curand_generator64_; + } +#endif // USE_CUDA +#endif // !CPU_ONLY // Returns the mode: running on CPU or GPU. inline static Brew mode() { return Get().mode_; } @@ -147,10 +163,14 @@ class Caffe { // it personally but better to note it here in the header file. inline static void set_mode(Brew mode) { Get().mode_ = mode; } // Sets the random seed of both boost and curand - static void set_random_seed(const unsigned int seed); + static void set_random_seed(const size_t seed, device* device_context); // Sets the device. Since we have cublas and curand stuff, set device also // requires us to reset those values. static void SetDevice(const int device_id); + // Switch the current device + static void SelectDevice(device* device_context); + static void SelectDevice(int id, bool listId); + // Prints the current GPU status. static void DeviceQuery(); // Parallel training info @@ -159,22 +179,40 @@ class Caffe { inline static bool root_solver() { return Get().root_solver_; } inline static void set_root_solver(bool val) { Get().root_solver_ = val; } + // Get the default device + static device *GetDefaultDevice(); + static device *GetCPUDevice(); + + // Prints info about all devices + static int EnumerateDevices(bool silent = false); + // Prepares contexts for devices to use + static void SetDevices(std::vector device_ids); + // Finish executing gpu kernels on the specified-device. + static void Synchronize(int device_id); + + // Get a device context + static device *GetDevice(int id, bool listId); + protected: #ifndef CPU_ONLY +#ifdef USE_CUDA cublasHandle_t cublas_handle_; curandGenerator_t curand_generator_; -#endif + curandGenerator_t curand_generator64_; +#endif // USE_CUDA +#endif // !CPU_ONLY shared_ptr random_generator_; Brew mode_; - int solver_count_; - bool root_solver_; - private: - // The private constructor to avoid duplicate instantiation. - Caffe(); + // The shared ptrs are being referenced on every thread, + // while the default device will be handled thread local + static vector > devices_; + shared_ptr cpu_device_; + device* default_device_; - DISABLE_COPY_AND_ASSIGN(Caffe); + int solver_count_; + bool root_solver_; }; } // namespace caffe diff --git a/include/caffe/cuda/cuda_dev_ptr.hpp b/include/caffe/cuda/cuda_dev_ptr.hpp new file mode 100644 index 00000000000..7c1ad7eeed1 --- /dev/null +++ b/include/caffe/cuda/cuda_dev_ptr.hpp @@ -0,0 +1,25 @@ +#ifndef CAFFE_CUDA_DEV_PTR_HPP_ +#define CAFFE_CUDA_DEV_PTR_HPP_ + +#include "caffe/dev_ptr.hpp" + +#ifdef USE_CUDA + +namespace caffe { + +template class cuda_dev_ptr : public dev_ptr { + public: + explicit cuda_dev_ptr(Type* ptr); + + void* get(); + int_tp off(); + + private: + Type* raw_ptr_; +}; + +} // namespace caffe + +#endif // USE_CUDA + +#endif /* CAFFE_CUDA_DEV_PTR_HPP_ */ diff --git a/include/caffe/data_reader.hpp b/include/caffe/data_reader.hpp index 8ed5542cb8d..aa20c48a48a 100644 --- a/include/caffe/data_reader.hpp +++ b/include/caffe/data_reader.hpp @@ -36,7 +36,7 @@ class DataReader { // Queue pairs are shared between a body and its readers class QueuePair { public: - explicit QueuePair(int size); + explicit QueuePair(int_tp size); ~QueuePair(); BlockingQueue free_; @@ -48,7 +48,7 @@ class DataReader { // A single body is created per source class Body : public InternalThread { public: - explicit Body(const LayerParameter& param); + explicit Body(const LayerParameter& param, device* device_context); virtual ~Body(); protected: @@ -71,6 +71,7 @@ class DataReader { const shared_ptr queue_pair_; shared_ptr body_; + device* device_; static map > bodies_; diff --git a/include/caffe/data_transformer.hpp b/include/caffe/data_transformer.hpp index 97b4ee6a8c4..47a64fd53e8 100644 --- a/include/caffe/data_transformer.hpp +++ b/include/caffe/data_transformer.hpp @@ -13,11 +13,13 @@ namespace caffe { * @brief Applies common transformations to the input data, such as * scaling, mirroring, substracting the image mean... */ -template +template class DataTransformer { public: - explicit DataTransformer(const TransformationParameter& param, Phase phase); - virtual ~DataTransformer() {} + explicit DataTransformer(const TransformationParameter& param, Phase phase, + device *device_context); + virtual ~DataTransformer() { + } /** * @brief Initialize the Random number generations if needed by the @@ -48,7 +50,7 @@ class DataTransformer { * set_cpu_data() is used. See memory_layer.cpp for an example. */ void Transform(const vector & datum_vector, - Blob* transformed_blob); + Blob* transformed_blob); #ifdef USE_OPENCV /** @@ -62,7 +64,7 @@ class DataTransformer { * set_cpu_data() is used. See memory_layer.cpp for an example. */ void Transform(const vector & mat_vector, - Blob* transformed_blob); + Blob* transformed_blob); /** * @brief Applies the transformation defined in the data layer's @@ -97,7 +99,7 @@ class DataTransformer { * @param datum * Datum containing the data to be transformed. */ - vector InferBlobShape(const Datum& datum); + vector InferBlobShape(const Datum& datum); /** * @brief Infers the shape of transformed_blob will have when * the transformation is applied to the data. @@ -106,7 +108,7 @@ class DataTransformer { * @param datum_vector * A vector of Datum containing the data to be transformed. */ - vector InferBlobShape(const vector & datum_vector); + vector InferBlobShape(const vector & datum_vector); /** * @brief Infers the shape of transformed_blob will have when * the transformation is applied to the data. @@ -116,7 +118,7 @@ class DataTransformer { * A vector of Mat containing the data to be transformed. */ #ifdef USE_OPENCV - vector InferBlobShape(const vector & mat_vector); + vector InferBlobShape(const vector & mat_vector); /** * @brief Infers the shape of transformed_blob will have when * the transformation is applied to the data. @@ -124,11 +126,11 @@ class DataTransformer { * @param cv_img * cv::Mat containing the data to be transformed. */ - vector InferBlobShape(const cv::Mat& cv_img); + vector InferBlobShape(const cv::Mat& cv_img); #endif // USE_OPENCV protected: - /** + /** * @brief Generates a random integer from Uniform({0, 1, ..., n-1}). * * @param n @@ -136,17 +138,17 @@ class DataTransformer { * @return * A uniformly random integer value from ({0, 1, ..., n-1}). */ - virtual int Rand(int n); + virtual int_tp Rand(int_tp n); void Transform(const Datum& datum, Dtype* transformed_data); // Tranformation parameters TransformationParameter param_; - shared_ptr rng_; Phase phase_; Blob data_mean_; vector mean_values_; + device *device_; }; } // namespace caffe diff --git a/include/caffe/definitions.hpp b/include/caffe/definitions.hpp new file mode 100644 index 00000000000..2c88042fd66 --- /dev/null +++ b/include/caffe/definitions.hpp @@ -0,0 +1,25 @@ +#ifndef CAFFE_DEFINITIONS_HPP_ +#define CAFFE_DEFINITIONS_HPP_ + +#include + + +#ifdef USE_INDEX_64 +// Types used for parameters, offset computations and so on +#define int_tp int64_t +#define uint_tp uint64_t + +// Definitions used to cast the types above as needed +#define int_tpc long long // NOLINT +#define uint_tpc unsigned long long // NOLINT +#else +// Types used for parameters, offset computations and so on +#define int_tp int32_t +#define uint_tp uint32_t + +// Definitions used to cast the types above as needed +#define int_tpc int // NOLINT +#define uint_tpc unsigned int // NOLINT +#endif + +#endif /* CAFFE_DEFINITIONS_HPP_ */ diff --git a/include/caffe/dev_ptr.hpp b/include/caffe/dev_ptr.hpp new file mode 100644 index 00000000000..db83797d0eb --- /dev/null +++ b/include/caffe/dev_ptr.hpp @@ -0,0 +1,34 @@ +#ifndef CAFFE_DEVPTR_HPP_ +#define CAFFE_DEVPTR_HPP_ + +#include +#include "caffe/definitions.hpp" + +namespace caffe { + +/* + * dev_ptr class should be constructed similarly to shared_ptr of Boost. + * (but excluding the smart pointer features, so memory management + * is explicit, and only support types (float, void, double, char, int_tp, ...)) + * It should be possible to use this object just like pointers, + * independently of the backend and device used. + * Dereferencing (although inefficient on some backends) should also + * be supported. + * */ +template class dev_ptr { + public: + virtual Type* get() = 0; + virtual std::size_t off() = 0; + + // Comparators + virtual inline bool operator==(dev_ptr const &other) = 0; + virtual inline bool operator!=(dev_ptr const &other) = 0; + virtual inline bool operator>(dev_ptr const &other) = 0; + virtual inline bool operator<(dev_ptr const &other) = 0; + virtual inline bool operator<=(dev_ptr const &other) = 0; + virtual inline bool operator>=(dev_ptr const &other) = 0; +}; + +} // namespace caffe + +#endif /* CAFFE_DEVPTR_HPP_ */ diff --git a/include/caffe/device.hpp b/include/caffe/device.hpp new file mode 100644 index 00000000000..2eae27b891a --- /dev/null +++ b/include/caffe/device.hpp @@ -0,0 +1,72 @@ +/* + * device_context.hpp + * + * Created on: Jun 26, 2015 + * Author: Fabian Tschopp + */ + +#ifndef CAFFE_device_HPP_ +#define CAFFE_device_HPP_ + +#ifdef CMAKE_BUILD +#include "caffe_config.h" +#endif + +#include +#include +#include +#include "caffe/blob.hpp" +#include "caffe/greentea/greentea.hpp" + +using std::vector; + +namespace caffe { + +class device { + public: + explicit device(); + explicit device(int id, int list_id, Backend backend); + Backend backend() const; + int id() const; + int list_id() const; + int current_queue_id(); + int WorkgroupSize(int id); + +#ifdef USE_GREENTEA + viennacl::ocl::program &program(); + void SetProgram(); +#endif // USE_GREENTEA + + template + shared_ptr > Buffer(int id); + + int num_queues(); + void SwitchQueue(int id); + void FinishQueues(); + + void Init(); + + uint_tp memory_usage(); + uint_tp peak_memory_usage(); + void IncreaseMemoryUsage(uint_tp bytes); + void DecreaseMemoryUsage(uint_tp bytes); + void ResetPeakMemoryUsage(); + bool CheckCapability(std::string cap); + + private: + int current_queue_id_; + std::vector workgroup_sizes_; + int id_; + int list_id_; + Backend backend_; + uint_tp memory_usage_; + uint_tp peak_memory_usage_; + std::vector > > buff_f_; + std::vector > > buff_d_; +#ifdef USE_GREENTEA + viennacl::ocl::program ocl_program_; +#endif // USE_GREENTEA +}; +} // namespace caffe + +#endif /* CAFFE_device_HPP_ */ diff --git a/include/caffe/filler.hpp b/include/caffe/filler.hpp index dad9ad46b3b..ae575120736 100644 --- a/include/caffe/filler.hpp +++ b/include/caffe/filler.hpp @@ -15,63 +15,71 @@ namespace caffe { /// @brief Fills a Blob with constant or randomly-generated data. -template +template class Filler { public: - explicit Filler(const FillerParameter& param) : filler_param_(param) {} - virtual ~Filler() {} + explicit Filler(const FillerParameter& param) + : filler_param_(param) { + } + virtual ~Filler() { + } virtual void Fill(Blob* blob) = 0; protected: FillerParameter filler_param_; -}; // class Filler - +}; +// class Filler /// @brief Fills a Blob with constant values @f$ x = 0 @f$. -template +template class ConstantFiller : public Filler { public: explicit ConstantFiller(const FillerParameter& param) - : Filler(param) {} + : Filler(param) { + } virtual void Fill(Blob* blob) { Dtype* data = blob->mutable_cpu_data(); - const int count = blob->count(); + const int_tp count = blob->count(); const Dtype value = this->filler_param_.value(); CHECK(count); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { data[i] = value; } CHECK_EQ(this->filler_param_.sparse(), -1) - << "Sparsity not supported by this Filler."; + << "Sparsity not supported by this Filler."; } }; /// @brief Fills a Blob with uniformly distributed values @f$ x\sim U(a, b) @f$. -template +template class UniformFiller : public Filler { public: explicit UniformFiller(const FillerParameter& param) - : Filler(param) {} + : Filler(param) { + } virtual void Fill(Blob* blob) { CHECK(blob->count()); caffe_rng_uniform(blob->count(), Dtype(this->filler_param_.min()), - Dtype(this->filler_param_.max()), blob->mutable_cpu_data()); + Dtype(this->filler_param_.max()), + blob->mutable_cpu_data()); CHECK_EQ(this->filler_param_.sparse(), -1) - << "Sparsity not supported by this Filler."; + << "Sparsity not supported by this Filler."; } }; /// @brief Fills a Blob with Gaussian-distributed values @f$ x = a @f$. -template +template class GaussianFiller : public Filler { public: explicit GaussianFiller(const FillerParameter& param) - : Filler(param) {} + : Filler(param) { + } virtual void Fill(Blob* blob) { Dtype* data = blob->mutable_cpu_data(); CHECK(blob->count()); caffe_rng_gaussian(blob->count(), Dtype(this->filler_param_.mean()), - Dtype(this->filler_param_.std()), blob->mutable_cpu_data()); - int sparse = this->filler_param_.sparse(); + Dtype(this->filler_param_.std()), + blob->mutable_cpu_data()); + int_tp sparse = this->filler_param_.sparse(); CHECK_GE(sparse, -1); if (sparse >= 0) { // Sparse initialization is implemented for "weight" blobs; i.e. matrices. @@ -79,12 +87,14 @@ class GaussianFiller : public Filler { // number of outputs. The 'sparse' variable specifies the mean number // of non-zero input weights for a given output. CHECK_GE(blob->num_axes(), 1); - const int num_outputs = blob->shape(0); + const int_tp num_outputs = blob->shape(0); Dtype non_zero_probability = Dtype(sparse) / Dtype(num_outputs); - rand_vec_.reset(new SyncedMemory(blob->count() * sizeof(int))); - int* mask = reinterpret_cast(rand_vec_->mutable_cpu_data()); + rand_vec_.reset( + new SyncedMemory(blob->count() * sizeof(int_tp), + blob->get_device())); + int_tp* mask = reinterpret_cast(rand_vec_->mutable_cpu_data()); caffe_rng_bernoulli(blob->count(), non_zero_probability, mask); - for (int i = 0; i < blob->count(); ++i) { + for (int_tp i = 0; i < blob->count(); ++i) { data[i] *= mask[i]; } } @@ -97,30 +107,31 @@ class GaussianFiller : public Filler { /** @brief Fills a Blob with values @f$ x \in [0, 1] @f$ * such that @f$ \forall i \sum_j x_{ij} = 1 @f$. */ -template +template class PositiveUnitballFiller : public Filler { public: explicit PositiveUnitballFiller(const FillerParameter& param) - : Filler(param) {} + : Filler(param) { + } virtual void Fill(Blob* blob) { Dtype* data = blob->mutable_cpu_data(); DCHECK(blob->count()); caffe_rng_uniform(blob->count(), 0, 1, blob->mutable_cpu_data()); // We expect the filler to not be called very frequently, so we will // just use a simple implementation - int dim = blob->count() / blob->num(); + int_tp dim = blob->count() / blob->num(); CHECK(dim); - for (int i = 0; i < blob->num(); ++i) { + for (int_tp i = 0; i < blob->num(); ++i) { Dtype sum = 0; - for (int j = 0; j < dim; ++j) { + for (int_tp j = 0; j < dim; ++j) { sum += data[i * dim + j]; } - for (int j = 0; j < dim; ++j) { + for (int_tp j = 0; j < dim; ++j) { data[i * dim + j] /= sum; } } CHECK_EQ(this->filler_param_.sparse(), -1) - << "Sparsity not supported by this Filler."; + << "Sparsity not supported by this Filler."; } }; @@ -140,31 +151,33 @@ class PositiveUnitballFiller : public Filler { * * TODO(dox): make notation in above comment consistent with rest & use LaTeX. */ -template +template class XavierFiller : public Filler { public: explicit XavierFiller(const FillerParameter& param) - : Filler(param) {} + : Filler(param) { + } virtual void Fill(Blob* blob) { CHECK(blob->count()); - int fan_in = blob->count() / blob->num(); - int fan_out = blob->count() / blob->channels(); + int_tp fan_in = blob->count() / blob->num(); + int_tp fan_out = blob->count() / blob->channels(); Dtype n = fan_in; // default to fan_in - if (this->filler_param_.variance_norm() == - FillerParameter_VarianceNorm_AVERAGE) { + if (this->filler_param_.variance_norm() + == FillerParameter_VarianceNorm_AVERAGE) { n = (fan_in + fan_out) / Dtype(2); - } else if (this->filler_param_.variance_norm() == - FillerParameter_VarianceNorm_FAN_OUT) { + } else if (this->filler_param_.variance_norm() + == FillerParameter_VarianceNorm_FAN_OUT) { n = fan_out; } Dtype scale = sqrt(Dtype(3) / n); caffe_rng_uniform(blob->count(), -scale, scale, - blob->mutable_cpu_data()); + blob->mutable_cpu_data()); CHECK_EQ(this->filler_param_.sparse(), -1) - << "Sparsity not supported by this Filler."; + << "Sparsity not supported by this Filler."; } }; + /** * @brief Fills a Blob with values @f$ x \sim N(0, \sigma^2) @f$ where * @f$ \sigma^2 @f$ is set inversely proportional to number of incoming @@ -182,28 +195,29 @@ class XavierFiller : public Filler { * a, b, c) where a * b * c = fan_in and num * b * c = fan_out. Note that this * is currently not the case for inner product layers. */ -template +template class MSRAFiller : public Filler { public: explicit MSRAFiller(const FillerParameter& param) - : Filler(param) {} + : Filler(param) { + } virtual void Fill(Blob* blob) { CHECK(blob->count()); - int fan_in = blob->count() / blob->num(); - int fan_out = blob->count() / blob->channels(); + int_tp fan_in = blob->count() / blob->num(); + int_tp fan_out = blob->count() / blob->channels(); Dtype n = fan_in; // default to fan_in - if (this->filler_param_.variance_norm() == - FillerParameter_VarianceNorm_AVERAGE) { + if (this->filler_param_.variance_norm() + == FillerParameter_VarianceNorm_AVERAGE) { n = (fan_in + fan_out) / Dtype(2); - } else if (this->filler_param_.variance_norm() == - FillerParameter_VarianceNorm_FAN_OUT) { + } else if (this->filler_param_.variance_norm() + == FillerParameter_VarianceNorm_FAN_OUT) { n = fan_out; } Dtype std = sqrt(Dtype(2) / n); caffe_rng_gaussian(blob->count(), Dtype(0), std, - blob->mutable_cpu_data()); + blob->mutable_cpu_data()); CHECK_EQ(this->filler_param_.sparse(), -1) - << "Sparsity not supported by this Filler."; + << "Sparsity not supported by this Filler."; } }; @@ -249,9 +263,9 @@ class BilinearFiller : public Filler { CHECK_EQ(blob->num_axes(), 4) << "Blob must be 4 dim."; CHECK_EQ(blob->width(), blob->height()) << "Filter must be square"; Dtype* data = blob->mutable_cpu_data(); - int f = ceil(blob->width() / 2.); + int_tp f = ceil(blob->width() / 2.); float c = (2 * f - 1 - f % 2) / (2. * f); - for (int i = 0; i < blob->count(); ++i) { + for (int_tp i = 0; i < blob->count(); ++i) { float x = i % blob->width(); float y = (i / blob->width()) % blob->height(); data[i] = (1 - fabs(x / f - c)) * (1 - fabs(y / f - c)); @@ -267,7 +281,7 @@ class BilinearFiller : public Filler { * Ideally this would be replaced by a factory pattern, but we will leave it * this way for now. */ -template +template Filler* GetFiller(const FillerParameter& param) { const std::string& type = param.type(); if (type == "constant") { @@ -280,14 +294,14 @@ Filler* GetFiller(const FillerParameter& param) { return new UniformFiller(param); } else if (type == "xavier") { return new XavierFiller(param); - } else if (type == "msra") { - return new MSRAFiller(param); } else if (type == "bilinear") { return new BilinearFiller(param); + } else if (type == "msra") { + return new MSRAFiller(param); } else { CHECK(false) << "Unknown filler name: " << param.type(); } - return (Filler*)(NULL); + return (Filler*) (NULL); } } // namespace caffe diff --git a/include/caffe/greentea/cl_kernels.hpp b/include/caffe/greentea/cl_kernels.hpp new file mode 100644 index 00000000000..0b7cf3c4891 --- /dev/null +++ b/include/caffe/greentea/cl_kernels.hpp @@ -0,0 +1,16 @@ +// AUTOMATICALLY GENERATED FILE, DO NOT EDIT +#include "caffe/common.hpp" +#ifdef USE_GREENTEA +#ifndef GREENTEA_CL_KERNELS_HPP_ +#define GREENTEA_CL_KERNELS_HPP_ +#include "caffe/greentea/greentea.hpp" +#include "viennacl/backend/opencl.hpp" +#include "viennacl/ocl/backend.hpp" +#include "viennacl/ocl/context.hpp" +#include "viennacl/ocl/device.hpp" +#include "viennacl/ocl/platform.hpp" +namespace caffe { +viennacl::ocl::program & RegisterKernels(viennacl::ocl::context *ctx); +} +#endif +#endif diff --git a/include/caffe/greentea/greentea.hpp b/include/caffe/greentea/greentea.hpp new file mode 100644 index 00000000000..75efb91f0fd --- /dev/null +++ b/include/caffe/greentea/greentea.hpp @@ -0,0 +1,87 @@ +/* + * greentea.hpp + * + * Created on: Apr 5, 2015 + * Author: Fabian Tschopp + */ + +#ifndef CAFFE_GREENTEA_HPP_ +#define CAFFE_GREENTEA_HPP_ + +#ifdef CMAKE_BUILD + #include "caffe_config.h" +#endif + +#include + +// Define ViennaCL/GreenTea flags +#ifdef USE_GREENTEA +#ifndef NDEBUG +#define NDEBUG +#endif + +#ifndef VIENNACL_WITH_OPENCL +#define VIENNACL_WITH_OPENCL +#endif + +#ifndef __APPLE__ +#include "CL/cl.h" +#else +#include "OpenCL/cl.h" +#endif + +#include "viennacl/backend/opencl.hpp" +#include "viennacl/ocl/backend.hpp" +#include "viennacl/ocl/context.hpp" +#include "viennacl/ocl/device.hpp" +#include "viennacl/ocl/platform.hpp" +#include "viennacl/vector.hpp" +#endif + +#ifndef GREENTEA_QUEUE_COUNT +#define GREENTEA_QUEUE_COUNT 1 +#endif + +namespace caffe { + +#ifdef USE_GREENTEA +viennacl::ocl::handle WrapHandle(cl_mem in, + viennacl::ocl::context *ctx); +#endif + +enum Backend { + BACKEND_CUDA, + BACKEND_OpenCL, + BACKEND_CPU +}; + + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same { + static const bool value = true; +}; + +#ifdef USE_GREENTEA + +#ifdef USE_CLBLAS +#define GREENTEA_CL_BLAS_CHECK(condition) \ + {clblasStatus status = condition; \ + CHECK_EQ(status, clblasSuccess) << "GreenTea CL BLAS ERROR";} +#endif + +// Macro to select the single (_float) or double (_double) precision kernel +#define CL_KERNEL_SELECT(kernel) \ + is_same::value ? \ + kernel "_float" : \ + kernel "_double" + +#endif + +} // namespace caffe + +#endif /* CAFFE_GREENTEA_HPP_ */ diff --git a/include/caffe/greentea/greentea_im2col.hpp b/include/caffe/greentea/greentea_im2col.hpp new file mode 100644 index 00000000000..694cdbc256e --- /dev/null +++ b/include/caffe/greentea/greentea_im2col.hpp @@ -0,0 +1,64 @@ +#ifndef GREENTEA_IM2COL_HPP_ +#define GREENTEA_IM2COL_HPP_ +#ifdef USE_GREENTEA + +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#include "viennacl/ocl/backend.hpp" +#include "viennacl/ocl/context.hpp" +#include "viennacl/ocl/device.hpp" +#include "viennacl/ocl/platform.hpp" +#include "viennacl/vector.hpp" + +namespace caffe { + +template +void greentea_im2col_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, const cl_mem data_im, + const int_tp data_offset, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + cl_mem data_col, const int_tp data_col_off); + +template +void greentea_col2im_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, const cl_mem data_col, + const int_tp data_col_off, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp patch_h, const int_tp patch_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + cl_mem data_im, const int_tp data_im_off); + +template +void greentea_im2col_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, cl_mem data_im, + const int_tp data_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, + const int_tp num_kernels, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, cl_mem stride, + cl_mem dilation, cl_mem data_col, + const int_tp data_col_off); + +template +void greentea_col2im_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, cl_mem data_col, + const int_tp data_col_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, + const int_tp im_size, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, cl_mem stride, + cl_mem dilation, cl_mem data_im, + int_tp data_im_off); + +} // namespace caffe + +#endif // USE_GREENTEA +#endif /* GREENTEA_IM2COL_HPP_ */ diff --git a/include/caffe/greentea/greentea_math_functions.hpp b/include/caffe/greentea/greentea_math_functions.hpp new file mode 100644 index 00000000000..3cfcf90777d --- /dev/null +++ b/include/caffe/greentea/greentea_math_functions.hpp @@ -0,0 +1,163 @@ +/* + * greentea_math_functions.hpp + * + * Created on: Apr 6, 2015 + * Author: fabian + */ + +#ifndef GREENTEA_MATH_FUNCTIONS_HPP_ +#define GREENTEA_MATH_FUNCTIONS_HPP_ + +#include "caffe/common.hpp" +#include "caffe/definitions.hpp" + +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/util/math_functions.hpp" +#include "viennacl/ocl/backend.hpp" +#include "viennacl/ocl/context.hpp" +#include "viennacl/ocl/device.hpp" +#include "viennacl/ocl/platform.hpp" +#include "viennacl/vector.hpp" + +namespace caffe { + +void greentea_memset(const int_tp ctx_id, const uint_tp N, const int_tp alpha, + cl_mem X, const int_tp offX); + +void greentea_gpu_memcpy(const uint_tp N, const cl_mem X, const int_tp offX, + void *Y, viennacl::ocl::context *ctx); + +void greentea_gpu_memcpy(const uint_tp N, const void* X, cl_mem Y, + const int_tp offY, viennacl::ocl::context *ctx); + +void greentea_gpu_memcpy(const uint_tp N, const cl_mem X, const int_tp offX, + cl_mem Y, const int_tp offY, + viennacl::ocl::context *ctx); + +template +void greentea_copy(const int_tp N, const cl_mem X, const int_tp offX, cl_mem Y, + const int_tp offY, viennacl::ocl::context *ctx); + +template +void greentea_copy(const int_tp N, const cl_mem X, const int_tp offX, Dtype* Y, + viennacl::ocl::context *ctx); + +template +void greentea_copy(const int_tp N, const Dtype* X, cl_mem Y, const int_tp offY, + viennacl::ocl::context *ctx); + +template +void greentea_gpu_gemm(const int_tp ctx_id, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const int_tp M, + const int_tp N, const int_tp K, const Dtype alpha, + const cl_mem A, const int_tp offA, const cl_mem B, + const int_tp offB, const Dtype beta, cl_mem C, + const int_tp offC); + +template +void greentea_gpu_gemv(const int_tp ctx_id, const CBLAS_TRANSPOSE TransA, + const int_tp M, const int_tp N, const Dtype alpha, + const cl_mem A, const int_tp offA, const cl_mem x, + const int_tp offx, const Dtype beta, cl_mem y, + const int_tp offy); + +template +void greentea_gpu_axpy(const int_tp ctx_id, const int_tp N, const Dtype alpha, + const cl_mem x, const int_tp offx, cl_mem y, + const int_tp offy); + +template +void greentea_gpu_mul(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_scal(const int_tp ctx_id, const int_tp N, const Dtype alpha, + cl_mem x, int_tp offx); + +template +void greentea_gpu_axpby(const int_tp ctx_id, const int_tp N, const Dtype alpha, + const cl_mem X, const int_tp offX, const Dtype beta, + cl_mem Y, const int_tp offY); + +template +void greentea_gpu_dot(const int_tp ctx_id, const int_tp n, const cl_mem X, + const int_tp offX, const cl_mem Y, const int_tp offY, + Dtype* out); + +template +void greentea_gpu_asum(const int_tp ctx_id, const int_tp n, const cl_mem X, + const int_tp offX, Dtype* Y); + +template +void greentea_gpu_scale(const int_tp ctx_id, const int_tp n, const Dtype alpha, + const cl_mem X, const int_tp offX, cl_mem Y, + const int_tp offY); + +template +void greentea_gpu_set(const int_tp ctx_id, const int_tp N, const Dtype alpha, + cl_mem Y, const int_tp offY); + +template +void greentea_gpu_add_scalar(const int_tp ctx_id, const int_tp N, + const Dtype alpha, cl_mem Y, const int_tp offY); + +template +void greentea_gpu_add(const int_tp ctx_id, const int_tp n, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_sub(const int_tp ctx_id, const int_tp n, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_div(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_abs(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, cl_mem y, const int_tp offy); + +template +void greentea_gpu_exp(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, cl_mem y, const int_tp offy); + +template +void greentea_gpu_powx(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, const Dtype alpha, cl_mem y, + const int_tp offy); + +template +void greentea_gpu_log(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, cl_mem y, const int_tp offy); + +template +void greentea_gpu_sign(const int_tp ctx_id, const int_tp n, const cl_mem x, + int_tp offx, cl_mem y, const int_tp offy); + +template +void greentea_gpu_sgnbit(const int_tp ctx_id, const int_tp n, const cl_mem x, +int_tp offx, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_rng_uniform(const int_tp ctx_id, const int_tp n, + const Dtype a, const Dtype b, cl_mem r, + const int_tp offr); + +void greentea_gpu_rng_uniform(const int_tp ctx_id, const int_tp n, cl_mem r, +int_tp offr); + +template +void greentea_gpu_rng_gaussian(const int_tp ctx_id, const int_tp n, + const Dtype mu, const Dtype sigma, cl_mem r, + const int_tp offr); + +} // namespace caffe + +#endif // USE GREENTEA +#endif /* GREENTEA_MATH_FUNCTIONS_HPP_ */ diff --git a/include/caffe/internal_thread.hpp b/include/caffe/internal_thread.hpp index 6a8c5a02892..533150a5d65 100644 --- a/include/caffe/internal_thread.hpp +++ b/include/caffe/internal_thread.hpp @@ -2,12 +2,15 @@ #define CAFFE_INTERNAL_THREAD_HPP_ #include "caffe/common.hpp" +#include "device.hpp" /** Forward declare boost::thread instead of including boost/thread.hpp to avoid a boost/NVCC issues (#1009, #1010) on OSX. */ -namespace boost { class thread; } +namespace boost { +class thread; +} namespace caffe { @@ -18,7 +21,9 @@ namespace caffe { */ class InternalThread { public: - InternalThread() : thread_() {} + InternalThread() + : thread_() { + } virtual ~InternalThread(); /** @@ -26,7 +31,7 @@ class InternalThread { * thread values, e.g. device id, solver index etc. The random seed * is initialized using caffe_rng_rand. */ - void StartInternalThread(); + void StartInternalThread(device* device_context); /** Will not return until the internal thread has exited. */ void StopInternalThread(); @@ -35,15 +40,18 @@ class InternalThread { protected: /* Implement this method in your subclass - with the code you want your thread to run. */ - virtual void InternalThreadEntry() {} + with the code you want your thread to run. */ + virtual void InternalThreadEntry() { + } /* Should be tested when running loops to exit when requested. */ bool must_stop(); + device* thread_device_; + private: - void entry(int device, Caffe::Brew mode, int rand_seed, int solver_count, - bool root_solver); + void entry(device* device_context, Caffe::Brew mode, int_tp rand_seed, + int_tp solver_count, bool root_solver); shared_ptr thread_; }; diff --git a/include/caffe/layer.hpp b/include/caffe/layer.hpp index 10f353f94f9..f1fb7cef177 100644 --- a/include/caffe/layer.hpp +++ b/include/caffe/layer.hpp @@ -7,29 +7,34 @@ #include "caffe/blob.hpp" #include "caffe/common.hpp" +#include "caffe/definitions.hpp" #include "caffe/layer_factory.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/util/math_functions.hpp" +#include "caffe/greentea/greentea.hpp" +#include "device.hpp" + /** Forward declare boost::thread instead of including boost/thread.hpp to avoid a boost/NVCC issues (#1009, #1010) on OSX. */ namespace boost { class mutex; } + namespace caffe { /** * @brief An interface for the units of computation which can be composed into a * Net. * - * Layer%s must implement a Forward function, in which they take their input - * (bottom) Blob%s (if any) and compute their output Blob%s (if any). + * Layer&s must implement a Forward function, in which they take their input + * (bottom) Blob&s (if any) and compute their output Blob&s (if any). * They may also implement a Backward function, in which they compute the error - * gradients with respect to their input Blob%s, given the error gradients with - * their output Blob%s. + * gradients with respect to their input Blob&s, given the error gradients with + * their output Blob&s. */ -template +template class Layer { public: /** @@ -38,18 +43,21 @@ class Layer { * layer. */ explicit Layer(const LayerParameter& param) - : layer_param_(param), is_shared_(false) { - // Set phase and copy blobs (if there are any). - phase_ = param.phase(); - if (layer_param_.blobs_size() > 0) { - blobs_.resize(layer_param_.blobs_size()); - for (int i = 0; i < layer_param_.blobs_size(); ++i) { - blobs_[i].reset(new Blob()); - blobs_[i]->FromProto(layer_param_.blobs(i)); - } + : layer_param_(param), is_shared_(false) { + device_ = Caffe::GetDevice(layer_param_.device(), true); + // Set phase and copy blobs (if there are any). + phase_ = param.phase(); + if (layer_param_.blobs_size() > 0) { + blobs_.resize(layer_param_.blobs_size()); + for (int_tp i = 0; i < layer_param_.blobs_size(); ++i) { + blobs_[i].reset(new Blob(device_)); + blobs_[i]->FromProto(layer_param_.blobs(i)); } } - virtual ~Layer() {} + } + + virtual ~Layer() { + } /** * @brief Implements common layer setup functionality. @@ -65,7 +73,7 @@ class Layer { * This method may not be overridden. */ void SetUp(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { InitMutex(); CheckBlobCounts(bottom, top); LayerSetUp(bottom, top); @@ -90,7 +98,8 @@ class Layer { * adjust the top blob sizes. */ virtual void LayerSetUp(const vector*>& bottom, - const vector*>& top) {} + const vector*>& top) { + } /** * @brief Whether a layer should be shared by multiple nets during data @@ -129,7 +138,7 @@ class Layer { * accommodate the bottom blobs. */ virtual void Reshape(const vector*>& bottom, - const vector*>& top) = 0; + const vector*>& top) = 0; /** * @brief Given the bottom blobs, compute the top blobs and the loss. @@ -149,7 +158,7 @@ class Layer { * Your layer should implement Forward_cpu and (optionally) Forward_gpu. */ inline Dtype Forward(const vector*>& bottom, - const vector*>& top); + const vector*>& top); /** * @brief Given the top blob error gradients, compute the bottom blob error @@ -173,8 +182,8 @@ class Layer { * Your layer should implement Backward_cpu and (optionally) Backward_gpu. */ inline void Backward(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom); + const vector& propagate_down, + const vector*>& bottom); /** * @brief Returns the vector of learnable parameter blobs. @@ -186,7 +195,9 @@ class Layer { /** * @brief Returns the layer parameter. */ - const LayerParameter& layer_param() const { return layer_param_; } + const LayerParameter& layer_param() const { + return layer_param_; + } /** * @brief Writes the layer parameter to a protocol buffer @@ -196,14 +207,14 @@ class Layer { /** * @brief Returns the scalar loss associated with a top blob at a given index. */ - inline Dtype loss(const int top_index) const { + inline Dtype loss(const int_tp top_index) const { return (loss_.size() > top_index) ? loss_[top_index] : Dtype(0); } /** * @brief Sets the loss associated with a top blob at a given index. */ - inline void set_loss(const int top_index, const Dtype value) { + inline void set_loss(const int_tp top_index, const Dtype value) { if (loss_.size() <= top_index) { loss_.resize(top_index + 1, Dtype(0)); } @@ -213,7 +224,9 @@ class Layer { /** * @brief Returns the layer type. */ - virtual inline const char* type() const { return ""; } + virtual inline const char* type() const { + return ""; + } /** * @brief Returns the exact number of bottom blobs required by the layer, @@ -222,7 +235,9 @@ class Layer { * This method should be overridden to return a non-negative value if your * layer expects some exact number of bottom blobs. */ - virtual inline int ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp ExactNumBottomBlobs() const { + return -1; + } /** * @brief Returns the minimum number of bottom blobs required by the layer, * or -1 if no minimum number is required. @@ -230,7 +245,9 @@ class Layer { * This method should be overridden to return a non-negative value if your * layer expects some minimum number of bottom blobs. */ - virtual inline int MinBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { + return -1; + } /** * @brief Returns the maximum number of bottom blobs required by the layer, * or -1 if no maximum number is required. @@ -238,7 +255,9 @@ class Layer { * This method should be overridden to return a non-negative value if your * layer expects some maximum number of bottom blobs. */ - virtual inline int MaxBottomBlobs() const { return -1; } + virtual inline int_tp MaxBottomBlobs() const { + return -1; + } /** * @brief Returns the exact number of top blobs required by the layer, * or -1 if no exact number is required. @@ -246,7 +265,9 @@ class Layer { * This method should be overridden to return a non-negative value if your * layer expects some exact number of top blobs. */ - virtual inline int ExactNumTopBlobs() const { return -1; } + virtual inline int_tp ExactNumTopBlobs() const { + return -1; + } /** * @brief Returns the minimum number of top blobs required by the layer, * or -1 if no minimum number is required. @@ -254,7 +275,9 @@ class Layer { * This method should be overridden to return a non-negative value if your * layer expects some minimum number of top blobs. */ - virtual inline int MinTopBlobs() const { return -1; } + virtual inline int_tp MinTopBlobs() const { + return -1; + } /** * @brief Returns the maximum number of top blobs required by the layer, * or -1 if no maximum number is required. @@ -262,7 +285,9 @@ class Layer { * This method should be overridden to return a non-negative value if your * layer expects some maximum number of top blobs. */ - virtual inline int MaxTopBlobs() const { return -1; } + virtual inline int_tp MaxTopBlobs() const { + return -1; + } /** * @brief Returns true if the layer requires an equal number of bottom and * top blobs. @@ -270,7 +295,9 @@ class Layer { * This method should be overridden to return true if your layer expects an * equal number of bottom and top blobs. */ - virtual inline bool EqualNumBottomTopBlobs() const { return false; } + virtual inline bool EqualNumBottomTopBlobs() const { + return false; + } /** * @brief Return whether "anonymous" top blobs are created automatically @@ -280,7 +307,9 @@ class Layer { * blobs to fulfill the requirement specified by ExactNumTopBlobs() or * MinTopBlobs(). */ - virtual inline bool AutoTopBlobs() const { return false; } + virtual inline bool AutoTopBlobs() const { + return false; + } /** * @brief Return whether to allow force_backward for a given bottom blob @@ -290,7 +319,7 @@ class Layer { * setting and backpropagate to blob i only if it needs gradient information * (as is done when force_backward == false). */ - virtual inline bool AllowForceBackward(const int bottom_index) const { + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { return true; } @@ -301,21 +330,40 @@ class Layer { * You can safely ignore false values and always compute gradients * for all parameters, but possibly with wasteful computation. */ - inline bool param_propagate_down(const int param_id) { - return (param_propagate_down_.size() > param_id) ? - param_propagate_down_[param_id] : false; + inline bool param_propagate_down(const int_tp param_id) { + return + (param_propagate_down_.size() > param_id) ? + param_propagate_down_[param_id] : false; } /** * @brief Sets whether the layer should compute gradients w.r.t. a * parameter at a particular index given by param_id. */ - inline void set_param_propagate_down(const int param_id, const bool value) { + inline void set_param_propagate_down(const int_tp param_id, + const bool value) { if (param_propagate_down_.size() <= param_id) { param_propagate_down_.resize(param_id + 1, true); } param_propagate_down_[param_id] = value; } + /** + * @brief Returns the device context this layer runs on + */ + inline device *get_device() { + return device_; + } + + /** + * @brief Returns the estimated floating point operations of this layer + */ + virtual uint_tp ForwardFlops() { + return 0; + } + + virtual uint_tp BackwardFlops() { + return 0; + } protected: /** The protobuf that stores the layer parameters */ @@ -331,17 +379,20 @@ class Layer { * the objective function. */ vector loss_; + /** Device context */ + device *device_; + /** @brief Using the CPU device, compute the layer output. */ virtual void Forward_cpu(const vector*>& bottom, - const vector*>& top) = 0; + const vector*>& top) = 0; /** * @brief Using the GPU device, compute the layer output. * Fall back to Forward_cpu() if unavailable. */ virtual void Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { // LOG(WARNING) << "Using CPU code as backup."; - return Forward_cpu(bottom, top); + Forward_cpu(bottom, top); } /** @@ -349,16 +400,16 @@ class Layer { * for the bottom blobs if propagate_down is true. */ virtual void Backward_cpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) = 0; + const vector& propagate_down, + const vector*>& bottom) = 0; /** * @brief Using the GPU device, compute the gradients for any parameters and * for the bottom blobs if propagate_down is true. * Fall back to Backward_cpu() if unavailable. */ virtual void Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { // LOG(WARNING) << "Using CPU code as backup."; Backward_cpu(top, propagate_down, bottom); } @@ -371,39 +422,39 @@ class Layer { virtual void CheckBlobCounts(const vector*>& bottom, const vector*>& top) { if (ExactNumBottomBlobs() >= 0) { - CHECK_EQ(ExactNumBottomBlobs(), bottom.size()) - << type() << " Layer takes " << ExactNumBottomBlobs() - << " bottom blob(s) as input."; + CHECK_EQ(ExactNumBottomBlobs(), bottom.size())<< type() + << " Layer takes " << ExactNumBottomBlobs() + << " bottom blob(s) as input."; } if (MinBottomBlobs() >= 0) { CHECK_LE(MinBottomBlobs(), bottom.size()) - << type() << " Layer takes at least " << MinBottomBlobs() - << " bottom blob(s) as input."; + << type() << " Layer takes at least " << MinBottomBlobs() + << " bottom blob(s) as input."; } if (MaxBottomBlobs() >= 0) { CHECK_GE(MaxBottomBlobs(), bottom.size()) - << type() << " Layer takes at most " << MaxBottomBlobs() - << " bottom blob(s) as input."; + << type() << " Layer takes at most " << MaxBottomBlobs() + << " bottom blob(s) as input."; } if (ExactNumTopBlobs() >= 0) { CHECK_EQ(ExactNumTopBlobs(), top.size()) - << type() << " Layer produces " << ExactNumTopBlobs() - << " top blob(s) as output."; + << type() << " Layer produces " << ExactNumTopBlobs() + << " top blob(s) as output."; } if (MinTopBlobs() >= 0) { CHECK_LE(MinTopBlobs(), top.size()) - << type() << " Layer produces at least " << MinTopBlobs() - << " top blob(s) as output."; + << type() << " Layer produces at least " << MinTopBlobs() + << " top blob(s) as output."; } if (MaxTopBlobs() >= 0) { CHECK_GE(MaxTopBlobs(), top.size()) - << type() << " Layer produces at most " << MaxTopBlobs() - << " top blob(s) as output."; + << type() << " Layer produces at most " << MaxTopBlobs() + << " top blob(s) as output."; } if (EqualNumBottomTopBlobs()) { CHECK_EQ(bottom.size(), top.size()) - << type() << " Layer produces one top blob as output for each " - << "bottom blob input."; + << type() << " Layer produces one top blob as output for each " + << "bottom blob input."; } } @@ -412,15 +463,15 @@ class Layer { * the loss function. Store non-zero loss weights in the diff blob. */ inline void SetLossWeights(const vector*>& top) { - const int num_loss_weights = layer_param_.loss_weight_size(); + const int_tp num_loss_weights = layer_param_.loss_weight_size(); if (num_loss_weights) { CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be " - "unspecified or specified once per top blob."; - for (int top_id = 0; top_id < top.size(); ++top_id) { + "unspecified or specified once per top blob."; + for (int_tp top_id = 0; top_id < top.size(); ++top_id) { const Dtype loss_weight = layer_param_.loss_weight(top_id); - if (loss_weight == Dtype(0)) { continue; } + if (loss_weight == Dtype(0)) {continue;} this->set_loss(top_id, loss_weight); - const int count = top[top_id]->count(); + const int_tp count = top[top_id]->count(); Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff(); caffe_set(count, loss_weight, loss_multiplier); } @@ -447,68 +498,91 @@ class Layer { // Forward and backward wrappers. You should implement the cpu and // gpu specific implementations instead, and should not change these // functions. -template +template inline Dtype Layer::Forward(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { // Lock during forward to ensure sequential forward Lock(); Dtype loss = 0; Reshape(bottom, top); switch (Caffe::mode()) { - case Caffe::CPU: - Forward_cpu(bottom, top); - for (int top_id = 0; top_id < top.size(); ++top_id) { - if (!this->loss(top_id)) { continue; } - const int count = top[top_id]->count(); - const Dtype* data = top[top_id]->cpu_data(); - const Dtype* loss_weights = top[top_id]->cpu_diff(); - loss += caffe_cpu_dot(count, data, loss_weights); - } - break; - case Caffe::GPU: - Forward_gpu(bottom, top); + case Caffe::CPU: + Forward_cpu(bottom, top); + for (int_tp top_id = 0; top_id < top.size(); ++top_id) { + if (!this->loss(top_id)) { + continue; + } + const int_tp count = top[top_id]->count(); + const Dtype* data = top[top_id]->cpu_data(); + const Dtype* loss_weights = top[top_id]->cpu_diff(); + loss += caffe_cpu_dot(count, data, loss_weights); + } + break; + case Caffe::GPU: + Forward_gpu(bottom, top); #ifndef CPU_ONLY - for (int top_id = 0; top_id < top.size(); ++top_id) { - if (!this->loss(top_id)) { continue; } - const int count = top[top_id]->count(); - const Dtype* data = top[top_id]->gpu_data(); - const Dtype* loss_weights = top[top_id]->gpu_diff(); - Dtype blob_loss = 0; - caffe_gpu_dot(count, data, loss_weights, &blob_loss); - loss += blob_loss; - } + if (device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int_tp top_id = 0; top_id < top.size(); ++top_id) { + if (!this->loss(top_id)) { + continue; + } + const int_tp count = top[top_id]->count(); + const Dtype* data = top[top_id]->gpu_data(); + const Dtype* loss_weights = top[top_id]->gpu_diff(); + Dtype blob_loss = 0; + caffe_gpu_dot(count, data, loss_weights, &blob_loss); + loss += blob_loss; + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + for (int_tp top_id = 0; top_id < top.size(); ++top_id) { + if (!this->loss(top_id)) { + continue; + } + const int_tp count = top[top_id]->count(); + cl_mem data = (cl_mem) (top[top_id]->gpu_data()); + cl_mem loss_weights = (cl_mem) (top[top_id]->gpu_diff()); + Dtype blob_loss = 0; + greentea_gpu_dot(this->device_->id(), count, data, 0, + loss_weights, 0, &blob_loss); + loss += blob_loss; + } +#endif // USE_GREENTEA + } #endif - break; - default: - LOG(FATAL) << "Unknown caffe mode."; - } + break; + default: + LOG(FATAL)<< "Unknown caffe mode."; + } Unlock(); return loss; } -template +template inline void Layer::Backward(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { switch (Caffe::mode()) { - case Caffe::CPU: - Backward_cpu(top, propagate_down, bottom); - break; - case Caffe::GPU: - Backward_gpu(top, propagate_down, bottom); - break; - default: - LOG(FATAL) << "Unknown caffe mode."; + case Caffe::CPU: + Backward_cpu(top, propagate_down, bottom); + break; + case Caffe::GPU: + Backward_gpu(top, propagate_down, bottom); + break; + default: + LOG(FATAL)<< "Unknown caffe mode."; + } } -} // Serialize LayerParameter to protocol buffer -template +template void Layer::ToProto(LayerParameter* param, bool write_diff) { param->Clear(); param->CopyFrom(layer_param_); param->clear_blobs(); - for (int i = 0; i < blobs_.size(); ++i) { + for (int_tp i = 0; i < blobs_.size(); ++i) { blobs_[i]->ToProto(param->add_blobs(), write_diff); } } diff --git a/include/caffe/layer_factory.hpp b/include/caffe/layer_factory.hpp index f385afccfee..70f42416f8a 100644 --- a/include/caffe/layer_factory.hpp +++ b/include/caffe/layer_factory.hpp @@ -44,6 +44,7 @@ #include #include "caffe/common.hpp" +#include "caffe/device.hpp" #include "caffe/layer.hpp" #include "caffe/proto/caffe.pb.h" diff --git a/include/caffe/layers/absval_layer.hpp b/include/caffe/layers/absval_layer.hpp index 9b5305dceb4..5a94fdda9b9 100644 --- a/include/caffe/layers/absval_layer.hpp +++ b/include/caffe/layers/absval_layer.hpp @@ -30,8 +30,8 @@ class AbsValLayer : public NeuronLayer { const vector*>& top); virtual inline const char* type() const { return "AbsVal"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: /// @copydoc AbsValLayer diff --git a/include/caffe/layers/accuracy_layer.hpp b/include/caffe/layers/accuracy_layer.hpp index fe2adb939e4..48e0a485eec 100644 --- a/include/caffe/layers/accuracy_layer.hpp +++ b/include/caffe/layers/accuracy_layer.hpp @@ -34,12 +34,12 @@ class AccuracyLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Accuracy"; } - virtual inline int ExactNumBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumBottomBlobs() const { return 2; } // If there are two top blobs, then the second blob will contain // accuracies per class. - virtual inline int MinTopBlobs() const { return 1; } - virtual inline int MaxTopBlos() const { return 2; } + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlos() const { return 2; } protected: /** @@ -51,7 +51,7 @@ class AccuracyLayer : public Layer { * label @f$ \hat{l}_n @f$ given by its maximal index: * @f$ \hat{l}_n = \arg\max\limits_k x_{nk} @f$ * -# @f$ (N \times 1 \times 1 \times 1) @f$ - * the labels @f$ l @f$, an integer-valued Blob with values + * the labels @f$ l @f$, an int_tpeger-valued Blob with values * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ * indicating the correct class label among the @f$ K @f$ classes * @param top output Blob vector (length 1) @@ -73,19 +73,19 @@ class AccuracyLayer : public Layer { /// @brief Not implemented -- AccuracyLayer cannot be used as a loss. virtual void Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { - for (int i = 0; i < propagate_down.size(); ++i) { + for (int_tp i = 0; i < propagate_down.size(); ++i) { if (propagate_down[i]) { NOT_IMPLEMENTED; } } } - int label_axis_, outer_num_, inner_num_; + int_tp label_axis_, outer_num_, inner_num_; - int top_k_; + int_tp top_k_; /// Whether to ignore instances with a certain label. bool has_ignore_label_; /// The label indicating that an instance should be ignored. - int ignore_label_; + int_tp ignore_label_; /// Keeps counts of the number of samples per class. Blob nums_buffer_; }; diff --git a/include/caffe/layers/affinity_layer.hpp b/include/caffe/layers/affinity_layer.hpp new file mode 100644 index 00000000000..2d1a72d223f --- /dev/null +++ b/include/caffe/layers/affinity_layer.hpp @@ -0,0 +1,48 @@ +#ifndef CAFFE_AFFINITY_LAYER_HPP_ +#define CAFFE_AFFINITY_LAYER_HPP_ + +#include + +#include "caffe/blob.hpp" +#include "caffe/layer.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + + +/** + * @brief Computes a one edge per dimension 2D affinity graph + * for a given segmentation/label map + */ +template +class AffinityLayer : public Layer { + public: + explicit AffinityLayer(const LayerParameter& param) + : Layer(param) { + } + + virtual inline const char* type() const { + return "Affinity"; + } + + protected: + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom); + + private: + std::vector< shared_ptr< Blob > > min_index_; + std::vector offsets_; +}; + +} // namespace caffe + +#endif // CAFFE_AFFINITY_LAYER_HPP_ diff --git a/include/caffe/layers/argmax_layer.hpp b/include/caffe/layers/argmax_layer.hpp index 4fef363e850..3311ddb0fa4 100644 --- a/include/caffe/layers/argmax_layer.hpp +++ b/include/caffe/layers/argmax_layer.hpp @@ -13,7 +13,7 @@ namespace caffe { * @brief Compute the index of the @f$ K @f$ max values for each datum across * all dimensions @f$ (C \times H \times W) @f$. * - * Intended for use after a classification layer to produce a prediction. + * int_tpended for use after a classification layer to produce a prediction. * If parameter out_max_val is set to true, output is a vector of pairs * (max_ind, max_val) for each image. The axis parameter specifies an axis * along which to maximise. @@ -26,12 +26,12 @@ class ArgMaxLayer : public Layer { /** * @param param provides ArgMaxParameter argmax_param, * with ArgMaxLayer options: - * - top_k (\b optional uint, default 1). + * - top_k (\b optional uint_tp_tp, default 1). * the number @f$ K @f$ of maximal items to output. * - out_max_val (\b optional bool, default false). * if set, output a vector of pairs (max_ind, max_val) unless axis is set then * output max_val along the specified axis. - * - axis (\b optional int). + * - axis (\b optional int_tp). * if set, maximise along the specified axis else maximise the flattened * trailing dimensions for each index of the first / num dimension. */ @@ -43,8 +43,8 @@ class ArgMaxLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "ArgMax"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: /** @@ -69,7 +69,7 @@ class ArgMaxLayer : public Layer { bool out_max_val_; size_t top_k_; bool has_axis_; - int axis_; + int_tp axis_; }; } // namespace caffe diff --git a/include/caffe/layers/base_conv_layer.hpp b/include/caffe/layers/base_conv_layer.hpp index 0160a833dd2..aca544fbb7c 100644 --- a/include/caffe/layers/base_conv_layer.hpp +++ b/include/caffe/layers/base_conv_layer.hpp @@ -8,52 +8,69 @@ #include "caffe/proto/caffe.pb.h" #include "caffe/util/im2col.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea_im2col.hpp" +#endif + namespace caffe { /** * @brief Abstract base class that factors out the BLAS code common to * ConvolutionLayer and DeconvolutionLayer. */ -template +template class BaseConvolutionLayer : public Layer { public: explicit BaseConvolutionLayer(const LayerParameter& param) - : Layer(param) {} + : Layer(param) { + } virtual void LayerSetUp(const vector*>& bottom, - const vector*>& top); + const vector*>& top); virtual void Reshape(const vector*>& bottom, - const vector*>& top); + const vector*>& top); - virtual inline int MinBottomBlobs() const { return 1; } - virtual inline int MinTopBlobs() const { return 1; } - virtual inline bool EqualNumBottomTopBlobs() const { return true; } + virtual inline int_tp MinBottomBlobs() const { + return 1; + } + virtual inline int_tp MinTopBlobs() const { + return 1; + } + virtual inline bool EqualNumBottomTopBlobs() const { + return true; + } protected: // Helper functions that abstract away the column buffer and gemm arguments. // The last argument in forward_cpu_gemm is so that we can skip the im2col if // we just called weight_cpu_gemm with the same input. - void forward_cpu_gemm(const Dtype* input, const Dtype* weights, - Dtype* output, bool skip_im2col = false); + void forward_cpu_gemm(const Dtype* input, const Dtype* weights, Dtype* output, + bool skip_im2col = false); void forward_cpu_bias(Dtype* output, const Dtype* bias); void backward_cpu_gemm(const Dtype* input, const Dtype* weights, - Dtype* output); - void weight_cpu_gemm(const Dtype* input, const Dtype* output, Dtype* - weights); + Dtype* output); + void weight_cpu_gemm(const Dtype* input, const Dtype* output, Dtype* weights); void backward_cpu_bias(Dtype* bias, const Dtype* input); #ifndef CPU_ONLY - void forward_gpu_gemm(const Dtype* col_input, const Dtype* weights, - Dtype* output, bool skip_im2col = false); - void forward_gpu_bias(Dtype* output, const Dtype* bias); - void backward_gpu_gemm(const Dtype* input, const Dtype* weights, - Dtype* col_output); - void weight_gpu_gemm(const Dtype* col_input, const Dtype* output, Dtype* - weights); - void backward_gpu_bias(Dtype* bias, const Dtype* input); + void forward_gpu_gemm(const Dtype* col_input, const int_tp col_input_off, + const Dtype* weights, Dtype* output, + const int_tp output_off, bool skip_im2col = false); + void forward_gpu_bias(Dtype* output, const int_tp output_off, + const Dtype* bias); + void backward_gpu_gemm(const Dtype* input, const int_tp input_off, + const Dtype* weights, Dtype* col_output, + const int_tp col_output_off); + void weight_gpu_gemm(const Dtype* col_input, const int_tp col_input_off, + const Dtype* output, const int_tp output_off, + Dtype* weights); + void backward_gpu_bias(Dtype* bias, const Dtype* input, + const int_tp input_off); + + shared_ptr > col_buffer(); #endif /// @brief The spatial dimensions of the input. - inline int input_shape(int i) { + inline int_tp input_shape(int_tp i) { return (*bottom_shape_)[channel_axis_ + i]; } // reverse_dimensions should return true iff we are implementing deconv, so @@ -63,35 +80,36 @@ class BaseConvolutionLayer : public Layer { virtual void compute_output_shape() = 0; /// @brief The spatial dimensions of a filter kernel. - Blob kernel_shape_; + Blob kernel_shape_; /// @brief The spatial dimensions of the stride. - Blob stride_; + Blob stride_; /// @brief The spatial dimensions of the padding. - Blob pad_; + Blob pad_; /// @brief The spatial dimensions of the dilation. - Blob dilation_; + Blob dilation_; /// @brief The spatial dimensions of the convolution input. - Blob conv_input_shape_; + Blob conv_input_shape_; /// @brief The spatial dimensions of the col_buffer. - vector col_buffer_shape_; + vector col_buffer_shape_; /// @brief The spatial dimensions of the output. - vector output_shape_; - const vector* bottom_shape_; - - int num_spatial_axes_; - int bottom_dim_; - int top_dim_; - - int channel_axis_; - int num_; - int channels_; - int group_; - int out_spatial_dim_; - int weight_offset_; - int num_output_; + vector output_shape_; + const vector* bottom_shape_; + + int_tp num_spatial_axes_; + int_tp bottom_dim_; + int_tp top_dim_; + + int_tp channel_axis_; + int_tp num_; + int_tp channels_; + int_tp group_; + int_tp out_spatial_dim_; + int_tp weight_offset_; + int_tp num_output_; bool bias_term_; bool is_1x1_; bool force_nd_im2col_; + bool use_colbuffer_; private: // wrap im2col/col2im so we don't have to remember the (long) argument lists @@ -123,7 +141,9 @@ class BaseConvolutionLayer : public Layer { pad_.cpu_data(), stride_.cpu_data(), dilation_.cpu_data(), data); } } + #ifndef CPU_ONLY +#ifdef USE_CUDA inline void conv_im2col_gpu(const Dtype* data, Dtype* col_buff) { if (!force_nd_im2col_ && num_spatial_axes_ == 2) { im2col_gpu(data, conv_in_channels_, @@ -139,6 +159,7 @@ class BaseConvolutionLayer : public Layer { stride_.gpu_data(), dilation_.gpu_data(), col_buff); } } + inline void conv_col2im_gpu(const Dtype* col_buff, Dtype* data) { if (!force_nd_im2col_ && num_spatial_axes_ == 2) { col2im_gpu(col_buff, conv_in_channels_, @@ -154,16 +175,96 @@ class BaseConvolutionLayer : public Layer { dilation_.gpu_data(), data); } } -#endif +#endif // USE_CUDA +#ifdef USE_GREENTEA + inline void greentea_conv_im2col_gpu(const Dtype* data, const int_tp data_off, + Dtype* col_buff, + const int_tp col_buff_off) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if (!force_nd_im2col_ && num_spatial_axes_ == 2) { + greentea_im2col_gpu(&program, &ctx, (cl_mem) data, data_off, + conv_in_channels_, + conv_input_shape_.cpu_data()[1], + conv_input_shape_.cpu_data()[2], + kernel_shape_.cpu_data()[0], + kernel_shape_.cpu_data()[1], + pad_.cpu_data()[0], pad_.cpu_data()[1], + stride_.cpu_data()[0], stride_.cpu_data()[1], + dilation_.cpu_data()[0], + dilation_.cpu_data()[1], (cl_mem) col_buff, + col_buff_off); + } else { + greentea_im2col_nd_gpu(&program, &ctx, (cl_mem) data, data_off, + num_spatial_axes_, + (int_tp)0, + num_kernels_im2col_, + (cl_mem) (conv_input_shape_.gpu_data()), + (cl_mem) (col_buffer_.gpu_shape()), + (cl_mem) (kernel_shape_.gpu_data()), + (cl_mem) (pad_.gpu_data()), + (cl_mem) (stride_.gpu_data()), + (cl_mem) (dilation_.gpu_data()), + (cl_mem) col_buff, col_buff_off); + } + } + + inline void greentea_conv_col2im_gpu(const Dtype* col_buff, + const int_tp col_buff_off, Dtype* data, + const int_tp data_off) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if (!force_nd_im2col_ && num_spatial_axes_ == 2) { + greentea_col2im_gpu(&program, &ctx, + (cl_mem) col_buff, + col_buff_off, + conv_in_channels_, + conv_input_shape_.cpu_data()[1], + conv_input_shape_.cpu_data()[2], + kernel_shape_.cpu_data()[0], + kernel_shape_.cpu_data()[1], + pad_.cpu_data()[0], + pad_.cpu_data()[1], + stride_.cpu_data()[0], + stride_.cpu_data()[1], + dilation_.cpu_data()[0], + dilation_.cpu_data()[1], + (cl_mem) data, + data_off); + } else { + greentea_col2im_nd_gpu(&program, &ctx, + (cl_mem) col_buff, + col_buff_off, + num_spatial_axes_, + (int_tp)0, + num_kernels_col2im_, + (cl_mem) (conv_input_shape_.gpu_data()), + (cl_mem) (col_buffer_.gpu_shape()), + (cl_mem) (kernel_shape_.gpu_data()), + (cl_mem) (pad_.gpu_data()), + (cl_mem) (stride_.gpu_data()), + (cl_mem) (dilation_.gpu_data()), + (cl_mem) data, + data_off); + } + } +#endif // USE_GREENTEA +#endif // !CPU_ONLY + + int_tp num_kernels_im2col_; + int_tp num_kernels_col2im_; + int_tp conv_out_channels_; + int_tp conv_in_channels_; + int_tp conv_out_spatial_dim_; + int_tp kernel_dim_; + int_tp col_offset_; + int_tp output_offset_; - int num_kernels_im2col_; - int num_kernels_col2im_; - int conv_out_channels_; - int conv_in_channels_; - int conv_out_spatial_dim_; - int kernel_dim_; - int col_offset_; - int output_offset_; + bool use_skernel_; Blob col_buffer_; Blob bias_multiplier_; diff --git a/include/caffe/layers/base_data_layer.hpp b/include/caffe/layers/base_data_layer.hpp index 2c49b73184b..9c32b1ae247 100644 --- a/include/caffe/layers/base_data_layer.hpp +++ b/include/caffe/layers/base_data_layer.hpp @@ -68,7 +68,7 @@ class BasePrefetchingDataLayer : const vector*>& top); // Prefetches batches (asynchronously if to GPU memory) - static const int PREFETCH_COUNT = 3; + static const int_tp PREFETCH_COUNT = 3; protected: virtual void InternalThreadEntry(); diff --git a/include/caffe/layers/batch_norm_layer.hpp b/include/caffe/layers/batch_norm_layer.hpp index 9b2d5126efb..c88065308f7 100644 --- a/include/caffe/layers/batch_norm_layer.hpp +++ b/include/caffe/layers/batch_norm_layer.hpp @@ -34,7 +34,7 @@ namespace caffe { * the BatchNorm layer's output. * * [1] S. Ioffe and C. Szegedy, "Batch Normalization: Accelerating Deep Network - * Training by Reducing Internal Covariate Shift." arXiv preprint + * Training by Reducing int_tpernal Covariate Shift." arXiv preprint_tp * arXiv:1502.03167 (2015). * * TODO(dox): thorough documentation for Forward, Backward, and proto params. @@ -50,8 +50,8 @@ class BatchNormLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "BatchNorm"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -66,7 +66,7 @@ class BatchNormLayer : public Layer { Blob mean_, variance_, temp_, x_norm_; bool use_global_stats_; Dtype moving_average_fraction_; - int channels_; + int_tp channels_; Dtype eps_; // extra temporarary variables is used to carry out sums/broadcasting diff --git a/include/caffe/layers/batch_reindex_layer.hpp b/include/caffe/layers/batch_reindex_layer.hpp index ebb3a567bc4..de4d3699368 100644 --- a/include/caffe/layers/batch_reindex_layer.hpp +++ b/include/caffe/layers/batch_reindex_layer.hpp @@ -11,10 +11,10 @@ namespace caffe { /** - * @brief Index into the input blob along its first axis. + * @brief Index int_tpo the input blob along its first axis. * * This layer can be used to select, reorder, and even replicate examples in a - * batch. The second blob is cast to int and treated as an index into the + * batch. The second blob is cast to int_tp and treated as an index int_tpo the * first axis of the first blob. */ template @@ -26,8 +26,8 @@ class BatchReindexLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "BatchReindex"; } - virtual inline int ExactNumBottomBlobs() const { return 2; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: /** @@ -69,12 +69,12 @@ class BatchReindexLayer : public Layer { private: struct pair_sort_first { - bool operator()(const std::pair &left, - const std::pair &right) { + bool operator()(const std::pair &left, + const std::pair &right) { return left.first < right.first; } }; - void check_batch_reindex(int initial_num, int final_num, + void check_batch_reindex(int_tp initial_num, int_tp final_num, const Dtype* ridx_data); }; diff --git a/include/caffe/layers/bias_layer.hpp b/include/caffe/layers/bias_layer.hpp index eedc3aaa351..bc84e65951c 100644 --- a/include/caffe/layers/bias_layer.hpp +++ b/include/caffe/layers/bias_layer.hpp @@ -29,9 +29,9 @@ class BiasLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Bias"; } - virtual inline int MinBottomBlobs() const { return 1; } - virtual inline int MaxBottomBlobs() const { return 2; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp MinBottomBlobs() const { return 1; } + virtual inline int_tp MaxBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); @@ -44,7 +44,7 @@ class BiasLayer : public Layer { private: Blob bias_multiplier_; - int outer_dim_, bias_dim_, inner_dim_, dim_; + int_tp outer_dim_, bias_dim_, inner_dim_, dim_; }; diff --git a/include/caffe/layers/bnll_layer.hpp b/include/caffe/layers/bnll_layer.hpp index be07c748364..6fbae1a8d25 100644 --- a/include/caffe/layers/bnll_layer.hpp +++ b/include/caffe/layers/bnll_layer.hpp @@ -11,6 +11,8 @@ namespace caffe { +const float kBNLL_THRESHOLD = 50.; + /** * @brief Computes @f$ y = x + \log(1 + \exp(-x)) @f$ if @f$ x > 0 @f$; * @f$ y = \log(1 + \exp(x)) @f$ otherwise. diff --git a/include/caffe/layers/concat_layer.hpp b/include/caffe/layers/concat_layer.hpp index a1570249197..e1d33041db6 100644 --- a/include/caffe/layers/concat_layer.hpp +++ b/include/caffe/layers/concat_layer.hpp @@ -24,8 +24,8 @@ class ConcatLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Concat"; } - virtual inline int MinBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp MinBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: /** @@ -59,7 +59,7 @@ class ConcatLayer : public Layer { * containing error gradients @f$ \frac{\partial E}{\partial y} @f$ * with respect to concatenated outputs @f$ y @f$ * @param propagate_down see Layer::Backward. - * @param bottom input Blob vector (length K), into which the top gradient + * @param bottom input Blob vector (length K), int_tpo which the top gradient * @f$ \frac{\partial E}{\partial y} @f$ is deconcatenated back to the * inputs @f$ * \left[ \begin{array}{cccc} @@ -76,10 +76,10 @@ class ConcatLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int count_; - int num_concats_; - int concat_input_size_; - int concat_axis_; + int_tp count_; + int_tp num_concats_; + int_tp concat_input_size_; + int_tp concat_axis_; }; } // namespace caffe diff --git a/include/caffe/layers/connected_component_layer.hpp b/include/caffe/layers/connected_component_layer.hpp new file mode 100644 index 00000000000..c6eb87fd96f --- /dev/null +++ b/include/caffe/layers/connected_component_layer.hpp @@ -0,0 +1,54 @@ +#ifndef CAFFE_CONNECTED_COMPONENT_LAYER_HPP_ +#define CAFFE_CONNECTED_COMPONENT_LAYER_HPP_ + +#include + +#include "caffe/blob.hpp" +#include "caffe/layer.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + + +/** + * @brief Computes a connected components map from a segmentation map. + */ +template +class ConnectedComponentLayer : public Layer { + public: + explicit ConnectedComponentLayer(const LayerParameter& param) + : Layer(param) { + } + + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline int_tp ExactNumBottomBlobs() const { + return 1; + } + + virtual inline int_tp ExactNumTopBlobs() const { + return 1; + } + + virtual inline const char* type() const { + return "ConnectedComponent"; + } + + protected: + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom); + + private: + cv::Mat FindBlobs(const int maxlabel, const cv::Mat &input); +}; + +} // namespace caffe + +#endif // CAFFE_CONNECTED_COMPONENT_LAYER_HPP_ diff --git a/include/caffe/layers/contrastive_loss_layer.hpp b/include/caffe/layers/contrastive_loss_layer.hpp index e890afb8207..bc52c4fd1a7 100644 --- a/include/caffe/layers/contrastive_loss_layer.hpp +++ b/include/caffe/layers/contrastive_loss_layer.hpp @@ -43,13 +43,13 @@ class ContrastiveLossLayer : public LossLayer { virtual void LayerSetUp(const vector*>& bottom, const vector*>& top); - virtual inline int ExactNumBottomBlobs() const { return 3; } + virtual inline int_tp ExactNumBottomBlobs() const { return 3; } virtual inline const char* type() const { return "ContrastiveLoss"; } /** * Unlike most loss layers, in the ContrastiveLossLayer we can backpropagate * to the first two inputs. */ - virtual inline bool AllowForceBackward(const int bottom_index) const { + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { return bottom_index != 2; } diff --git a/include/caffe/layers/conv_layer.hpp b/include/caffe/layers/conv_layer.hpp index 93a618ddd72..3743f536eea 100644 --- a/include/caffe/layers/conv_layer.hpp +++ b/include/caffe/layers/conv_layer.hpp @@ -27,7 +27,7 @@ namespace caffe { * be filtered. col2im restores the output spatial structure by rolling up * the output channel N' columns of the output matrix. */ -template +template class ConvolutionLayer : public BaseConvolutionLayer { public: /** @@ -62,20 +62,41 @@ class ConvolutionLayer : public BaseConvolutionLayer { * kernels + stream parallelism) engines. */ explicit ConvolutionLayer(const LayerParameter& param) - : BaseConvolutionLayer(param) {} + : BaseConvolutionLayer(param) { + } - virtual inline const char* type() const { return "Convolution"; } + virtual inline const char* type() const { + return "Convolution"; + } + + virtual uint_tp ForwardFlops() { + uint_tp group = this->group_; + uint_tp N = 1; + uint_tp M = this->num_output_ / group; + uint_tp K = this->channels_; + const int_tp* kshape = this->kernel_shape_.cpu_data(); + for (int_tp i = 0; i < this->output_shape_.size(); ++i) { + N *= this->output_shape_[i]; + K *= kshape[i]; + } + K /= group; + return group* (M * N * (2 * K - 1)); + } protected: virtual void Forward_cpu(const vector*>& bottom, - const vector*>& top); + const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, - const vector*>& top); + const vector*>& top); virtual void Backward_cpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom); + const vector& propagate_down, + const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom); - virtual inline bool reverse_dimensions() { return false; } + const vector& propagate_down, + const vector*>& bottom); + virtual inline bool reverse_dimensions() { + return false; + } virtual void compute_output_shape(); }; diff --git a/include/caffe/layers/cudnn_conv_layer.hpp b/include/caffe/layers/cudnn_conv_layer.hpp index 31fe49a71fa..209e3f9cb9a 100644 --- a/include/caffe/layers/cudnn_conv_layer.hpp +++ b/include/caffe/layers/cudnn_conv_layer.hpp @@ -9,9 +9,14 @@ #include "caffe/layers/conv_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN + /* * @brief cuDNN implementation of ConvolutionLayer. * Fallback to ConvolutionLayer for CPU mode. @@ -56,14 +61,14 @@ class CuDNNConvolutionLayer : public ConvolutionLayer { cudnnTensorDescriptor_t bias_desc_; cudnnFilterDescriptor_t filter_desc_; vector conv_descs_; - int bottom_offset_, top_offset_, bias_offset_; + int_tp bottom_offset_, top_offset_, bias_offset_; size_t *workspace_fwd_sizes_; size_t *workspace_bwd_data_sizes_; size_t *workspace_bwd_filter_sizes_; size_t workspaceSizeInBytes; // size of underlying storage void *workspaceData; // underlying storage - void **workspace; // aliases into workspaceData + void **workspace; // aliases int_tpo workspaceData }; #endif diff --git a/include/caffe/layers/cudnn_lcn_layer.hpp b/include/caffe/layers/cudnn_lcn_layer.hpp index 74cf4775e51..28ad7dc807c 100644 --- a/include/caffe/layers/cudnn_lcn_layer.hpp +++ b/include/caffe/layers/cudnn_lcn_layer.hpp @@ -10,6 +10,10 @@ #include "caffe/layers/lrn_layer.hpp" #include "caffe/layers/power_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN @@ -36,7 +40,7 @@ class CuDNNLCNLayer : public LRNLayer { cudnnLRNDescriptor_t norm_desc_; cudnnTensorDescriptor_t bottom_desc_, top_desc_; - int size_, pre_pad_; + int_tp size_, pre_pad_; Dtype alpha_, beta_, k_; size_t tempDataSize; diff --git a/include/caffe/layers/cudnn_lrn_layer.hpp b/include/caffe/layers/cudnn_lrn_layer.hpp index 000ccc36507..c2db5dc75e1 100644 --- a/include/caffe/layers/cudnn_lrn_layer.hpp +++ b/include/caffe/layers/cudnn_lrn_layer.hpp @@ -9,6 +9,10 @@ #include "caffe/layers/lrn_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN @@ -34,7 +38,7 @@ class CuDNNLRNLayer : public LRNLayer { cudnnLRNDescriptor_t norm_desc_; cudnnTensorDescriptor_t bottom_desc_, top_desc_; - int size_; + int_tp size_; Dtype alpha_, beta_, k_; }; #endif diff --git a/include/caffe/layers/cudnn_pooling_layer.hpp b/include/caffe/layers/cudnn_pooling_layer.hpp index 6d0db47d660..e7df07bf036 100644 --- a/include/caffe/layers/cudnn_pooling_layer.hpp +++ b/include/caffe/layers/cudnn_pooling_layer.hpp @@ -9,6 +9,10 @@ #include "caffe/layers/pooling_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN @@ -27,8 +31,8 @@ class CuDNNPoolingLayer : public PoolingLayer { const vector*>& top); virtual ~CuDNNPoolingLayer(); // Currently, cuDNN does not support the extra top blob. - virtual inline int MinTopBlobs() const { return -1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp MinTopBlobs() const { return -1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_gpu(const vector*>& bottom, diff --git a/include/caffe/layers/cudnn_relu_layer.hpp b/include/caffe/layers/cudnn_relu_layer.hpp index e01f568abc9..d7014834913 100644 --- a/include/caffe/layers/cudnn_relu_layer.hpp +++ b/include/caffe/layers/cudnn_relu_layer.hpp @@ -10,6 +10,10 @@ #include "caffe/layers/neuron_layer.hpp" #include "caffe/layers/relu_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN diff --git a/include/caffe/layers/cudnn_sigmoid_layer.hpp b/include/caffe/layers/cudnn_sigmoid_layer.hpp index 9c597958b0b..8be8cd2508c 100644 --- a/include/caffe/layers/cudnn_sigmoid_layer.hpp +++ b/include/caffe/layers/cudnn_sigmoid_layer.hpp @@ -10,6 +10,10 @@ #include "caffe/layers/neuron_layer.hpp" #include "caffe/layers/sigmoid_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN diff --git a/include/caffe/layers/cudnn_softmax_layer.hpp b/include/caffe/layers/cudnn_softmax_layer.hpp index 174368e413d..b80b6e8b29c 100644 --- a/include/caffe/layers/cudnn_softmax_layer.hpp +++ b/include/caffe/layers/cudnn_softmax_layer.hpp @@ -9,6 +9,10 @@ #include "caffe/layers/softmax_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN diff --git a/include/caffe/layers/cudnn_tanh_layer.hpp b/include/caffe/layers/cudnn_tanh_layer.hpp index c0f0053f71e..1eaf6612aa9 100644 --- a/include/caffe/layers/cudnn_tanh_layer.hpp +++ b/include/caffe/layers/cudnn_tanh_layer.hpp @@ -10,6 +10,10 @@ #include "caffe/layers/neuron_layer.hpp" #include "caffe/layers/tanh_layer.hpp" +#ifdef USE_CUDNN // cuDNN acceleration library. +#include "caffe/util/cudnn.hpp" +#endif + namespace caffe { #ifdef USE_CUDNN diff --git a/include/caffe/layers/data_layer.hpp b/include/caffe/layers/data_layer.hpp index 6c361791a0c..d76c433b733 100644 --- a/include/caffe/layers/data_layer.hpp +++ b/include/caffe/layers/data_layer.hpp @@ -24,9 +24,9 @@ class DataLayer : public BasePrefetchingDataLayer { // DataLayer uses DataReader instead for sharing for parallelism virtual inline bool ShareInParallel() const { return false; } virtual inline const char* type() const { return "Data"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int MinTopBlobs() const { return 1; } - virtual inline int MaxTopBlobs() const { return 2; } + virtual inline int_tp ExactNumBottomBlobs() const { return 0; } + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlobs() const { return 2; } protected: virtual void load_batch(Batch* batch); diff --git a/include/caffe/layers/dropout_layer.hpp b/include/caffe/layers/dropout_layer.hpp index e83143bc3cc..d12711029ad 100644 --- a/include/caffe/layers/dropout_layer.hpp +++ b/include/caffe/layers/dropout_layer.hpp @@ -66,13 +66,13 @@ class DropoutLayer : public NeuronLayer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - /// when divided by UINT_MAX, the randomly generated values @f$u\sim U(0,1)@f$ - Blob rand_vec_; + /// when divided by uint_MAX, the randomly generated values @f$u\sim U(0,1)@f$ + Blob rand_vec_; /// the probability @f$ p @f$ of dropping any input Dtype threshold_; /// the scale for undropped inputs at train time @f$ 1 / (1 - p) @f$ Dtype scale_; - unsigned int uint_thres_; + uint_tp uint_thres_; }; } // namespace caffe diff --git a/include/caffe/layers/dummy_data_layer.hpp b/include/caffe/layers/dummy_data_layer.hpp index 4180f1d01e4..22ac4cc282c 100644 --- a/include/caffe/layers/dummy_data_layer.hpp +++ b/include/caffe/layers/dummy_data_layer.hpp @@ -29,8 +29,8 @@ class DummyDataLayer : public Layer { const vector*>& top) {} virtual inline const char* type() const { return "DummyData"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int MinTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 0; } + virtual inline int_tp MinTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, diff --git a/include/caffe/layers/eltwise_layer.hpp b/include/caffe/layers/eltwise_layer.hpp index 091de834362..ebd0fbb2ad9 100644 --- a/include/caffe/layers/eltwise_layer.hpp +++ b/include/caffe/layers/eltwise_layer.hpp @@ -26,8 +26,8 @@ class EltwiseLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Eltwise"; } - virtual inline int MinBottomBlobs() const { return 2; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp MinBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -41,7 +41,7 @@ class EltwiseLayer : public Layer { EltwiseParameter_EltwiseOp op_; vector coeffs_; - Blob max_idx_; + Blob max_idx_; bool stable_prod_grad_; }; diff --git a/include/caffe/layers/embed_layer.hpp b/include/caffe/layers/embed_layer.hpp index 36137a625b6..e6c15a66026 100644 --- a/include/caffe/layers/embed_layer.hpp +++ b/include/caffe/layers/embed_layer.hpp @@ -27,8 +27,8 @@ class EmbedLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Embed"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -40,9 +40,9 @@ class EmbedLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int M_; - int K_; - int N_; + int_tp M_; + int_tp K_; + int_tp N_; bool bias_term_; Blob bias_multiplier_; }; diff --git a/include/caffe/layers/euclidean_loss_layer.hpp b/include/caffe/layers/euclidean_loss_layer.hpp index f564569e27a..b51e2cd7d48 100644 --- a/include/caffe/layers/euclidean_loss_layer.hpp +++ b/include/caffe/layers/euclidean_loss_layer.hpp @@ -50,10 +50,14 @@ class EuclideanLossLayer : public LossLayer { * Unlike most loss layers, in the EuclideanLossLayer we can backpropagate * to both inputs -- override to return true and always allow force_backward. */ - virtual inline bool AllowForceBackward(const int bottom_index) const { + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { return true; } + virtual inline int_tp ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { return 2; } + virtual inline int_tp MaxBottomBlobs() const { return 3; } + protected: /// @copydoc EuclideanLossLayer virtual void Forward_cpu(const vector*>& bottom, @@ -102,6 +106,7 @@ class EuclideanLossLayer : public LossLayer { Blob diff_; }; + } // namespace caffe #endif // CAFFE_EUCLIDEAN_LOSS_LAYER_HPP_ diff --git a/include/caffe/layers/filter_layer.hpp b/include/caffe/layers/filter_layer.hpp index e040e66612b..eac80a189cf 100644 --- a/include/caffe/layers/filter_layer.hpp +++ b/include/caffe/layers/filter_layer.hpp @@ -10,7 +10,7 @@ namespace caffe { /** - * @brief Takes two+ Blobs, interprets last Blob as a selector and + * @brief Takes two+ Blobs, int_tperprets last Blob as a selector and * filter remaining Blobs accordingly with selector data (0 means that * the corresponding item has to be filtered, non-zero means that corresponding * item needs to stay). @@ -26,8 +26,8 @@ class FilterLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Filter"; } - virtual inline int MinBottomBlobs() const { return 2; } - virtual inline int MinTopBlobs() const { return 1; } + virtual inline int_tp MinBottomBlobs() const { return 2; } + virtual inline int_tp MinTopBlobs() const { return 1; } protected: /** @@ -60,7 +60,7 @@ class FilterLayer : public Layer { * @param top output Blob vector (length 1+), providing the error gradient with * respect to the outputs * @param propagate_down see Layer::Backward. - * @param bottom input Blob vector (length 2+), into which the top error + * @param bottom input Blob vector (length 2+), int_tpo which the top error * gradient is copied */ virtual void Backward_cpu(const vector*>& top, @@ -69,7 +69,7 @@ class FilterLayer : public Layer { const vector& propagate_down, const vector*>& bottom); bool first_reshape_; - vector indices_to_forward_; + vector indices_to_forward_; }; } // namespace caffe diff --git a/include/caffe/layers/flatten_layer.hpp b/include/caffe/layers/flatten_layer.hpp index e494bbb588f..86d9f3e691e 100644 --- a/include/caffe/layers/flatten_layer.hpp +++ b/include/caffe/layers/flatten_layer.hpp @@ -10,13 +10,13 @@ namespace caffe { /** - * @brief Reshapes the input Blob into flat vectors. + * @brief Reshapes the input Blob int_tpo flat vectors. * * Note: because this layer does not change the input values -- merely the * dimensions -- it can simply copy the input. The copy happens "virtually" * (thus taking effectively 0 real time) by setting, in Forward, the data - * pointer of the top Blob to that of the bottom Blob (see Blob::ShareData), - * and in Backward, the diff pointer of the bottom Blob to that of the top Blob + * point_tper of the top Blob to that of the bottom Blob (see Blob::ShareData), + * and in Backward, the diff point_tper of the bottom Blob to that of the top Blob * (see Blob::ShareDiff). */ template @@ -28,8 +28,8 @@ class FlattenLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Flatten"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: /** @@ -49,7 +49,7 @@ class FlattenLayer : public Layer { * @param top output Blob vector (length 1), providing the error gradient with * respect to the outputs * @param propagate_down see Layer::Backward. - * @param bottom input Blob vector (length K), into which the top error + * @param bottom input Blob vector (length K), int_tpo which the top error * gradient is (virtually) copied */ virtual void Backward_cpu(const vector*>& top, diff --git a/include/caffe/layers/hdf5_data_layer.hpp b/include/caffe/layers/hdf5_data_layer.hpp index b04cf8e1940..5bd94b69c77 100644 --- a/include/caffe/layers/hdf5_data_layer.hpp +++ b/include/caffe/layers/hdf5_data_layer.hpp @@ -34,8 +34,8 @@ class HDF5DataLayer : public Layer { const vector*>& top) {} virtual inline const char* type() const { return "HDF5Data"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int MinTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 0; } + virtual inline int_tp MinTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -49,12 +49,12 @@ class HDF5DataLayer : public Layer { virtual void LoadHDF5FileData(const char* filename); std::vector hdf_filenames_; - unsigned int num_files_; - unsigned int current_file_; + uint_tp num_files_; + uint_tp current_file_; hsize_t current_row_; std::vector > > hdf_blobs_; - std::vector data_permutation_; - std::vector file_permutation_; + std::vector data_permutation_; + std::vector file_permutation_; }; } // namespace caffe diff --git a/include/caffe/layers/hdf5_output_layer.hpp b/include/caffe/layers/hdf5_output_layer.hpp index 487d08fc06c..5d547347894 100644 --- a/include/caffe/layers/hdf5_output_layer.hpp +++ b/include/caffe/layers/hdf5_output_layer.hpp @@ -36,8 +36,8 @@ class HDF5OutputLayer : public Layer { virtual inline const char* type() const { return "HDF5Output"; } // TODO: no limit on the number of blobs - virtual inline int ExactNumBottomBlobs() const { return 2; } - virtual inline int ExactNumTopBlobs() const { return 0; } + virtual inline int_tp ExactNumBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumTopBlobs() const { return 0; } inline std::string file_name() const { return file_name_; } diff --git a/include/caffe/layers/hinge_loss_layer.hpp b/include/caffe/layers/hinge_loss_layer.hpp index 54e42bd44da..df55d229a70 100644 --- a/include/caffe/layers/hinge_loss_layer.hpp +++ b/include/caffe/layers/hinge_loss_layer.hpp @@ -26,7 +26,7 @@ namespace caffe { * HingeLossLayer and no other learnable parameters or losses is * equivalent to an SVM. * -# @f$ (N \times 1 \times 1 \times 1) @f$ - * the labels @f$ l @f$, an integer-valued Blob with values + * the labels @f$ l @f$, an int_tpeger-valued Blob with values * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ * indicating the correct class label among the @f$ K @f$ classes * @param top output Blob vector (length 1) diff --git a/include/caffe/layers/im2col_layer.hpp b/include/caffe/layers/im2col_layer.hpp index 71e32f7427f..07726547caa 100644 --- a/include/caffe/layers/im2col_layer.hpp +++ b/include/caffe/layers/im2col_layer.hpp @@ -10,7 +10,7 @@ namespace caffe { /** - * @brief A helper for image operations that rearranges image regions into + * @brief A helper for image operations that rearranges image regions int_tpo * column vectors. Used by ConvolutionLayer to perform convolution * by matrix multiplication. * @@ -27,8 +27,8 @@ class Im2colLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Im2col"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -41,21 +41,21 @@ class Im2colLayer : public Layer { const vector& propagate_down, const vector*>& bottom); /// @brief The spatial dimensions of a filter kernel. - Blob kernel_shape_; + Blob kernel_shape_; /// @brief The spatial dimensions of the stride. - Blob stride_; + Blob stride_; /// @brief The spatial dimensions of the padding. - Blob pad_; + Blob pad_; /// @brief The spatial dimensions of the dilation. - Blob dilation_; + Blob dilation_; - int num_spatial_axes_; - int bottom_dim_; - int top_dim_; + int_tp num_spatial_axes_; + int_tp bottom_dim_; + int_tp top_dim_; - int channel_axis_; - int num_; - int channels_; + int_tp channel_axis_; + int_tp num_; + int_tp channels_; bool force_nd_im2col_; }; diff --git a/include/caffe/layers/image_data_layer.hpp b/include/caffe/layers/image_data_layer.hpp index a0d3384e4c9..58d2fce9ac6 100644 --- a/include/caffe/layers/image_data_layer.hpp +++ b/include/caffe/layers/image_data_layer.hpp @@ -29,16 +29,16 @@ class ImageDataLayer : public BasePrefetchingDataLayer { const vector*>& top); virtual inline const char* type() const { return "ImageData"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int ExactNumTopBlobs() const { return 2; } + virtual inline int_tp ExactNumBottomBlobs() const { return 0; } + virtual inline int_tp ExactNumTopBlobs() const { return 2; } protected: shared_ptr prefetch_rng_; virtual void ShuffleImages(); virtual void load_batch(Batch* batch); - vector > lines_; - int lines_id_; + vector > lines_; + int_tp lines_id_; }; diff --git a/include/caffe/layers/infogain_loss_layer.hpp b/include/caffe/layers/infogain_loss_layer.hpp index 633f339a28e..b42e7813107 100644 --- a/include/caffe/layers/infogain_loss_layer.hpp +++ b/include/caffe/layers/infogain_loss_layer.hpp @@ -27,7 +27,7 @@ namespace caffe { * should sum to 1 as in a probability distribution: @f$ * \forall n \sum\limits_{k=1}^K \hat{p}_{nk} = 1 @f$. * -# @f$ (N \times 1 \times 1 \times 1) @f$ - * the labels @f$ l @f$, an integer-valued Blob with values + * the labels @f$ l @f$, an int_tpeger-valued Blob with values * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ * indicating the correct class label among the @f$ K @f$ classes * -# @f$ (1 \times 1 \times K \times K) @f$ @@ -56,9 +56,9 @@ class InfogainLossLayer : public LossLayer { // InfogainLossLayer takes 2-3 bottom Blobs; if there are 3 the third should // be the infogain matrix. (Otherwise the infogain matrix is loaded from a // file specified by LayerParameter.) - virtual inline int ExactNumBottomBlobs() const { return -1; } - virtual inline int MinBottomBlobs() const { return 2; } - virtual inline int MaxBottomBlobs() const { return 3; } + virtual inline int_tp ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { return 2; } + virtual inline int_tp MaxBottomBlobs() const { return 3; } virtual inline const char* type() const { return "InfogainLoss"; } diff --git a/include/caffe/layers/inner_product_layer.hpp b/include/caffe/layers/inner_product_layer.hpp index 250576a4817..90903e5eebc 100644 --- a/include/caffe/layers/inner_product_layer.hpp +++ b/include/caffe/layers/inner_product_layer.hpp @@ -26,8 +26,8 @@ class InnerProductLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "InnerProduct"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -39,9 +39,9 @@ class InnerProductLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int M_; - int K_; - int N_; + int_tp M_; + int_tp K_; + int_tp N_; bool bias_term_; Blob bias_multiplier_; }; diff --git a/include/caffe/layers/loss_layer.hpp b/include/caffe/layers/loss_layer.hpp index dbdf612c062..caab7ba662c 100644 --- a/include/caffe/layers/loss_layer.hpp +++ b/include/caffe/layers/loss_layer.hpp @@ -12,7 +12,7 @@ namespace caffe { const float kLOG_THRESHOLD = 1e-20; /** - * @brief An interface for Layer%s that take two Blob%s as input -- usually + * @brief An int_tperface for Layer%s that take two Blob%s as input -- usually * (1) predictions and (2) ground-truth labels -- and output a * singleton Blob representing the loss. * @@ -29,21 +29,21 @@ class LossLayer : public Layer { virtual void Reshape( const vector*>& bottom, const vector*>& top); - virtual inline int ExactNumBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumBottomBlobs() const { return 2; } /** * @brief For convenience and backwards compatibility, instruct the Net to - * automatically allocate a single top Blob for LossLayers, into which + * automatically allocate a single top Blob for LossLayers, int_tpo which * they output their singleton loss, (even if the user didn't specify * one in the prototxt, etc.). */ virtual inline bool AutoTopBlobs() const { return true; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } /** * We usually cannot backpropagate to the labels; ignore force_backward for * these inputs. */ - virtual inline bool AllowForceBackward(const int bottom_index) const { + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { return bottom_index != 1; } }; diff --git a/include/caffe/layers/lrn_layer.hpp b/include/caffe/layers/lrn_layer.hpp index 06cf71a94cb..eb4a1a31304 100644 --- a/include/caffe/layers/lrn_layer.hpp +++ b/include/caffe/layers/lrn_layer.hpp @@ -30,8 +30,8 @@ class LRNLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "LRN"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -56,18 +56,18 @@ class LRNLayer : public Layer { virtual void WithinChannelBackward(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int size_; - int pre_pad_; + int_tp size_; + int_tp pre_pad_; Dtype alpha_; Dtype beta_; Dtype k_; - int num_; - int channels_; - int height_; - int width_; + int_tp num_; + int_tp channels_; + int_tp height_; + int_tp width_; // Fields used for normalization ACROSS_CHANNELS - // scale_ stores the intermediate summing results + // scale_ stores the int_tpermediate summing results Blob scale_; // Fields used for normalization WITHIN_CHANNEL diff --git a/include/caffe/layers/malis_loss_layer.hpp b/include/caffe/layers/malis_loss_layer.hpp new file mode 100644 index 00000000000..ab2b8623fb1 --- /dev/null +++ b/include/caffe/layers/malis_loss_layer.hpp @@ -0,0 +1,60 @@ +#ifndef CAFFE_MALIS_LOSS_LAYER_HPP_ +#define CAFFE_MALIS_LOSS_LAYER_HPP_ + +#include + +#include "caffe/blob.hpp" +#include "caffe/layer.hpp" +#include "caffe/layers/loss_layer.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + + +template +class MalisLossLayer : public LossLayer { + public: + explicit MalisLossLayer(const LayerParameter& param) + : LossLayer(param) {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "MalisLoss"; } + virtual inline int_tp ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { return 3; } + virtual inline int_tp MaxBottomBlobs() const { return 4; } + virtual inline int_tp ExactNumTopBlobs() const { return -1; } + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlobs() const { return 2; } + + protected: + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + private: + void Malis(const Dtype* conn_data, const int_tp conn_num_dims, + const int_tp* conn_dims, + const int_tp* nhood_data, const int_tp* nhood_dims, + const Dtype* seg_data, + const bool pos, Dtype* dloss_data, Dtype* loss_out, + Dtype *classerr_out, Dtype *rand_index_out); + + int_tp nedges_; + int_tp conn_num_dims_; + std::vector conn_dims_; + std::vector nhood_data_; + std::vector nhood_dims_; + + Blob affinity_pos_; + Blob affinity_neg_; + Blob dloss_pos_; + Blob dloss_neg_; +}; + +} // namespace caffe + +#endif // CAFFE_MALIS_LOSS_LAYER_HPP_ diff --git a/include/caffe/layers/memory_data_layer.hpp b/include/caffe/layers/memory_data_layer.hpp index 8abcc8c1b68..c13e814b0f6 100644 --- a/include/caffe/layers/memory_data_layer.hpp +++ b/include/caffe/layers/memory_data_layer.hpp @@ -25,34 +25,39 @@ class MemoryDataLayer : public BaseDataLayer { const vector*>& top); virtual inline const char* type() const { return "MemoryData"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int ExactNumTopBlobs() const { return 2; } + virtual inline int_tp ExactNumBottomBlobs() const { return 0; } + virtual inline int_tp ExactNumTopBlobs() const { return 2; } virtual void AddDatumVector(const vector& datum_vector); #ifdef USE_OPENCV virtual void AddMatVector(const vector& mat_vector, - const vector& labels); + const vector& labels); #endif // USE_OPENCV // Reset should accept const pointers, but can't, because the memory // will be given to Blob, which is mutable - void Reset(Dtype* data, Dtype* label, int n); - void set_batch_size(int new_size); + void Reset(Dtype* data, Dtype* label, int_tp n); + void set_batch_size(int_tp new_size); - int batch_size() { return batch_size_; } - int channels() { return channels_; } - int height() { return height_; } - int width() { return width_; } + vector shape() { return shape_; } + vector label_shape() { return label_shape_; } + int_tp batch_size() { return shape_[0]; } + int_tp channels() { return shape_[1]; } + int_tp height() { return shape_[2]; } + int_tp width() { return shape_[3]; } protected: virtual void Forward_cpu(const vector*>& bottom, const vector*>& top); - int batch_size_, channels_, height_, width_, size_; + vector shape_; + vector label_shape_; + int_tp size_; + Dtype* data_; Dtype* labels_; - int n_; - size_t pos_; + int_tp n_; + uint_tp pos_; Blob added_data_; Blob added_label_; bool has_new_data_; diff --git a/include/caffe/layers/mergecrop_layer.hpp b/include/caffe/layers/mergecrop_layer.hpp new file mode 100644 index 00000000000..90ea470e230 --- /dev/null +++ b/include/caffe/layers/mergecrop_layer.hpp @@ -0,0 +1,58 @@ +#ifndef CAFFE_MERGECROP_LAYER_HPP_ +#define CAFFE_MERGECROP_LAYER_HPP_ + +#include + +#include "caffe/blob.hpp" +#include "caffe/layer.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + + +/** + * @brief Merges and crops feature maps for U-Net architectures. + */ +template +class MergeCropLayer : public Layer { + public: + explicit MergeCropLayer(const LayerParameter& param) + : Layer(param) { + } + + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline int_tp ExactNumBottomBlobs() const { + return 2; + } + + virtual inline const char* type() const { + return "MergeCrop"; + } + + protected: + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Forward_gpu(const vector*>& bottom, + const vector*>& top); + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom); + virtual void Backward_gpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom); + + private: + vector forward_; + vector backward_; + Blob shape_a_; + Blob shape_b_; +}; + +} // namespace caffe + +#endif // CAFFE_MERGECROP_LAYER_HPP_ diff --git a/include/caffe/layers/multinomial_logistic_loss_layer.hpp b/include/caffe/layers/multinomial_logistic_loss_layer.hpp index 3977cf9ea57..bacca16ae6d 100644 --- a/include/caffe/layers/multinomial_logistic_loss_layer.hpp +++ b/include/caffe/layers/multinomial_logistic_loss_layer.hpp @@ -31,7 +31,7 @@ namespace caffe { * should sum to 1 as in a probability distribution: @f$ * \forall n \sum\limits_{k=1}^K \hat{p}_{nk} = 1 @f$. * -# @f$ (N \times 1 \times 1 \times 1) @f$ - * the labels @f$ l @f$, an integer-valued Blob with values + * the labels @f$ l @f$, an int_tpeger-valued Blob with values * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ * indicating the correct class label among the @f$ K @f$ classes * @param top output Blob vector (length 1) diff --git a/include/caffe/layers/mvn_layer.hpp b/include/caffe/layers/mvn_layer.hpp index 3a235ceca64..3962e4a3f30 100644 --- a/include/caffe/layers/mvn_layer.hpp +++ b/include/caffe/layers/mvn_layer.hpp @@ -23,8 +23,8 @@ class MVNLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "MVN"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, diff --git a/include/caffe/layers/neuron_layer.hpp b/include/caffe/layers/neuron_layer.hpp index 10c108ce682..77b208a8d3b 100644 --- a/include/caffe/layers/neuron_layer.hpp +++ b/include/caffe/layers/neuron_layer.hpp @@ -10,7 +10,7 @@ namespace caffe { /** - * @brief An interface for layers that take one blob as input (@f$ x @f$) + * @brief An int_tperface for layers that take one blob as input (@f$ x @f$) * and produce one equally-sized blob as output (@f$ y @f$), where * each element of the output depends only on the corresponding input * element. @@ -23,8 +23,8 @@ class NeuronLayer : public Layer { virtual void Reshape(const vector*>& bottom, const vector*>& top); - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } }; } // namespace caffe diff --git a/include/caffe/layers/pooling_layer.hpp b/include/caffe/layers/pooling_layer.hpp index f4d6803ba8e..e207f73743b 100644 --- a/include/caffe/layers/pooling_layer.hpp +++ b/include/caffe/layers/pooling_layer.hpp @@ -12,47 +12,66 @@ namespace caffe { /** * @brief Pools the input image by taking the max, average, etc. within regions. * - * TODO(dox): thorough documentation for Forward, Backward, and proto params. + * For whole image processing, reducing redundancy. */ -template +template class PoolingLayer : public Layer { public: explicit PoolingLayer(const LayerParameter& param) - : Layer(param) {} + : Layer(param) { + } virtual void LayerSetUp(const vector*>& bottom, - const vector*>& top); + const vector*>& top); virtual void Reshape(const vector*>& bottom, - const vector*>& top); - - virtual inline const char* type() const { return "Pooling"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int MinTopBlobs() const { return 1; } - // MAX POOL layers can output an extra top blob for the mask; - // others can only output the pooled inputs. - virtual inline int MaxTopBlobs() const { - return (this->layer_param_.pooling_param().pool() == - PoolingParameter_PoolMethod_MAX) ? 2 : 1; - } + const vector*>& top); protected: virtual void Forward_cpu(const vector*>& bottom, - const vector*>& top); + const vector*>& top); virtual void Forward_gpu(const vector*>& bottom, - const vector*>& top); + const vector*>& top); virtual void Backward_cpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom); + const vector& propagate_down, + const vector*>& bottom); virtual void Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom); - - int kernel_h_, kernel_w_; - int stride_h_, stride_w_; - int pad_h_, pad_w_; - int channels_; - int height_, width_; - int pooled_height_, pooled_width_; + const vector& propagate_down, + const vector*>& bottom); + + virtual inline const char* type() const { + return "Pooling"; + } + virtual inline int_tp ExactNumBottomBlobs() const { + return 1; + } + virtual inline int_tp MinTopBlobs() const { + return 1; + } + // MAX POOL layers can output an extra top blob for the mask; + // others can only output the pooled inputs. + virtual inline int_tp MaxTopBlobs() const { + return + (this->layer_param_.pooling_param().pool() + == PoolingParameter_PoolMethod_MAX) ? 2 : 1; + } + + Blob kernel_shape_; + Blob ext_kernel_shape_; + Blob stride_; + Blob pad_; + Blob dilation_; + Blob size_; + Blob pooled_size_; + + int_tp channel_axis_; + int_tp num_spatial_axes_; + int_tp channels_; + + bool use_skernel_; bool global_pooling_; + + int_tp max_top_blobs_; Blob rand_idx_; - Blob max_idx_; + Blob max_idx_; }; } // namespace caffe diff --git a/include/caffe/layers/reduction_layer.hpp b/include/caffe/layers/reduction_layer.hpp index 804a495b11c..61da99bf8e4 100644 --- a/include/caffe/layers/reduction_layer.hpp +++ b/include/caffe/layers/reduction_layer.hpp @@ -27,8 +27,8 @@ class ReductionLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Reduction"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -45,11 +45,11 @@ class ReductionLayer : public Layer { /// @brief a scalar coefficient applied to all outputs Dtype coeff_; /// @brief the index of the first input axis to reduce - int axis_; + int_tp axis_; /// @brief the number of reductions performed - int num_; + int_tp num_; /// @brief the input size of each reduction - int dim_; + int_tp dim_; /// @brief a helper Blob used for summation (op_ == SUM) Blob sum_multiplier_; }; diff --git a/include/caffe/layers/reshape_layer.hpp b/include/caffe/layers/reshape_layer.hpp index d11e06384ce..0a77ed3c8bb 100644 --- a/include/caffe/layers/reshape_layer.hpp +++ b/include/caffe/layers/reshape_layer.hpp @@ -10,7 +10,7 @@ namespace caffe { /* - * @brief Reshapes the input Blob into an arbitrary-sized output Blob. + * @brief Reshapes the input Blob int_tpo an arbitrary-sized output Blob. * * Note: similarly to FlattenLayer, this layer does not change the input values * (see FlattenLayer, Blob::ShareData and Blob::ShareDiff). @@ -26,8 +26,8 @@ class ReshapeLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Reshape"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -40,11 +40,11 @@ class ReshapeLayer : public Layer { const vector& propagate_down, const vector*>& bottom) {} /// @brief vector of axes indices whose dimensions we'll copy from the bottom - vector copy_axes_; + vector copy_axes_; /// @brief the index of the axis whose dimension we infer, or -1 if none - int inferred_axis_; + int_tp inferred_axis_; /// @brief the product of the "constant" output dimensions - int constant_count_; + int_tp constant_count_; }; } // namespace caffe diff --git a/include/caffe/layers/scale_layer.hpp b/include/caffe/layers/scale_layer.hpp index 924df2e51ab..a4675182ef3 100644 --- a/include/caffe/layers/scale_layer.hpp +++ b/include/caffe/layers/scale_layer.hpp @@ -32,9 +32,9 @@ class ScaleLayer: public Layer { virtual inline const char* type() const { return "Scale"; } // Scale - virtual inline int MinBottomBlobs() const { return 1; } - virtual inline int MaxBottomBlobs() const { return 2; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp MinBottomBlobs() const { return 1; } + virtual inline int_tp MaxBottomBlobs() const { return 2; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: /** @@ -68,13 +68,13 @@ class ScaleLayer: public Layer { shared_ptr > bias_layer_; vector*> bias_bottom_vec_; vector bias_propagate_down_; - int bias_param_id_; + int_tp bias_param_id_; Blob sum_multiplier_; Blob sum_result_; Blob temp_; - int axis_; - int outer_dim_, scale_dim_, inner_dim_; + int_tp axis_; + int_tp outer_dim_, scale_dim_, inner_dim_; }; diff --git a/include/caffe/layers/sigmoid_cross_entropy_loss_layer.hpp b/include/caffe/layers/sigmoid_cross_entropy_loss_layer.hpp index 598dca5ff2c..ebc8f20ee8b 100644 --- a/include/caffe/layers/sigmoid_cross_entropy_loss_layer.hpp +++ b/include/caffe/layers/sigmoid_cross_entropy_loss_layer.hpp @@ -18,7 +18,7 @@ namespace caffe { * p_n \log \hat{p}_n + * (1 - p_n) \log(1 - \hat{p}_n) * \right] - * @f$, often used for predicting targets interpreted as probabilities. + * @f$, often used for predicting targets int_tperpreted as probabilities. * * This layer is implemented rather than separate * SigmoidLayer + CrossEntropyLayer @@ -95,7 +95,7 @@ class SigmoidCrossEntropyLossLayer : public LossLayer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - /// The internal SigmoidLayer used to map predictions to probabilities. + /// The int_tpernal SigmoidLayer used to map predictions to probabilities. shared_ptr > sigmoid_layer_; /// sigmoid_output stores the output of the SigmoidLayer. shared_ptr > sigmoid_output_; diff --git a/include/caffe/layers/silence_layer.hpp b/include/caffe/layers/silence_layer.hpp index fba087fcef0..646f65ebfa2 100644 --- a/include/caffe/layers/silence_layer.hpp +++ b/include/caffe/layers/silence_layer.hpp @@ -22,8 +22,8 @@ class SilenceLayer : public Layer { const vector*>& top) {} virtual inline const char* type() const { return "Silence"; } - virtual inline int MinBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 0; } + virtual inline int_tp MinBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 0; } protected: virtual void Forward_cpu(const vector*>& bottom, diff --git a/include/caffe/layers/slice_layer.hpp b/include/caffe/layers/slice_layer.hpp index 10a0abb6eeb..9c1c8dcd95e 100644 --- a/include/caffe/layers/slice_layer.hpp +++ b/include/caffe/layers/slice_layer.hpp @@ -26,8 +26,8 @@ class SliceLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Slice"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int MinTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp MinTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -39,11 +39,11 @@ class SliceLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int count_; - int num_slices_; - int slice_size_; - int slice_axis_; - vector slice_point_; + int_tp count_; + int_tp num_slices_; + int_tp slice_size_; + int_tp slice_axis_; + vector slice_point_; }; } // namespace caffe diff --git a/include/caffe/layers/softmax_layer.hpp b/include/caffe/layers/softmax_layer.hpp index c65b8703e43..a26700d8269 100644 --- a/include/caffe/layers/softmax_layer.hpp +++ b/include/caffe/layers/softmax_layer.hpp @@ -23,8 +23,8 @@ class SoftmaxLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Softmax"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -36,12 +36,12 @@ class SoftmaxLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int outer_num_; - int inner_num_; - int softmax_axis_; + int_tp outer_num_; + int_tp inner_num_; + int_tp softmax_axis_; /// sum_multiplier is used to carry out sum using BLAS Blob sum_multiplier_; - /// scale is an intermediate Blob to hold temporary results. + /// scale is an int_tpermediate Blob to hold temporary results. Blob scale_; }; diff --git a/include/caffe/layers/softmax_loss_layer.hpp b/include/caffe/layers/softmax_loss_layer.hpp index f07e8a02cf1..71213d90048 100644 --- a/include/caffe/layers/softmax_loss_layer.hpp +++ b/include/caffe/layers/softmax_loss_layer.hpp @@ -31,7 +31,7 @@ namespace caffe { * @f$ \hat{p}_{nk} = \exp(x_{nk}) / * \left[\sum_{k'} \exp(x_{nk'})\right] @f$ (see SoftmaxLayer). * -# @f$ (N \times 1 \times 1 \times 1) @f$ - * the labels @f$ l @f$, an integer-valued Blob with values + * the labels @f$ l @f$, an int_tpeger-valued Blob with values * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ * indicating the correct class label among the @f$ K @f$ classes * @param top output Blob vector (length 1) @@ -59,9 +59,9 @@ class SoftmaxWithLossLayer : public LossLayer { const vector*>& top); virtual inline const char* type() const { return "SoftmaxWithLoss"; } - virtual inline int ExactNumTopBlobs() const { return -1; } - virtual inline int MinTopBlobs() const { return 1; } - virtual inline int MaxTopBlobs() const { return 2; } + virtual inline int_tp ExactNumTopBlobs() const { return -1; } + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlobs() const { return 2; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -105,9 +105,9 @@ class SoftmaxWithLossLayer : public LossLayer { /// outputs will be read from valid_count, unless it is -1 in which case /// all outputs are assumed to be valid. virtual Dtype get_normalizer( - LossParameter_NormalizationMode normalization_mode, int valid_count); + LossParameter_NormalizationMode normalization_mode, int_tp valid_count); - /// The internal SoftmaxLayer used to map predictions to a distribution. + /// The int_tpernal SoftmaxLayer used to map predictions to a distribution. shared_ptr > softmax_layer_; /// prob stores the output probability predictions from the SoftmaxLayer. Blob prob_; @@ -118,11 +118,11 @@ class SoftmaxWithLossLayer : public LossLayer { /// Whether to ignore instances with a certain label. bool has_ignore_label_; /// The label indicating that an instance should be ignored. - int ignore_label_; + int_tp ignore_label_; /// How to normalize the output loss. LossParameter_NormalizationMode normalization_; - int softmax_axis_, outer_num_, inner_num_; + int_tp softmax_axis_, outer_num_, inner_num_; }; } // namespace caffe diff --git a/include/caffe/layers/split_layer.hpp b/include/caffe/layers/split_layer.hpp index 8140dfc7c40..8df9605fb2d 100644 --- a/include/caffe/layers/split_layer.hpp +++ b/include/caffe/layers/split_layer.hpp @@ -11,7 +11,7 @@ namespace caffe { /** * @brief Creates a "split" path in the network by copying the bottom Blob - * into multiple top Blob%s to be used by multiple consuming layers. + * int_tpo multiple top Blob%s to be used by multiple consuming layers. * * TODO(dox): thorough documentation for Forward, Backward, and proto params. */ @@ -24,8 +24,8 @@ class SplitLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Split"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int MinTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp MinTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -37,7 +37,7 @@ class SplitLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - int count_; + int_tp count_; }; } // namespace caffe diff --git a/include/caffe/layers/spp_layer.hpp b/include/caffe/layers/spp_layer.hpp index 9f145cc77e3..20f3ed188bd 100644 --- a/include/caffe/layers/spp_layer.hpp +++ b/include/caffe/layers/spp_layer.hpp @@ -26,8 +26,8 @@ class SPPLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "SPP"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -36,30 +36,32 @@ class SPPLayer : public Layer { const vector& propagate_down, const vector*>& bottom); // calculates the kernel and stride dimensions for the pooling layer, // returns a correctly configured LayerParameter for a PoolingLayer - virtual LayerParameter GetPoolingParam(const int pyramid_level, - const int bottom_h, const int bottom_w, const SPPParameter spp_param); + virtual LayerParameter GetPoolingParam(const int_tp pyramid_level, + const int_tp bottom_h, + const int_tp bottom_w, + const SPPParameter spp_param); - int pyramid_height_; - int bottom_h_, bottom_w_; - int num_; - int channels_; - int kernel_h_, kernel_w_; - int pad_h_, pad_w_; + int_tp pyramid_height_; + int_tp bottom_h_, bottom_w_; + int_tp num_; + int_tp channels_; + int_tp kernel_h_, kernel_w_; + int_tp pad_h_, pad_w_; bool reshaped_first_time_; - /// the internal Split layer that feeds the pooling layers + /// the int_tpernal Split layer that feeds the pooling layers shared_ptr > split_layer_; /// top vector holder used in call to the underlying SplitLayer::Forward vector*> split_top_vec_; /// bottom vector holder used in call to the underlying PoolingLayer::Forward vector*>*> pooling_bottom_vecs_; - /// the internal Pooling layers of different kernel sizes + /// the int_tpernal Pooling layers of different kernel sizes vector > > pooling_layers_; /// top vector holders used in call to the underlying PoolingLayer::Forward vector*>*> pooling_top_vecs_; /// pooling_outputs stores the outputs of the PoolingLayers vector*> pooling_outputs_; - /// the internal Flatten layers that the Pooling layers feed into + /// the int_tpernal Flatten layers that the Pooling layers feed int_tpo vector*> flatten_layers_; /// top vector holders used in call to the underlying FlattenLayer::Forward vector*>*> flatten_top_vecs_; @@ -67,7 +69,7 @@ class SPPLayer : public Layer { vector*> flatten_outputs_; /// bottom vector holder used in call to the underlying ConcatLayer::Forward vector*> concat_bottom_vec_; - /// the internal Concat layers that the Flatten layers feed into + /// the int_tpernal Concat layers that the Flatten layers feed int_tpo shared_ptr > concat_layer_; }; diff --git a/include/caffe/layers/tile_layer.hpp b/include/caffe/layers/tile_layer.hpp index fbdbe2f0c53..8543d3835c8 100644 --- a/include/caffe/layers/tile_layer.hpp +++ b/include/caffe/layers/tile_layer.hpp @@ -21,8 +21,8 @@ class TileLayer : public Layer { const vector*>& top); virtual inline const char* type() const { return "Tile"; } - virtual inline int ExactNumBottomBlobs() const { return 1; } - virtual inline int ExactNumTopBlobs() const { return 1; } + virtual inline int_tp ExactNumBottomBlobs() const { return 1; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } protected: virtual void Forward_cpu(const vector*>& bottom, @@ -35,7 +35,7 @@ class TileLayer : public Layer { virtual void Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom); - unsigned int axis_, tiles_, outer_dim_, inner_dim_; + uint_tp axis_, tiles_, outer_dim_, inner_dim_; }; } // namespace caffe diff --git a/include/caffe/layers/window_data_layer.hpp b/include/caffe/layers/window_data_layer.hpp index 35f41b80e63..311be6149f5 100644 --- a/include/caffe/layers/window_data_layer.hpp +++ b/include/caffe/layers/window_data_layer.hpp @@ -30,15 +30,15 @@ class WindowDataLayer : public BasePrefetchingDataLayer { const vector*>& top); virtual inline const char* type() const { return "WindowData"; } - virtual inline int ExactNumBottomBlobs() const { return 0; } - virtual inline int ExactNumTopBlobs() const { return 2; } + virtual inline int_tp ExactNumBottomBlobs() const { return 0; } + virtual inline int_tp ExactNumTopBlobs() const { return 2; } protected: - virtual unsigned int PrefetchRand(); + virtual uint_tp PrefetchRand(); virtual void load_batch(Batch* batch); shared_ptr prefetch_rng_; - vector > > image_database_; + vector > > image_database_; enum WindowField { IMAGE_INDEX, LABEL, OVERLAP, X1, Y1, X2, Y2, NUM }; vector > fg_windows_; vector > bg_windows_; diff --git a/include/caffe/loss_layers.hpp b/include/caffe/loss_layers.hpp new file mode 100644 index 00000000000..a7ec57175bd --- /dev/null +++ b/include/caffe/loss_layers.hpp @@ -0,0 +1,828 @@ +#ifndef CAFFE_LOSS_LAYERS_HPP_ +#define CAFFE_LOSS_LAYERS_HPP_ + +#include +#include +#include +#include + +#include "caffe/blob.hpp" +#include "caffe/layer.hpp" +#include "caffe/neuron_layers.hpp" +#include "caffe/proto/caffe.pb.h" + +namespace caffe { + +const float kLOG_THRESHOLD = 1e-20; + +/** + * @brief Computes the classification accuracy for a one-of-many + * classification task. + */ +template +class AccuracyLayer : public Layer { + public: + /** + * @param param provides AccuracyParameter accuracy_param, + * with AccuracyLayer options: + * - top_k (\b optional, default 1). + * Sets the maximum rank @f$ k @f$ at which a prediction is considered + * correct. For example, if @f$ k = 5 @f$, a prediction is counted + * correct if the correct label is among the top 5 predicted labels. + */ + explicit AccuracyLayer(const LayerParameter& param) + : Layer(param) {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "Accuracy"; } + virtual inline int_tp ExactNumBottomBlobs() const { return 2; } + + // If there are two top blobs, then the second blob will contain + // accuracies per class. + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlos() const { return 2; } + + protected: + /** + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ x @f$, a Blob with values in + * @f$ [-\infty, +\infty] @f$ indicating the predicted score for each of + * the @f$ K = CHW @f$ classes. Each @f$ x_n @f$ is mapped to a predicted + * label @f$ \hat{l}_n @f$ given by its maximal index: + * @f$ \hat{l}_n = \arg\max\limits_k x_{nk} @f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels @f$ l @f$, an integer-valued Blob with values + * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ + * indicating the correct class label among the @f$ K @f$ classes + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed accuracy: @f$ + * \frac{1}{N} \sum\limits_{n=1}^N \delta\{ \hat{l}_n = l_n \} + * @f$, where @f$ + * \delta\{\mathrm{condition}\} = \left\{ + * \begin{array}{lr} + * 1 & \mbox{if condition} \\ + * 0 & \mbox{otherwise} + * \end{array} \right. + * @f$ + */ + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + + + /// @brief Not implemented -- AccuracyLayer cannot be used as a loss. + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom) { + for (int_tp i = 0; i < propagate_down.size(); ++i) { + if (propagate_down[i]) { NOT_IMPLEMENTED; } + } + } + + int_tp label_axis_, outer_num_, inner_num_; + + int_tp top_k_; + + /// Whether to ignore instances with a certain label. + bool has_ignore_label_; + /// The label indicating that an instance should be ignored. + int_tp ignore_label_; + /// Keeps counts of the number of samples per class. + Blob nums_buffer_; +}; + +/** + * @brief An interface for Layer%s that take two Blob%s as input -- usually + * (1) predictions and (2) ground-truth labels -- and output a + * singleton Blob representing the loss. + * + * LossLayers are typically only capable of backpropagating to their first input + * -- the predictions. + */ +template +class LossLayer : public Layer { + public: + explicit LossLayer(const LayerParameter& param) + : Layer(param) {} + virtual void LayerSetUp( + const vector*>& bottom, const vector*>& top); + virtual void Reshape( + const vector*>& bottom, const vector*>& top); + + virtual inline int_tp ExactNumBottomBlobs() const { return 2; } + + /** + * @brief For convenience and backwards compatibility, instruct the Net to + * automatically allocate a single top Blob for LossLayers, into which + * they output their singleton loss, (even if the user didn't specify + * one in the prototxt, etc.). + */ + virtual inline bool AutoTopBlobs() const { return true; } + virtual inline int_tp ExactNumTopBlobs() const { return 1; } + /** + * We usually cannot backpropagate to the labels; ignore force_backward for + * these inputs. + */ + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { + return bottom_index != 1; + } +}; + +/** + * @brief Computes the contrastive loss @f$ + * E = \frac{1}{2N} \sum\limits_{n=1}^N \left(y\right) d^2 + + * \left(1-y\right) \max \left(margin-d, 0\right)^2 + * @f$ where @f$ + * d = \left| \left| a_n - b_n \right| \right|_2 @f$. This can be + * used to train siamese networks. + * + * @param bottom input Blob vector (length 3) + * -# @f$ (N \times C \times 1 \times 1) @f$ + * the features @f$ a \in [-\infty, +\infty]@f$ + * -# @f$ (N \times C \times 1 \times 1) @f$ + * the features @f$ b \in [-\infty, +\infty]@f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the binary similarity @f$ s \in [0, 1]@f$ + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed contrastive loss: @f$ E = + * \frac{1}{2N} \sum\limits_{n=1}^N \left(y\right) d^2 + + * \left(1-y\right) \max \left(margin-d, 0\right)^2 + * @f$ where @f$ + * d = \left| \left| a_n - b_n \right| \right|_2 @f$. + * This can be used to train siamese networks. + */ +template +class ContrastiveLossLayer : public LossLayer { + public: + explicit ContrastiveLossLayer(const LayerParameter& param) + : LossLayer(param), diff_() {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + + virtual inline int_tp ExactNumBottomBlobs() const { return 3; } + virtual inline const char* type() const { return "ContrastiveLoss"; } + /** + * Unlike most loss layers, in the ContrastiveLossLayer we can backpropagate + * to the first two inputs. + */ + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { + return bottom_index != 2; + } + + protected: + /// @copydoc ContrastiveLossLayer + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Forward_gpu(const vector*>& bottom, + const vector*>& top); + + /** + * @brief Computes the Contrastive error gradient w.r.t. the inputs. + * + * Computes the gradients with respect to the two input vectors (bottom[0] and + * bottom[1]), but not the similarity label (bottom[2]). + * + * @param top output Blob vector (length 1), providing the error gradient with + * respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times 1 \times 1) @f$ + * the features @f$a@f$; Backward fills their diff with + * gradients if propagate_down[0] + * -# @f$ (N \times C \times 1 \times 1) @f$ + * the features @f$b@f$; Backward fills their diff with gradients if + * propagate_down[1] + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + virtual void Backward_gpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + Blob diff_; // cached for backward pass + Blob dist_sq_; // cached for backward pass + Blob diff_sq_; // tmp storage for gpu forward pass + Blob summer_vec_; // tmp storage for gpu forward pass +}; + +/** + * @brief Computes the Euclidean (L2) loss @f$ + * E = \frac{1}{2N} \sum\limits_{n=1}^N \left| \left| \hat{y}_n - y_n + * \right| \right|_2^2 @f$ for real-valued regression tasks. + * + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ \hat{y} \in [-\infty, +\infty]@f$ + * -# @f$ (N \times C \times H \times W) @f$ + * the targets @f$ y \in [-\infty, +\infty]@f$ + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed Euclidean loss: @f$ E = + * \frac{1}{2n} \sum\limits_{n=1}^N \left| \left| \hat{y}_n - y_n + * \right| \right|_2^2 @f$ + * + * This can be used for least-squares regression tasks. An InnerProductLayer + * input to a EuclideanLossLayer exactly formulates a linear least squares + * regression problem. With non-zero weight decay the problem becomes one of + * ridge regression -- see src/caffe/test/test_sgd_solver.cpp for a concrete + * example wherein we check that the gradients computed for a Net with exactly + * this structure match hand-computed gradient formulas for ridge regression. + * + * (Note: Caffe, and SGD in general, is certainly \b not the best way to solve + * linear least squares problems! We use it only as an instructive example.) + */ +template +class EuclideanLossLayer : public LossLayer { + public: + explicit EuclideanLossLayer(const LayerParameter& param) + : LossLayer(param), diff_() {} + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "EuclideanLoss"; } + /** + * Unlike most loss layers, in the EuclideanLossLayer we can backpropagate + * to both inputs -- override to return true and always allow force_backward. + */ + virtual inline bool AllowForceBackward(const int_tp bottom_index) const { + return true; + } + + virtual inline int_tp ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { return 2; } + virtual inline int_tp MaxBottomBlobs() const { return 3; } + + protected: + /// @copydoc EuclideanLossLayer + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Forward_gpu(const vector*>& bottom, + const vector*>& top); + + /** + * @brief Computes the Euclidean error gradient w.r.t. the inputs. + * + * Unlike other children of LossLayer, EuclideanLossLayer \b can compute + * gradients with respect to the label inputs bottom[1] (but still only will + * if propagate_down[1] is set, due to being produced by learnable parameters + * or if force_backward is set). In fact, this layer is "commutative" -- the + * result is the same regardless of the order of the two bottoms. + * + * @param top output Blob vector (length 1), providing the error gradient with + * respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$\hat{y}@f$; Backward fills their diff with + * gradients @f$ + * \frac{\partial E}{\partial \hat{y}} = + * \frac{1}{n} \sum\limits_{n=1}^N (\hat{y}_n - y_n) + * @f$ if propagate_down[0] + * -# @f$ (N \times C \times H \times W) @f$ + * the targets @f$y@f$; Backward fills their diff with gradients + * @f$ \frac{\partial E}{\partial y} = + * \frac{1}{n} \sum\limits_{n=1}^N (y_n - \hat{y}_n) + * @f$ if propagate_down[1] + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + virtual void Backward_gpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + Blob diff_; +}; + +/** + * @brief Computes the hinge loss for a one-of-many classification task. + * + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ t @f$, a Blob with values in + * @f$ [-\infty, +\infty] @f$ indicating the predicted score for each of + * the @f$ K = CHW @f$ classes. In an SVM, @f$ t @f$ is the result of + * taking the inner product @f$ X^T W @f$ of the D-dimensional features + * @f$ X \in \mathcal{R}^{D \times N} @f$ and the learned hyperplane + * parameters @f$ W \in \mathcal{R}^{D \times K} @f$, so a Net with just + * an InnerProductLayer (with num_output = D) providing predictions to a + * HingeLossLayer and no other learnable parameters or losses is + * equivalent to an SVM. + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels @f$ l @f$, an integer-valued Blob with values + * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ + * indicating the correct class label among the @f$ K @f$ classes + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed hinge loss: @f$ E = + * \frac{1}{N} \sum\limits_{n=1}^N \sum\limits_{k=1}^K + * [\max(0, 1 - \delta\{l_n = k\} t_{nk})] ^ p + * @f$, for the @f$ L^p @f$ norm + * (defaults to @f$ p = 1 @f$, the L1 norm; L2 norm, as in L2-SVM, + * is also available), and @f$ + * \delta\{\mathrm{condition}\} = \left\{ + * \begin{array}{lr} + * 1 & \mbox{if condition} \\ + * -1 & \mbox{otherwise} + * \end{array} \right. + * @f$ + * + * In an SVM, @f$ t \in \mathcal{R}^{N \times K} @f$ is the result of taking + * the inner product @f$ X^T W @f$ of the features + * @f$ X \in \mathcal{R}^{D \times N} @f$ + * and the learned hyperplane parameters + * @f$ W \in \mathcal{R}^{D \times K} @f$. So, a Net with just an + * InnerProductLayer (with num_output = @f$k@f$) providing predictions to a + * HingeLossLayer is equivalent to an SVM (assuming it has no other learned + * outside the InnerProductLayer and no other losses outside the + * HingeLossLayer). + */ +template +class HingeLossLayer : public LossLayer { + public: + explicit HingeLossLayer(const LayerParameter& param) + : LossLayer(param) {} + + virtual inline const char* type() const { return "HingeLoss"; } + + protected: + /// @copydoc HingeLossLayer + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + + /** + * @brief Computes the hinge loss error gradient w.r.t. the predictions. + * + * Gradients cannot be computed with respect to the label inputs (bottom[1]), + * so this method ignores bottom[1] and requires !propagate_down[1], crashing + * if propagate_down[1] is set. + * + * @param top output Blob vector (length 1), providing the error gradient with + * respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * propagate_down[1] must be false as we can't compute gradients with + * respect to the labels. + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$t@f$; Backward computes diff + * @f$ \frac{\partial E}{\partial t} @f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels -- ignored as we can't compute their error gradients + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); +}; + +/** + * @brief A generalization of MultinomialLogisticLossLayer that takes an + * "information gain" (infogain) matrix specifying the "value" of all label + * pairs. + * + * Equivalent to the MultinomialLogisticLossLayer if the infogain matrix is the + * identity. + * + * @param bottom input Blob vector (length 2-3) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ \hat{p} @f$, a Blob with values in + * @f$ [0, 1] @f$ indicating the predicted probability of each of the + * @f$ K = CHW @f$ classes. Each prediction vector @f$ \hat{p}_n @f$ + * should sum to 1 as in a probability distribution: @f$ + * \forall n \sum\limits_{k=1}^K \hat{p}_{nk} = 1 @f$. + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels @f$ l @f$, an integer-valued Blob with values + * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ + * indicating the correct class label among the @f$ K @f$ classes + * -# @f$ (1 \times 1 \times K \times K) @f$ + * (\b optional) the infogain matrix @f$ H @f$. This must be provided as + * the third bottom blob input if not provided as the infogain_mat in the + * InfogainLossParameter. If @f$ H = I @f$, this layer is equivalent to the + * MultinomialLogisticLossLayer. + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed infogain multinomial logistic loss: @f$ E = + * \frac{-1}{N} \sum\limits_{n=1}^N H_{l_n} \log(\hat{p}_n) = + * \frac{-1}{N} \sum\limits_{n=1}^N \sum\limits_{k=1}^{K} H_{l_n,k} + * \log(\hat{p}_{n,k}) + * @f$, where @f$ H_{l_n} @f$ denotes row @f$l_n@f$ of @f$H@f$. + */ +template +class InfogainLossLayer : public LossLayer { + public: + explicit InfogainLossLayer(const LayerParameter& param) + : LossLayer(param), infogain_() {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + // InfogainLossLayer takes 2-3 bottom Blobs; if there are 3 the third should + // be the infogain matrix. (Otherwise the infogain matrix is loaded from a + // file specified by LayerParameter.) + virtual inline int_tp ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { return 2; } + virtual inline int_tp MaxBottomBlobs() const { return 3; } + + virtual inline const char* type() const { return "InfogainLoss"; } + + protected: + /// @copydoc InfogainLossLayer + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + + /** + * @brief Computes the infogain loss error gradient w.r.t. the predictions. + * + * Gradients cannot be computed with respect to the label inputs (bottom[1]), + * so this method ignores bottom[1] and requires !propagate_down[1], crashing + * if propagate_down[1] is set. (The same applies to the infogain matrix, if + * provided as bottom[2] rather than in the layer_param.) + * + * @param top output Blob vector (length 1), providing the error gradient + * with respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * propagate_down[1] must be false as we can't compute gradients with + * respect to the labels (similarly for propagate_down[2] and the + * infogain matrix, if provided as bottom[2]) + * @param bottom input Blob vector (length 2-3) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ \hat{p} @f$; Backward computes diff + * @f$ \frac{\partial E}{\partial \hat{p}} @f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels -- ignored as we can't compute their error gradients + * -# @f$ (1 \times 1 \times K \times K) @f$ + * (\b optional) the information gain matrix -- ignored as its error + * gradient computation is not implemented. + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + Blob infogain_; +}; + +/** + * @brief Computes the multinomial logistic loss for a one-of-many + * classification task, directly taking a predicted probability + * distribution as input. + * + * When predictions are not already a probability distribution, you should + * instead use the SoftmaxWithLossLayer, which maps predictions to a + * distribution using the SoftmaxLayer, before computing the multinomial + * logistic loss. The SoftmaxWithLossLayer should be preferred over separate + * SoftmaxLayer + MultinomialLogisticLossLayer + * as its gradient computation is more numerically stable. + * + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ \hat{p} @f$, a Blob with values in + * @f$ [0, 1] @f$ indicating the predicted probability of each of the + * @f$ K = CHW @f$ classes. Each prediction vector @f$ \hat{p}_n @f$ + * should sum to 1 as in a probability distribution: @f$ + * \forall n \sum\limits_{k=1}^K \hat{p}_{nk} = 1 @f$. + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels @f$ l @f$, an integer-valued Blob with values + * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ + * indicating the correct class label among the @f$ K @f$ classes + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed multinomial logistic loss: @f$ E = + * \frac{-1}{N} \sum\limits_{n=1}^N \log(\hat{p}_{n,l_n}) + * @f$ + */ +template +class MultinomialLogisticLossLayer : public LossLayer { + public: + explicit MultinomialLogisticLossLayer(const LayerParameter& param) + : LossLayer(param) {} + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "MultinomialLogisticLoss"; } + + protected: + /// @copydoc MultinomialLogisticLossLayer + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + + /** + * @brief Computes the multinomial logistic loss error gradient w.r.t. the + * predictions. + * + * Gradients cannot be computed with respect to the label inputs (bottom[1]), + * so this method ignores bottom[1] and requires !propagate_down[1], crashing + * if propagate_down[1] is set. + * + * @param top output Blob vector (length 1), providing the error gradient with + * respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * propagate_down[1] must be false as we can't compute gradients with + * respect to the labels. + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ \hat{p} @f$; Backward computes diff + * @f$ \frac{\partial E}{\partial \hat{p}} @f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels -- ignored as we can't compute their error gradients + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); +}; + +/** + * @brief Computes the cross-entropy (logistic) loss @f$ + * E = \frac{-1}{n} \sum\limits_{n=1}^N \left[ + * p_n \log \hat{p}_n + + * (1 - p_n) \log(1 - \hat{p}_n) + * \right] + * @f$, often used for predicting targets interpreted as probabilities. + * + * This layer is implemented rather than separate + * SigmoidLayer + CrossEntropyLayer + * as its gradient computation is more numerically stable. + * At test time, this layer can be replaced simply by a SigmoidLayer. + * + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the scores @f$ x \in [-\infty, +\infty]@f$, + * which this layer maps to probability predictions + * @f$ \hat{p}_n = \sigma(x_n) \in [0, 1] @f$ + * using the sigmoid function @f$ \sigma(.) @f$ (see SigmoidLayer). + * -# @f$ (N \times C \times H \times W) @f$ + * the targets @f$ y \in [0, 1] @f$ + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed cross-entropy loss: @f$ + * E = \frac{-1}{n} \sum\limits_{n=1}^N \left[ + * p_n \log \hat{p}_n + (1 - p_n) \log(1 - \hat{p}_n) + * \right] + * @f$ + */ +template +class SigmoidCrossEntropyLossLayer : public LossLayer { + public: + explicit SigmoidCrossEntropyLossLayer(const LayerParameter& param) + : LossLayer(param), + sigmoid_layer_(new SigmoidLayer(param)), + sigmoid_output_(new Blob()) {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "SigmoidCrossEntropyLoss"; } + + protected: + /// @copydoc SigmoidCrossEntropyLossLayer + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + + /** + * @brief Computes the sigmoid cross-entropy loss error gradient w.r.t. the + * predictions. + * + * Gradients cannot be computed with respect to the target inputs (bottom[1]), + * so this method ignores bottom[1] and requires !propagate_down[1], crashing + * if propagate_down[1] is set. + * + * @param top output Blob vector (length 1), providing the error gradient with + * respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * propagate_down[1] must be false as gradient computation with respect + * to the targets is not implemented. + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$x@f$; Backward computes diff + * @f$ \frac{\partial E}{\partial x} = + * \frac{1}{n} \sum\limits_{n=1}^N (\hat{p}_n - p_n) + * @f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels -- ignored as we can't compute their error gradients + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + virtual void Backward_gpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + /// The internal SigmoidLayer used to map predictions to probabilities. + shared_ptr > sigmoid_layer_; + /// sigmoid_output stores the output of the SigmoidLayer. + shared_ptr > sigmoid_output_; + /// bottom vector holder to call the underlying SigmoidLayer::Forward + vector*> sigmoid_bottom_vec_; + /// top vector holder to call the underlying SigmoidLayer::Forward + vector*> sigmoid_top_vec_; +}; + +// Forward declare SoftmaxLayer for use in SoftmaxWithLossLayer. +template class SoftmaxLayer; + +/** + * @brief Computes the multinomial logistic loss for a one-of-many + * classification task, passing real-valued predictions through a + * softmax to get a probability distribution over classes. + * + * This layer should be preferred over separate + * SoftmaxLayer + MultinomialLogisticLossLayer + * as its gradient computation is more numerically stable. + * At test time, this layer can be replaced simply by a SoftmaxLayer. + * + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ x @f$, a Blob with values in + * @f$ [-\infty, +\infty] @f$ indicating the predicted score for each of + * the @f$ K = CHW @f$ classes. This layer maps these scores to a + * probability distribution over classes using the softmax function + * @f$ \hat{p}_{nk} = \exp(x_{nk}) / + * \left[\sum_{k'} \exp(x_{nk'})\right] @f$ (see SoftmaxLayer). + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels @f$ l @f$, an integer-valued Blob with values + * @f$ l_n \in [0, 1, 2, ..., K - 1] @f$ + * indicating the correct class label among the @f$ K @f$ classes + * @param top output Blob vector (length 1) + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * the computed cross-entropy classification loss: @f$ E = + * \frac{-1}{N} \sum\limits_{n=1}^N \log(\hat{p}_{n,l_n}) + * @f$, for softmax output class probabilites @f$ \hat{p} @f$ + */ +template +class SoftmaxWithLossLayer : public LossLayer { + public: + /** + * @param param provides LossParameter loss_param, with options: + * - ignore_label (optional) + * Specify a label value that should be ignored when computing the loss. + * - normalize (optional, default true) + * If true, the loss is normalized by the number of (nonignored) labels + * present; otherwise the loss is simply summed over spatial locations. + */ + explicit SoftmaxWithLossLayer(const LayerParameter& param) + : LossLayer(param) {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "SoftmaxWithLoss"; } + virtual inline int_tp ExactNumTopBlobs() const { return -1; } + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlobs() const { return 2; } + + protected: + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Forward_gpu(const vector*>& bottom, + const vector*>& top); + /** + * @brief Computes the softmax loss error gradient w.r.t. the predictions. + * + * Gradients cannot be computed with respect to the label inputs (bottom[1]), + * so this method ignores bottom[1] and requires !propagate_down[1], crashing + * if propagate_down[1] is set. + * + * @param top output Blob vector (length 1), providing the error gradient with + * respect to the outputs + * -# @f$ (1 \times 1 \times 1 \times 1) @f$ + * This Blob's diff will simply contain the loss_weight* @f$ \lambda @f$, + * as @f$ \lambda @f$ is the coefficient of this layer's output + * @f$\ell_i@f$ in the overall Net loss + * @f$ E = \lambda_i \ell_i + \mbox{other loss terms}@f$; hence + * @f$ \frac{\partial E}{\partial \ell_i} = \lambda_i @f$. + * (*Assuming that this top Blob is not used as a bottom (input) by any + * other layer of the Net.) + * @param propagate_down see Layer::Backward. + * propagate_down[1] must be false as we can't compute gradients with + * respect to the labels. + * @param bottom input Blob vector (length 2) + * -# @f$ (N \times C \times H \times W) @f$ + * the predictions @f$ x @f$; Backward computes diff + * @f$ \frac{\partial E}{\partial x} @f$ + * -# @f$ (N \times 1 \times 1 \times 1) @f$ + * the labels -- ignored as we can't compute their error gradients + */ + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + virtual void Backward_gpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + /// Read the normalization mode parameter and compute the normalizer based + /// on the blob size. If normalization_mode is VALID, the count of valid + /// outputs will be read from valid_count, unless it is -1 in which case + /// all outputs are assumed to be valid. + virtual Dtype get_normalizer( + LossParameter_NormalizationMode normalization_mode, int valid_count); + + /// The internal SoftmaxLayer used to map predictions to a distribution. + shared_ptr > softmax_layer_; + /// prob stores the output probability predictions from the SoftmaxLayer. + Blob prob_; + /// bottom vector holder used in call to the underlying SoftmaxLayer::Forward + vector*> softmax_bottom_vec_; + /// top vector holder used in call to the underlying SoftmaxLayer::Forward + vector*> softmax_top_vec_; + /// Whether to ignore instances with a certain label. + bool has_ignore_label_; + /// The label indicating that an instance should be ignored. + int_tp ignore_label_; + /// How to normalize the output loss. + LossParameter_NormalizationMode normalization_; + + int_tp softmax_axis_, outer_num_, inner_num_; +}; + + +template +class MalisLossLayer : public LossLayer { + public: + explicit MalisLossLayer(const LayerParameter& param) + : LossLayer(param) {} + virtual void LayerSetUp(const vector*>& bottom, + const vector*>& top); + virtual void Reshape(const vector*>& bottom, + const vector*>& top); + + virtual inline const char* type() const { return "MalisLoss"; } + virtual inline int_tp ExactNumBottomBlobs() const { return -1; } + virtual inline int_tp MinBottomBlobs() const { return 3; } + virtual inline int_tp MaxBottomBlobs() const { return 4; } + virtual inline int_tp ExactNumTopBlobs() const { return -1; } + virtual inline int_tp MinTopBlobs() const { return 1; } + virtual inline int_tp MaxTopBlobs() const { return 2; } + + protected: + virtual void Forward_cpu(const vector*>& bottom, + const vector*>& top); + virtual void Backward_cpu(const vector*>& top, + const vector& propagate_down, const vector*>& bottom); + + private: + void Malis(const Dtype* conn_data, const int_tp conn_num_dims, + const int_tp* conn_dims, + const int_tp* nhood_data, const int_tp* nhood_dims, + const Dtype* seg_data, + const bool pos, Dtype* dloss_data, Dtype* loss_out, + Dtype *classerr_out, Dtype *rand_index_out); + + int_tp nedges_; + int_tp conn_num_dims_; + std::vector conn_dims_; + std::vector nhood_data_; + std::vector nhood_dims_; + + Blob affinity_pos_; + Blob affinity_neg_; + Blob dloss_pos_; + Blob dloss_neg_; +}; + + +} // namespace caffe + +#endif // CAFFE_LOSS_LAYERS_HPP_ diff --git a/include/caffe/net.hpp b/include/caffe/net.hpp index 543133e2517..71217c0d24a 100644 --- a/include/caffe/net.hpp +++ b/include/caffe/net.hpp @@ -11,6 +11,8 @@ #include "caffe/common.hpp" #include "caffe/layer.hpp" #include "caffe/proto/caffe.pb.h" +#include "device.hpp" + namespace caffe { @@ -20,19 +22,22 @@ namespace caffe { * * TODO(dox): more thorough description. */ -template +template class Net { public: - explicit Net(const NetParameter& param, const Net* root_net = NULL); - explicit Net(const string& param_file, Phase phase, - const Net* root_net = NULL); - virtual ~Net() {} + explicit Net(const NetParameter& param, device* device_context, + const Net* root_net = + NULL); + explicit Net(const string& param_file, Phase phase, device* device_context, + const Net* root_net = NULL); + virtual ~Net() { + } /// @brief Initialize a network with a NetParameter. void Init(const NetParameter& param); /** - * @brief Run Forward with the input Blob%s already fed separately. + * @brief Run Forward with the input Blobs already fed separately. * * You can get the input blobs using input_blobs(). */ @@ -46,12 +51,12 @@ class Net { * the middle may be incorrect if all of the layers of a fan-in are not * included. */ - Dtype ForwardFromTo(int start, int end); - Dtype ForwardFrom(int start); - Dtype ForwardTo(int end); + Dtype ForwardFromTo(int_tp start, int_tp end); + Dtype ForwardFrom(int_tp start); + Dtype ForwardTo(int_tp end); /// @brief Run forward using a set of bottom blobs, and return the result. - const vector*>& Forward(const vector* > & bottom, - Dtype* loss = NULL); + const vector*>& Forward(const vector*> & bottom, + Dtype* loss = NULL); /** * @brief Run forward using a serialized BlobProtoVector and return the * result as a serialized BlobProtoVector @@ -70,9 +75,9 @@ class Net { * provided during the forward pass. */ void Backward(); - void BackwardFromTo(int start, int end); - void BackwardFrom(int start); - void BackwardTo(int end); + void BackwardFromTo(int_tp start, int_tp end); + void BackwardFrom(int_tp start); + void BackwardTo(int_tp end); /** * @brief Reshape all layers from bottom to top. @@ -82,7 +87,7 @@ class Net { */ void Reshape(); - Dtype ForwardBackward(const vector* > & bottom) { + Dtype ForwardBackward(const vector*> & bottom) { Dtype loss; Forward(bottom, &loss); Backward(); @@ -120,11 +125,17 @@ class Net { void ToHDF5(const string& filename, bool write_diff = false) const; /// @brief returns the network name. - inline const string& name() const { return name_; } + inline const string& name() const { + return name_; + } /// @brief returns the layer names - inline const vector& layer_names() const { return layer_names_; } + inline const vector& layer_names() const { + return layer_names_; + } /// @brief returns the blob names - inline const vector& blob_names() const { return blob_names_; } + inline const vector& blob_names() const { + return blob_names_; + } /// @brief returns the blobs inline const vector > >& blobs() const { return blobs_; @@ -134,7 +145,9 @@ class Net { return layers_; } /// @brief returns the phase: TRAIN or TEST - inline Phase phase() const { return phase_; } + inline Phase phase() const { + return phase_; + } /** * @brief returns the bottom vecs for each layer -- usually you won't * need this unless you do per-layer checks such as gradients. @@ -150,13 +163,13 @@ class Net { return top_vecs_; } /// @brief returns the ids of the top blobs of layer i - inline const vector & top_ids(int i) const { + inline const vector & top_ids(int_tp i) const { CHECK_GE(i, 0) << "Invalid layer id"; CHECK_LT(i, top_id_vecs_.size()) << "Invalid layer id"; return top_id_vecs_[i]; } /// @brief returns the ids of the bottom blobs of layer i - inline const vector & bottom_ids(int i) const { + inline const vector & bottom_ids(int_tp i) const { CHECK_GE(i, 0) << "Invalid layer id"; CHECK_LT(i, bottom_id_vecs_.size()) << "Invalid layer id"; return bottom_id_vecs_[i]; @@ -187,26 +200,32 @@ class Net { inline const vector& has_params_decay() const { return has_params_decay_; } - const map& param_names_index() const { + const map& param_names_index() const { return param_names_index_; } - inline const vector& param_owners() const { return param_owners_; } + inline const vector& param_owners() const { + return param_owners_; + } inline const vector& param_display_names() const { return param_display_names_; } /// @brief Input and output blob numbers - inline int num_inputs() const { return net_input_blobs_.size(); } - inline int num_outputs() const { return net_output_blobs_.size(); } + inline int_tp num_inputs() const { + return net_input_blobs_.size(); + } + inline int_tp num_outputs() const { + return net_output_blobs_.size(); + } inline const vector*>& input_blobs() const { return net_input_blobs_; } inline const vector*>& output_blobs() const { return net_output_blobs_; } - inline const vector& input_blob_indices() const { + inline const vector& input_blob_indices() const { return net_input_blob_indices_; } - inline const vector& output_blob_indices() const { + inline const vector& output_blob_indices() const { return net_output_blob_indices_; } bool has_blob(const string& blob_name) const; @@ -214,7 +233,9 @@ class Net { bool has_layer(const string& layer_name) const; const shared_ptr > layer_by_name(const string& layer_name) const; - void set_debug_info(const bool value) { debug_info_ = value; } + void set_debug_info(const bool value) { + debug_info_ = value; + } // Helpers for Init. /** @@ -222,33 +243,33 @@ class Net { * phase, level, and stage. */ static void FilterNet(const NetParameter& param, - NetParameter* param_filtered); + NetParameter* param_filtered); /// @brief return whether NetState state meets NetStateRule rule static bool StateMeetsRule(const NetState& state, const NetStateRule& rule, - const string& layer_name); + const string& layer_name); protected: // Helpers for Init. /// @brief Append a new input or top blob to the net. - void AppendTop(const NetParameter& param, const int layer_id, - const int top_id, set* available_blobs, - map* blob_name_to_idx); + void AppendTop(const NetParameter& param, const int_tp layer_id, + const int_tp top_id, set* available_blobs, + map* blob_name_to_idx); /// @brief Append a new bottom blob to the net. - int AppendBottom(const NetParameter& param, const int layer_id, - const int bottom_id, set* available_blobs, - map* blob_name_to_idx); + int_tp AppendBottom(const NetParameter& param, const int_tp layer_id, + const int_tp bottom_id, set* available_blobs, + map* blob_name_to_idx); /// @brief Append a new parameter blob to the net. - void AppendParam(const NetParameter& param, const int layer_id, - const int param_id); + void AppendParam(const NetParameter& param, const int_tp layer_id, + const int_tp param_id); /// @brief Helper for displaying debug info in Forward about input Blobs. - void InputDebugInfo(const int layer_id); + void InputDebugInfo(const int_tp layer_id); /// @brief Helper for displaying debug info in Forward. - void ForwardDebugInfo(const int layer_id); + void ForwardDebugInfo(const int_tp layer_id); /// @brief Helper for displaying debug info in Backward. - void BackwardDebugInfo(const int layer_id); + void BackwardDebugInfo(const int_tp layer_id); /// @brief Helper for displaying debug info in Update. - void UpdateDebugInfo(const int param_id); + void UpdateDebugInfo(const int_tp param_id); /// @brief The network name string name_; @@ -257,33 +278,33 @@ class Net { /// @brief Individual layers in the net vector > > layers_; vector layer_names_; - map layer_names_index_; + map layer_names_index_; vector layer_need_backward_; /// @brief the blobs storing intermediate results between the layer. vector > > blobs_; vector blob_names_; - map blob_names_index_; + map blob_names_index_; vector blob_need_backward_; /// bottom_vecs stores the vectors containing the input for each layer. /// They don't actually host the blobs (blobs_ does), so we simply store /// pointers. vector*> > bottom_vecs_; - vector > bottom_id_vecs_; + vector > bottom_id_vecs_; vector > bottom_need_backward_; /// top_vecs stores the vectors containing the output for each layer vector*> > top_vecs_; - vector > top_id_vecs_; + vector > top_id_vecs_; /// Vector of weight in the loss (or objective) function of each net blob, /// indexed by blob_id. vector blob_loss_weights_; - vector > param_id_vecs_; - vector param_owners_; + vector > param_id_vecs_; + vector param_owners_; vector param_display_names_; - vector > param_layer_indices_; - map param_names_index_; + vector > param_layer_indices_; + map param_names_index_; /// blob indices for the input and the output of the net - vector net_input_blob_indices_; - vector net_output_blob_indices_; + vector net_input_blob_indices_; + vector net_output_blob_indices_; vector*> net_input_blobs_; vector*> net_output_blobs_; /// The parameters in the network. @@ -296,7 +317,7 @@ class Net { * if and only if params_[i] is an "owner"; otherwise, params_[i] is a sharer * and learnable_params_[learnable_param_ids_[i]] gives its owner. */ - vector learnable_param_ids_; + vector learnable_param_ids_; /// the learning rate multipliers for learnable_params_ vector params_lr_; vector has_params_lr_; @@ -304,15 +325,17 @@ class Net { vector params_weight_decay_; vector has_params_decay_; /// The bytes of memory used by this net - size_t memory_used_; + uint_tp memory_used_; /// Whether to compute and display debug info for the net. bool debug_info_; + + device* device_; + /// The root net that actually holds the shared layers in data parallelism const Net* const root_net_; DISABLE_COPY_AND_ASSIGN(Net); }; - } // namespace caffe #endif // CAFFE_NET_HPP_ diff --git a/include/caffe/opencl/ocl_dev_ptr.hpp b/include/caffe/opencl/ocl_dev_ptr.hpp new file mode 100644 index 00000000000..20962d0df2b --- /dev/null +++ b/include/caffe/opencl/ocl_dev_ptr.hpp @@ -0,0 +1,30 @@ +#ifndef CAFFE_OCL_DEV_PTR_HPP_ +#define CAFFE_OCL_DEV_PTR_HPP_ + +#ifdef USE_GREENTEA + +#include "caffe/dev_ptr.hpp" +#ifndef __APPLE__ +#include "CL/cl.h" +#else +#include "OpenCL/cl.h" +#endif + +namespace caffe { + +template class ocl_dev_ptr : public dev_ptr { + public: + explicit ocl_dev_ptr(cl_mem ocl_mem); + Type* get(); + std::size_t off(); + + private: + cl_mem ocl_mem_; + std::size_t off_; +}; + +} // namespace caffe + +#endif // USE_GREENTEA + +#endif /* CAFFE_OCL_DEV_PTR_HPP_ */ diff --git a/include/caffe/parallel.hpp b/include/caffe/parallel.hpp index 85fc2b55984..f1dcb905ca8 100644 --- a/include/caffe/parallel.hpp +++ b/include/caffe/parallel.hpp @@ -1,6 +1,10 @@ #ifndef CAFFE_PARALLEL_HPP_ #define CAFFE_PARALLEL_HPP_ +#ifdef CMAKE_BUILD + #include "caffe_config.h" +#endif + #include #include @@ -26,7 +30,7 @@ class Params { virtual ~Params() { } - inline size_t size() const { + inline uint_tp size() const { return size_; } inline Dtype* data() const { @@ -37,7 +41,7 @@ class Params { } protected: - const size_t size_; // Size of buffers + const uint_tp size_; // Size of buffers Dtype* data_; // Network parameters Dtype* diff_; // Gradient @@ -61,23 +65,26 @@ class GPUParams : public Params { class DevicePair { public: - DevicePair(int parent, int device) + DevicePair(device* parent, device* dev) : parent_(parent), - device_(device) { + device_(dev) { } - inline int parent() { + + inline device* get_parent() { return parent_; } - inline int device() { + + inline device* get_device() { return device_; } // Group GPUs in pairs, by proximity depending on machine's topology - static void compute(const vector devices, vector* pairs); + static void compute(const vector devices, + vector* pairs); protected: - int parent_; - int device_; + device* parent_; + device* device_; }; // Synchronous data parallelism using map-reduce between local GPUs. @@ -93,7 +100,7 @@ class P2PSync : public GPUParams, public Solver::Callback, return solver_; } - void run(const vector& gpus); + void run(const vector& gpus); protected: void on_start(); diff --git a/include/caffe/solver.hpp b/include/caffe/solver.hpp index 38259edad9f..187a644b208 100644 --- a/include/caffe/solver.hpp +++ b/include/caffe/solver.hpp @@ -1,11 +1,12 @@ -#ifndef CAFFE_SOLVER_HPP_ -#define CAFFE_SOLVER_HPP_ +#ifndef CAFFE_OPTIMIZATION_SOLVER_HPP_ +#define CAFFE_OPTIMIZATION_SOLVER_HPP_ #include #include #include #include "caffe/net.hpp" #include "caffe/solver_factory.hpp" +#include "device.hpp" namespace caffe { @@ -37,7 +38,7 @@ typedef boost::function ActionCallback; * Requires implementation of ApplyUpdate to compute a parameter update * given the current state of the Net parameters. */ -template +template class Solver { public: explicit Solver(const SolverParameter& param, @@ -47,6 +48,10 @@ class Solver { void InitTrainNet(); void InitTestNets(); + // Allows to change the solver parameters during training + void UpdateSolverParams(const SolverParameter& param); + SolverParameter GetSolverParams(); + // Client of the Solver optionally may call this in order to set the function // that the solver uses to see what action it should take (e.g. snapshot or // exit training early). @@ -55,8 +60,10 @@ class Solver { // The main entry of the solver function. In default, iter will be zero. Pass // in a non-zero iter number to resume training for a pre-trained net. virtual void Solve(const char* resume_file = NULL); - inline void Solve(const string resume_file) { Solve(resume_file.c_str()); } - void Step(int iters); + inline void Solve(const string resume_file) { + Solve(resume_file.c_str()); + } + Dtype Step(int_tp iters); // The Restore method simply dispatches to one of the // RestoreSolverStateFrom___ protected methods. You should implement these // methods to restore the state from the appropriate snapshot type. @@ -72,7 +79,17 @@ class Solver { inline const vector > >& test_nets() { return test_nets_; } - int iter() { return iter_; } + + int_tp iter() { + return iter_; + } + + int_tp max_iter() { + return param_.max_iter(); + } + + virtual void SnapshotSolverState(const string& model_filename) = 0; + // Invoked at specific points during an iteration class Callback { @@ -89,10 +106,18 @@ class Solver { } void CheckSnapshotWritePermissions(); + /** * @brief Returns the solver type. */ - virtual inline const char* type() const { return ""; } + virtual inline const char* type() const { + return ""; + } + + inline device *get_device() { + return device_; + } + protected: // Make and apply the update value for the current iteration. @@ -102,18 +127,19 @@ class Solver { string SnapshotToHDF5(); // The test routine void TestAll(); - void Test(const int test_net_id = 0); - virtual void SnapshotSolverState(const string& model_filename) = 0; + void Test(const int_tp test_net_id = 0); virtual void RestoreSolverStateFromHDF5(const string& state_file) = 0; virtual void RestoreSolverStateFromBinaryProto(const string& state_file) = 0; - void DisplayOutputBlobs(const int net_id); - void UpdateSmoothedLoss(Dtype loss, int start_iter, int average_loss); + + void DisplayOutputBlobs(const int_tp net_id); + void UpdateSmoothedLoss(Dtype loss, int_tp start_iter, int_tp average_loss); SolverParameter param_; - int iter_; - int current_step_; + int_tp iter_; + int_tp current_step_; shared_ptr > net_; vector > > test_nets_; + device* device_; vector callbacks_; vector losses_; Dtype smoothed_loss_; @@ -132,21 +158,24 @@ class Solver { DISABLE_COPY_AND_ASSIGN(Solver); }; + /** * @brief Solver that only computes gradients, used as worker * for multi-GPU training. */ -template +template class WorkerSolver : public Solver { public: explicit WorkerSolver(const SolverParameter& param, - const Solver* root_solver = NULL) - : Solver(param, root_solver) {} + const Solver* root_solver = NULL) + : Solver(param, root_solver) { + } protected: - void ApplyUpdate() {} + void ApplyUpdate() { + } void SnapshotSolverState(const string& model_filename) { - LOG(FATAL) << "Should not be called on worker solver."; + LOG(FATAL)<< "Should not be called on worker solver."; } void RestoreSolverStateFromBinaryProto(const string& state_file) { LOG(FATAL) << "Should not be called on worker solver."; @@ -158,4 +187,4 @@ class WorkerSolver : public Solver { } // namespace caffe -#endif // CAFFE_SOLVER_HPP_ +#endif // CAFFE_OPTIMIZATION_SOLVER_HPP_ diff --git a/include/caffe/syncedmem.hpp b/include/caffe/syncedmem.hpp index 38ee4664028..fc1a2085b54 100644 --- a/include/caffe/syncedmem.hpp +++ b/include/caffe/syncedmem.hpp @@ -4,37 +4,17 @@ #include #include "caffe/common.hpp" +#include "caffe/greentea/greentea.hpp" +#include "caffe/util/math_functions.hpp" + +#define OPENCL_PAGE_ALIGN 4096 +#define OPENCL_CACHE_ALIGN 64 namespace caffe { -// If CUDA is available and in GPU mode, host memory will be allocated pinned, -// using cudaMallocHost. It avoids dynamic pinning for transfers (DMA). -// The improvement in performance seems negligible in the single GPU case, -// but might be more significant for parallel training. Most importantly, -// it improved stability for large models on many GPUs. -inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda) { -#ifndef CPU_ONLY - if (Caffe::mode() == Caffe::GPU) { - CUDA_CHECK(cudaMallocHost(ptr, size)); - *use_cuda = true; - return; - } -#endif - *ptr = malloc(size); - *use_cuda = false; - CHECK(*ptr) << "host allocation of size " << size << " failed"; -} - -inline void CaffeFreeHost(void* ptr, bool use_cuda) { -#ifndef CPU_ONLY - if (use_cuda) { - CUDA_CHECK(cudaFreeHost(ptr)); - return; - } -#endif - free(ptr); -} +void CaffeMallocHost(void** ptr, int_tp size, device* device_context); +void CaffeFreeHost(void* ptr, device* device_context); /** * @brief Manages memory allocation and synchronization between the host (CPU) @@ -44,14 +24,48 @@ inline void CaffeFreeHost(void* ptr, bool use_cuda) { */ class SyncedMemory { public: - SyncedMemory() - : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED), - own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false), - gpu_device_(-1) {} - explicit SyncedMemory(size_t size) - : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED), - own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false), - gpu_device_(-1) {} +#ifdef USE_GREENTEA + explicit SyncedMemory(device *device_context) + : cpu_ptr_(NULL), + gpu_ptr_(NULL), + size_(0), + head_(UNINITIALIZED), + own_cpu_data_(false), + own_gpu_data_(false), + device_(device_context), + cl_gpu_mem_(NULL) { + } + explicit SyncedMemory(uint_tp size, device *device_context) + : cpu_ptr_(NULL), + gpu_ptr_(NULL), + size_(size), + head_(UNINITIALIZED), + own_cpu_data_(false), + own_gpu_data_(false), + device_(device_context), + cl_gpu_mem_(NULL) { + } +#else + explicit SyncedMemory(device *device_context) + : cpu_ptr_(NULL), + gpu_ptr_(NULL), + size_(0), + head_(UNINITIALIZED), + own_cpu_data_(false), + own_gpu_data_(false), + device_(device_context) { + } + explicit SyncedMemory(uint_tp size, device *device_context) + : cpu_ptr_(NULL), + gpu_ptr_(NULL), + size_(size), + head_(UNINITIALIZED), + own_cpu_data_(false), + own_gpu_data_(false), + device_(device_context) { + } +#endif + ~SyncedMemory(); const void* cpu_data(); void set_cpu_data(void* data); @@ -59,28 +73,45 @@ class SyncedMemory { void set_gpu_data(void* data); void* mutable_cpu_data(); void* mutable_gpu_data(); - enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED }; - SyncedHead head() { return head_; } - size_t size() { return size_; } + enum SyncedHead { + UNINITIALIZED, + HEAD_AT_CPU, + HEAD_AT_GPU, + SYNCED + }; + SyncedHead head() { + return head_; + } + uint_tp size() { + return size_; + } #ifndef CPU_ONLY +#ifdef USE_CUDA void async_gpu_push(const cudaStream_t& stream); -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY private: void to_cpu(); void to_gpu(); void* cpu_ptr_; void* gpu_ptr_; - size_t size_; + + uint_tp size_; SyncedHead head_; bool own_cpu_data_; - bool cpu_malloc_use_cuda_; bool own_gpu_data_; - int gpu_device_; + device *device_; + +#ifdef USE_GREENTEA + cl_mem cl_gpu_mem_; +#endif + - DISABLE_COPY_AND_ASSIGN(SyncedMemory); -}; // class SyncedMemory +DISABLE_COPY_AND_ASSIGN(SyncedMemory); +}; +// class SyncedMemory } // namespace caffe diff --git a/include/caffe/test/test_caffe_main.hpp b/include/caffe/test/test_caffe_main.hpp index fc156091476..063e31cff21 100644 --- a/include/caffe/test/test_caffe_main.hpp +++ b/include/caffe/test/test_caffe_main.hpp @@ -9,6 +9,7 @@ #include #include +#include "../device.hpp" #include "caffe/common.hpp" using std::cout; @@ -17,7 +18,7 @@ using std::endl; #ifdef CMAKE_BUILD #include "caffe_config.h" #else - #define CUDA_TEST_DEVICE -1 + #define TEST_DEVICE -1 #define CMAKE_SOURCE_DIR "src/" #define EXAMPLES_SOURCE_DIR "examples/" #define CMAKE_EXT "" diff --git a/include/caffe/test/test_gradient_check_util.hpp b/include/caffe/test/test_gradient_check_util.hpp index b25a84875ef..8ec9de992f5 100644 --- a/include/caffe/test/test_gradient_check_util.hpp +++ b/include/caffe/test/test_gradient_check_util.hpp @@ -15,72 +15,80 @@ namespace caffe { // The gradient checker adds a L2 normalization loss function on top of the // top blobs, and checks the gradient. -template +template class GradientChecker { public: // kink and kink_range specify an ignored nonsmooth region of the form // kink - kink_range <= |feature value| <= kink + kink_range, // which accounts for all nonsmoothness in use by caffe GradientChecker(const Dtype stepsize, const Dtype threshold, - const unsigned int seed = 1701, const Dtype kink = 0., - const Dtype kink_range = -1) - : stepsize_(stepsize), threshold_(threshold), seed_(seed), - kink_(kink), kink_range_(kink_range) {} + const uint_tp seed = 1701, const Dtype kink = 0., + const Dtype kink_range = -1) + : stepsize_(stepsize), threshold_(threshold), seed_(seed), kink_(kink), + kink_range_(kink_range) { + } // Checks the gradient of a layer, with provided bottom layers and top // layers. // Note that after the gradient check, we do not guarantee that the data // stored in the layer parameters and the blobs are unchanged. void CheckGradient(Layer* layer, const vector*>& bottom, - const vector*>& top, int check_bottom = -1) { - layer->SetUp(bottom, top); - CheckGradientSingle(layer, bottom, top, check_bottom, -1, -1); + const vector*>& top, + int_tp check_bottom = -1) { + layer->SetUp(bottom, top); + CheckGradientSingle(layer, bottom, top, check_bottom, -1, -1); } void CheckGradientExhaustive(Layer* layer, - const vector*>& bottom, const vector*>& top, - int check_bottom = -1); + const vector*>& bottom, + const vector*>& top, + int_tp check_bottom = -1); // CheckGradientEltwise can be used to test layers that perform element-wise // computation only (e.g., neuron layers) -- where (d y_i) / (d x_j) = 0 when // i != j. void CheckGradientEltwise(Layer* layer, - const vector*>& bottom, const vector*>& top); + const vector*>& bottom, + const vector*>& top); // Checks the gradient of a single output with respect to particular input // blob(s). If check_bottom = i >= 0, check only the ith bottom Blob. // If check_bottom == -1, check everything -- all bottom Blobs and all // param Blobs. Otherwise (if check_bottom < -1), check only param Blobs. void CheckGradientSingle(Layer* layer, - const vector*>& bottom, const vector*>& top, - int check_bottom, int top_id, int top_data_id, bool element_wise = false); + const vector*>& bottom, + const vector*>& top, int_tp check_bottom, + int_tp top_id, + int_tp top_data_id, bool element_wise = false); // Checks the gradient of a network. This network should not have any data // layers or loss layers, since the function does not explicitly deal with // such cases yet. All input blobs and parameter blobs are going to be // checked, layer-by-layer to avoid numerical problems to accumulate. void CheckGradientNet(const Net& net, - const vector*>& input); + const vector*>& input); protected: Dtype GetObjAndGradient(const Layer& layer, - const vector*>& top, int top_id = -1, int top_data_id = -1); + const vector*>& top, int_tp top_id = -1, + int_tp top_data_id = -1); Dtype stepsize_; Dtype threshold_; - unsigned int seed_; + uint_tp seed_; Dtype kink_; Dtype kink_range_; }; - -template -void GradientChecker::CheckGradientSingle(Layer* layer, - const vector*>& bottom, const vector*>& top, - int check_bottom, int top_id, int top_data_id, bool element_wise) { +template +void GradientChecker::CheckGradientSingle( + Layer* layer, const vector*>& bottom, + const vector*>& top, int_tp check_bottom, int_tp top_id, + int_tp top_data_id, + bool element_wise) { if (element_wise) { CHECK_EQ(0, layer->blobs().size()); CHECK_LE(0, top_id); CHECK_LE(0, top_data_id); - const int top_count = top[top_id]->count(); - for (int blob_id = 0; blob_id < bottom.size(); ++blob_id) { + const int_tp top_count = top[top_id]->count(); + for (int_tp blob_id = 0; blob_id < bottom.size(); ++blob_id) { CHECK_EQ(top_count, bottom[blob_id]->count()); } } @@ -88,13 +96,13 @@ void GradientChecker::CheckGradientSingle(Layer* layer, // parameter blobs. vector*> blobs_to_check; vector propagate_down(bottom.size(), check_bottom == -1); - for (int i = 0; i < layer->blobs().size(); ++i) { + for (int_tp i = 0; i < layer->blobs().size(); ++i) { Blob* blob = layer->blobs()[i].get(); caffe_set(blob->count(), static_cast(0), blob->mutable_cpu_diff()); blobs_to_check.push_back(blob); } if (check_bottom == -1) { - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { blobs_to_check.push_back(bottom[i]); } } else if (check_bottom >= 0) { @@ -102,9 +110,9 @@ void GradientChecker::CheckGradientSingle(Layer* layer, blobs_to_check.push_back(bottom[check_bottom]); propagate_down[check_bottom] = true; } - CHECK_GT(blobs_to_check.size(), 0) << "No blobs to check."; + CHECK_GT(blobs_to_check.size(), 0)<< "No blobs to check."; // Compute the gradient analytically using Backward - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); // Ignore the loss from the layer (it's just the weighted sum of the losses // from the top blobs, whose gradients we may want to test individually). layer->Forward(bottom, top); @@ -112,28 +120,29 @@ void GradientChecker::CheckGradientSingle(Layer* layer, GetObjAndGradient(*layer, top, top_id, top_data_id); layer->Backward(top, propagate_down, bottom); // Store computed gradients for all checked blobs - vector > > - computed_gradient_blobs(blobs_to_check.size()); - for (int blob_id = 0; blob_id < blobs_to_check.size(); ++blob_id) { + vector > > computed_gradient_blobs( + blobs_to_check.size()); + for (int_tp blob_id = 0; blob_id < blobs_to_check.size(); ++blob_id) { Blob* current_blob = blobs_to_check[blob_id]; computed_gradient_blobs[blob_id].reset(new Blob()); computed_gradient_blobs[blob_id]->ReshapeLike(*current_blob); - const int count = blobs_to_check[blob_id]->count(); + const int_tp count = blobs_to_check[blob_id]->count(); const Dtype* diff = blobs_to_check[blob_id]->cpu_diff(); - Dtype* computed_gradients = - computed_gradient_blobs[blob_id]->mutable_cpu_data(); - caffe_copy(count, diff, computed_gradients); + Dtype* computed_gradients = computed_gradient_blobs[blob_id] + ->mutable_cpu_data(); + + caffe_cpu_copy(count, diff, computed_gradients); } // Compute derivative of top w.r.t. each bottom and parameter input using // finite differencing. // LOG(ERROR) << "Checking " << blobs_to_check.size() << " blobs."; - for (int blob_id = 0; blob_id < blobs_to_check.size(); ++blob_id) { + for (int_tp blob_id = 0; blob_id < blobs_to_check.size(); ++blob_id) { Blob* current_blob = blobs_to_check[blob_id]; const Dtype* computed_gradients = computed_gradient_blobs[blob_id]->cpu_data(); // LOG(ERROR) << "Blob " << blob_id << ": checking " // << current_blob->count() << " parameters."; - for (int feat_id = 0; feat_id < current_blob->count(); ++feat_id) { + for (int_tp feat_id = 0; feat_id < current_blob->count(); ++feat_id) { // For an element-wise layer, we only need to do finite differencing to // compute the derivative of top[top_id][top_data_id] w.r.t. // bottom[blob_id][i] only for i == top_data_id. For any other @@ -146,20 +155,20 @@ void GradientChecker::CheckGradientSingle(Layer* layer, // Do finite differencing. // Compute loss with stepsize_ added to input. current_blob->mutable_cpu_data()[feat_id] += stepsize_; - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); layer->Forward(bottom, top); - positive_objective = - GetObjAndGradient(*layer, top, top_id, top_data_id); + positive_objective = GetObjAndGradient(*layer, top, top_id, + top_data_id); // Compute loss with stepsize_ subtracted from input. current_blob->mutable_cpu_data()[feat_id] -= stepsize_ * 2; - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); layer->Forward(bottom, top); - negative_objective = - GetObjAndGradient(*layer, top, top_id, top_data_id); + negative_objective = GetObjAndGradient(*layer, top, top_id, + top_data_id); // Recover original input value. current_blob->mutable_cpu_data()[feat_id] += stepsize_; - estimated_gradient = (positive_objective - negative_objective) / - stepsize_ / 2.; + estimated_gradient = (positive_objective - negative_objective) + / stepsize_ / 2.; } Dtype computed_gradient = computed_gradients[feat_id]; Dtype feature = current_blob->cpu_data()[feat_id]; @@ -173,11 +182,10 @@ void GradientChecker::CheckGradientSingle(Layer* layer, std::max(fabs(computed_gradient), fabs(estimated_gradient)), Dtype(1.)); EXPECT_NEAR(computed_gradient, estimated_gradient, threshold_ * scale) - << "debug: (top_id, top_data_id, blob_id, feat_id)=" - << top_id << "," << top_data_id << "," << blob_id << "," << feat_id - << "; feat = " << feature - << "; objective+ = " << positive_objective - << "; objective- = " << negative_objective; + << "debug: (top_id, top_data_id, blob_id, feat_id)=" << top_id + << "," << top_data_id << "," << blob_id << "," << feat_id + << "; feat = " << feature << "; objective+ = " << positive_objective + << "; objective- = " << negative_objective; } // LOG(ERROR) << "Feature: " << current_blob->cpu_data()[feat_id]; // LOG(ERROR) << "computed gradient: " << computed_gradient @@ -186,70 +194,73 @@ void GradientChecker::CheckGradientSingle(Layer* layer, } } -template -void GradientChecker::CheckGradientExhaustive(Layer* layer, - const vector*>& bottom, const vector*>& top, - int check_bottom) { +template +void GradientChecker::CheckGradientExhaustive( + Layer* layer, const vector*>& bottom, + const vector*>& top, int_tp check_bottom) { layer->SetUp(bottom, top); - CHECK_GT(top.size(), 0) << "Exhaustive mode requires at least one top blob."; + CHECK_GT(top.size(), 0)<< "Exhaustive mode requires at least one top blob."; // LOG(ERROR) << "Exhaustive Mode."; - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { // LOG(ERROR) << "Exhaustive: blob " << i << " size " << top[i]->count(); - for (int j = 0; j < top[i]->count(); ++j) { + for (int_tp j = 0; j < top[i]->count(); ++j) { // LOG(ERROR) << "Exhaustive: blob " << i << " data " << j; CheckGradientSingle(layer, bottom, top, check_bottom, i, j); } } } -template -void GradientChecker::CheckGradientEltwise(Layer* layer, - const vector*>& bottom, const vector*>& top) { +template +void GradientChecker::CheckGradientEltwise( + Layer* layer, const vector*>& bottom, + const vector*>& top) { layer->SetUp(bottom, top); - CHECK_GT(top.size(), 0) << "Eltwise mode requires at least one top blob."; - const int check_bottom = -1; + CHECK_GT(top.size(), 0)<< "Eltwise mode requires at least one top blob."; + const int_tp check_bottom = -1; const bool element_wise = true; - for (int i = 0; i < top.size(); ++i) { - for (int j = 0; j < top[i]->count(); ++j) { + for (int_tp i = 0; i < top.size(); ++i) { + for (int_tp j = 0; j < top[i]->count(); ++j) { CheckGradientSingle(layer, bottom, top, check_bottom, i, j, element_wise); } } } -template +template void GradientChecker::CheckGradientNet( const Net& net, const vector*>& input) { const vector > >& layers = net.layers(); vector*> >& bottom_vecs = net.bottom_vecs(); vector*> >& top_vecs = net.top_vecs(); - for (int i = 0; i < layers.size(); ++i) { + for (int_tp i = 0; i < layers.size(); ++i) { net.Forward(input); - LOG(ERROR) << "Checking gradient for " << layers[i]->layer_param().name(); + LOG(ERROR)<< "Checking gradient for " << layers[i]->layer_param().name(); CheckGradientExhaustive(*(layers[i].get()), bottom_vecs[i], top_vecs[i]); } } -template +template Dtype GradientChecker::GetObjAndGradient(const Layer& layer, - const vector*>& top, int top_id, int top_data_id) { + const vector*>& top, + int_tp top_id, + int_tp top_data_id) { Dtype loss = 0; if (top_id < 0) { // the loss will be half of the sum of squares of all outputs - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { Blob* top_blob = top[i]; const Dtype* top_blob_data = top_blob->cpu_data(); Dtype* top_blob_diff = top_blob->mutable_cpu_diff(); - int count = top_blob->count(); - for (int j = 0; j < count; ++j) { + int_tp count = top_blob->count(); + for (int_tp j = 0; j < count; ++j) { loss += top_blob_data[j] * top_blob_data[j]; } // set the diff: simply the data. - caffe_copy(top_blob->count(), top_blob_data, top_blob_diff); + caffe_cpu_copy(top_blob->count(), top_blob_data, top_blob_diff); } loss /= 2.; } else { // the loss will be the top_data_id-th element in the top_id-th blob. - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { Blob* top_blob = top[i]; Dtype* top_blob_diff = top_blob->mutable_cpu_diff(); caffe_set(top_blob->count(), Dtype(0), top_blob_diff); diff --git a/include/caffe/util/benchmark.hpp b/include/caffe/util/benchmark.hpp index d63582776ee..ba2a34156e3 100644 --- a/include/caffe/util/benchmark.hpp +++ b/include/caffe/util/benchmark.hpp @@ -28,9 +28,11 @@ class Timer { bool running_; bool has_run_at_least_once_; #ifndef CPU_ONLY +#ifdef USE_CUDA cudaEvent_t start_gpu_; cudaEvent_t stop_gpu_; -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY boost::posix_time::ptime start_cpu_; boost::posix_time::ptime stop_cpu_; float elapsed_milliseconds_; diff --git a/include/caffe/util/blocking_queue.hpp b/include/caffe/util/blocking_queue.hpp index d3de2e59b80..b7e8263e3fc 100644 --- a/include/caffe/util/blocking_queue.hpp +++ b/include/caffe/util/blocking_queue.hpp @@ -24,7 +24,7 @@ class BlockingQueue { // Return element without removing it T peek(); - size_t size() const; + uint_tp size() const; protected: /** diff --git a/include/caffe/util/cudnn.hpp b/include/caffe/util/cudnn.hpp index 8a7e17c6cd4..82bfd1b12f0 100644 --- a/include/caffe/util/cudnn.hpp +++ b/include/caffe/util/cudnn.hpp @@ -4,6 +4,9 @@ #include +#include +#include + #include "caffe/common.hpp" #include "caffe/proto/caffe.pb.h" @@ -64,35 +67,107 @@ template<> class dataType { }; template -inline void createTensor4dDesc(cudnnTensorDescriptor_t* desc) { +inline void createTensorNdDesc(cudnnTensorDescriptor_t* desc) { CUDNN_CHECK(cudnnCreateTensorDescriptor(desc)); } template -inline void setTensor4dDesc(cudnnTensorDescriptor_t* desc, - int n, int c, int h, int w, - int stride_n, int stride_c, int stride_h, int stride_w) { - CUDNN_CHECK(cudnnSetTensor4dDescriptorEx(*desc, dataType::type, - n, c, h, w, stride_n, stride_c, stride_h, stride_w)); +inline void setTensorNdDesc(cudnnTensorDescriptor_t* desc, + const int_tp total_dims, + const int_tp* shape, const int_tp* stride) { + + // Pad to at least 4 dimensions + int_tp cudnn_dims = std::max(total_dims, (int_tp)4); + int_tp padding = std::max((int_tp)0, cudnn_dims - total_dims); + + std::vector shape_int(cudnn_dims); + std::vector stride_int(cudnn_dims); + + for (int_tp i = cudnn_dims - 1; i >= 0; --i) { + if (i < padding) { + shape_int[i] = 1; + stride_int[i] = shape_int[i + 1] * stride_int[i + 1]; + } else { + shape_int[i] = shape[i - padding]; + stride_int[i] = stride[i - padding]; + } + } + + const int* shape_ptr = &shape_int[0]; + const int* stride_ptr = &stride_int[0]; + + CUDNN_CHECK( + cudnnSetTensorNdDescriptor(*desc, dataType::type, cudnn_dims, + shape_ptr, stride_ptr)); +} + +template +inline void setTensorNdDesc(cudnnTensorDescriptor_t* desc, + const int_tp total_dims, const int_tp* shape) { + + std::vector full_shape(total_dims); + std::vector full_stride(total_dims); + + for (int_tp i = total_dims - 1; i >= 0; --i) { + full_shape[i] = shape[i]; + if (i == total_dims - 1) { + full_stride[i] = 1; + } else { + full_stride[i] = full_stride[i + 1] * full_shape[i + 1]; + } + } + + setTensorNdDesc(desc, total_dims, + &full_shape[0], + &full_stride[0]); } template -inline void setTensor4dDesc(cudnnTensorDescriptor_t* desc, - int n, int c, int h, int w) { - const int stride_w = 1; - const int stride_h = w * stride_w; - const int stride_c = h * stride_h; - const int stride_n = c * stride_c; - setTensor4dDesc(desc, n, c, h, w, - stride_n, stride_c, stride_h, stride_w); +inline void setTensorNdDesc(cudnnTensorDescriptor_t* desc, + const int_tp num_spatial_dims, + const int_tp n, const int_tp c, const int_tp* shape) { + + std::vector full_shape(num_spatial_dims + 2); + std::vector full_stride(num_spatial_dims + 2); + + full_shape[0] = n; + full_shape[1] = c; + + for (int_tp i = num_spatial_dims + 1; i >= 0; --i) { + full_shape[i] = i > 1 ? shape[i-2] : full_shape[i]; + if (i == num_spatial_dims + 1) { + full_stride[i] = 1; + } else { + full_stride[i] = full_stride[i + 1] * full_shape[i + 1]; + } + } + + setTensorNdDesc(desc, num_spatial_dims + 2, + &full_shape[0], + &full_stride[0]); } + template inline void createFilterDesc(cudnnFilterDescriptor_t* desc, - int n, int c, int h, int w) { + const int_tp num_spatial_dims, + const int_tp n, const int_tp c, const int_tp* shape) { + + std::vector shape_int(num_spatial_dims + 2); + + shape_int[0] = n; + shape_int[1] = c; + + for (int_tp i = 0; i < num_spatial_dims; ++i) { + shape_int[2+i] = shape[i]; + } + + const int* shape_ptr = &shape_int[0]; + CUDNN_CHECK(cudnnCreateFilterDescriptor(desc)); - CUDNN_CHECK(cudnnSetFilter4dDescriptor(*desc, dataType::type, - n, c, h, w)); + CUDNN_CHECK(cudnnSetFilterNdDescriptor(*desc, dataType::type, + num_spatial_dims + 2, + shape_ptr)); } template @@ -103,15 +178,33 @@ inline void createConvolutionDesc(cudnnConvolutionDescriptor_t* conv) { template inline void setConvolutionDesc(cudnnConvolutionDescriptor_t* conv, cudnnTensorDescriptor_t bottom, cudnnFilterDescriptor_t filter, - int pad_h, int pad_w, int stride_h, int stride_w) { - CUDNN_CHECK(cudnnSetConvolution2dDescriptor(*conv, - pad_h, pad_w, stride_h, stride_w, 1, 1, CUDNN_CROSS_CORRELATION)); + const int_tp num_spatial_dims, const int_tp* pad, const int_tp* stride) { + + std::vector pad_int(num_spatial_dims); + std::vector stride_int(num_spatial_dims); + std::vector upscale_int(num_spatial_dims); + + for (int_tp i = 0; i < num_spatial_dims; ++i) { + pad_int[i] = pad[i]; + stride_int[i] = stride[i]; + upscale_int[i] = 1; + } + + const int* pad_ptr = &pad_int[0]; + const int* stride_ptr = &stride_int[0]; + const int* upscale_ptr = &upscale_int[0]; + + CUDNN_CHECK(cudnnSetConvolutionNdDescriptor(*conv, num_spatial_dims, + pad_ptr, stride_ptr, upscale_ptr, CUDNN_CROSS_CORRELATION, + dataType::type)); } template inline void createPoolingDesc(cudnnPoolingDescriptor_t* pool_desc, PoolingParameter_PoolMethod poolmethod, cudnnPoolingMode_t* mode, - int h, int w, int pad_h, int pad_w, int stride_h, int stride_w) { + const int_tp num_spatial_dims, + const int_tp* shape, + const int_tp* pad, const int_tp* stride) { switch (poolmethod) { case PoolingParameter_PoolMethod_MAX: *mode = CUDNN_POOLING_MAX; @@ -123,8 +216,26 @@ inline void createPoolingDesc(cudnnPoolingDescriptor_t* pool_desc, LOG(FATAL) << "Unknown pooling method."; } CUDNN_CHECK(cudnnCreatePoolingDescriptor(pool_desc)); - CUDNN_CHECK(cudnnSetPooling2dDescriptor(*pool_desc, *mode, h, w, - pad_h, pad_w, stride_h, stride_w)); + + std::vector shape_int(num_spatial_dims); + std::vector pad_int(num_spatial_dims); + std::vector stride_int(num_spatial_dims); + + for (int_tp i = 0; i < num_spatial_dims; ++i) { + shape_int[i] = shape[i]; + pad_int[i] = pad[i]; + stride_int[i] = stride[i]; + } + + const int* shape_ptr = &shape_int[0]; + const int* pad_ptr = &pad_int[0]; + const int* stride_ptr = &stride_int[0]; + + CUDNN_CHECK(cudnnSetPoolingNdDescriptor(*pool_desc, *mode, + num_spatial_dims, + shape_ptr, + pad_ptr, + stride_ptr)); } } // namespace cudnn diff --git a/include/caffe/util/db_lmdb.hpp b/include/caffe/util/db_lmdb.hpp index 4e1568ace50..96ba2cbc8fb 100644 --- a/include/caffe/util/db_lmdb.hpp +++ b/include/caffe/util/db_lmdb.hpp @@ -10,7 +10,7 @@ namespace caffe { namespace db { -inline void MDB_CHECK(int mdb_status) { +inline void MDB_CHECK(int_tp mdb_status) { CHECK_EQ(mdb_status, MDB_SUCCESS) << mdb_strerror(mdb_status); } @@ -37,7 +37,7 @@ class LMDBCursor : public Cursor { private: void Seek(MDB_cursor_op op) { - int mdb_status = mdb_cursor_get(mdb_cursor_, &mdb_key_, &mdb_value_, op); + int_tp mdb_status = mdb_cursor_get(mdb_cursor_, &mdb_key_, &mdb_value_, op); if (mdb_status == MDB_NOTFOUND) { valid_ = false; } else { diff --git a/include/caffe/util/device_alternate.hpp b/include/caffe/util/device_alternate.hpp index e3fe4fe29fd..548a6017a67 100644 --- a/include/caffe/util/device_alternate.hpp +++ b/include/caffe/util/device_alternate.hpp @@ -1,8 +1,14 @@ #ifndef CAFFE_UTIL_DEVICE_ALTERNATE_H_ #define CAFFE_UTIL_DEVICE_ALTERNATE_H_ +#ifdef CMAKE_BUILD + #include "caffe_config.h" +#endif + #ifdef CPU_ONLY // CPU-only Caffe. +#define CAFFE_CUDA_NUM_THREADS 0 + #include // Stub out GPU calls as unavailable. @@ -30,15 +36,13 @@ void classname::funcname##_##gpu(const vector*>& top, \ const vector*>& bottom) { NO_GPU; } \ #else // Normal GPU + CPU Caffe. +#ifdef USE_CUDA // Include CUDA macros and headers only if enabled #include #include #include #include #include // cuda driver types -#ifdef USE_CUDNN // cuDNN acceleration library. -#include "caffe/util/cudnn.hpp" -#endif // // CUDA macros @@ -68,7 +72,7 @@ void classname::funcname##_##gpu(const vector*>& top, \ // CUDA: grid stride looping #define CUDA_KERNEL_LOOP(i, n) \ - for (int i = blockIdx.x * blockDim.x + threadIdx.x; \ + for (int_tp i = blockIdx.x * blockDim.x + threadIdx.x; \ i < (n); \ i += blockDim.x * gridDim.x) @@ -81,16 +85,25 @@ namespace caffe { const char* cublasGetErrorString(cublasStatus_t error); const char* curandGetErrorString(curandStatus_t error); -// CUDA: use 512 threads per block -const int CAFFE_CUDA_NUM_THREADS = 512; +#define CAFFE_CUDA_NUM_THREADS 512 + +// CDT hacks: allow proper code formatting and remove errors in CDT +#ifdef __CDT_PARSER__ +#include "device_launch_parameters.h" +#define CUDA_KERNEL(...) +#else +#define CUDA_KERNEL(...) <<< __VA_ARGS__ >>> +#endif // CUDA: number of blocks for threads. -inline int CAFFE_GET_BLOCKS(const int N) { +inline int_tp CAFFE_GET_BLOCKS(const int_tp N) { return (N + CAFFE_CUDA_NUM_THREADS - 1) / CAFFE_CUDA_NUM_THREADS; } } // namespace caffe -#endif // CPU_ONLY + +#endif // USE_CUDA +#endif // !CPU_ONLY #endif // CAFFE_UTIL_DEVICE_ALTERNATE_H_ diff --git a/include/caffe/util/format.hpp b/include/caffe/util/format.hpp index 925ad2e0479..cc137418bd3 100644 --- a/include/caffe/util/format.hpp +++ b/include/caffe/util/format.hpp @@ -4,10 +4,12 @@ #include // NOLINT(readability/streams) #include // NOLINT(readability/streams) #include +#include "caffe/definitions.hpp" + namespace caffe { -inline std::string format_int(int n, int numberOfLeadingZeros = 0 ) { +inline std::string format_int(int_tp n, int_tp numberOfLeadingZeros = 0 ) { std::ostringstream s; s << std::setw(numberOfLeadingZeros) << std::setfill('0') << n; return s.str(); diff --git a/include/caffe/util/im2col.hpp b/include/caffe/util/im2col.hpp index a35bc6e0b1c..261695dafd6 100644 --- a/include/caffe/util/im2col.hpp +++ b/include/caffe/util/im2col.hpp @@ -1,59 +1,70 @@ #ifndef _CAFFE_UTIL_IM2COL_HPP_ #define _CAFFE_UTIL_IM2COL_HPP_ +#include +#include "caffe/definitions.hpp" + namespace caffe { -template -void im2col_nd_cpu(const Dtype* data_im, const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_col); - -template -void im2col_cpu(const Dtype* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - Dtype* data_col); - -template -void col2im_nd_cpu(const Dtype* data_col, const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_im); - -template -void col2im_cpu(const Dtype* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - Dtype* data_im); - -template -void im2col_nd_gpu(const Dtype* data_im, const int num_spatial_axes, - const int col_size, const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_col); - -template -void im2col_gpu(const Dtype* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - Dtype* data_col); - -template -void col2im_nd_gpu(const Dtype* data_col, const int num_spatial_axes, - const int im_size, const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_im); - -template -void col2im_gpu(const Dtype* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - Dtype* data_im); +template +void im2col_nd_cpu(const Dtype* data_im, const int_tp num_spatial_axes, + const int_tp* im_shape, const int_tp* col_shape, + const int_tp* kernel_shape, const int_tp* pad, + const int_tp* stride, const int_tp* dilation, + Dtype* data_col); + +template +void im2col_cpu(const Dtype* data_im, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_col); + +template +void col2im_nd_cpu(const Dtype* data_col, const int_tp num_spatial_axes, + const int_tp* im_shape, const int_tp* col_shape, + const int_tp* kernel_shape, const int_tp* pad, + const int_tp* stride, const int_tp* dilation, + Dtype* data_im); + +template +void col2im_cpu(const Dtype* data_col, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_im); + +template +void im2col_nd_gpu(const Dtype* data_im, const int_tp num_spatial_axes, + const int_tp col_size, const int_tp* im_shape, + const int_tp* col_shape, const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_col); + +template +void im2col_gpu(const Dtype* data_im, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_col); + +template +void col2im_nd_gpu(const Dtype* data_col, const int_tp num_spatial_axes, + const int_tp im_size, const int_tp* im_shape, + const int_tp* col_shape, const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_im); + +template +void col2im_gpu(const Dtype* data_col, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_im); } // namespace caffe diff --git a/include/caffe/util/insert_splits.hpp b/include/caffe/util/insert_splits.hpp index 446abb817be..1def1fc3b95 100644 --- a/include/caffe/util/insert_splits.hpp +++ b/include/caffe/util/insert_splits.hpp @@ -12,14 +12,14 @@ namespace caffe { void InsertSplits(const NetParameter& param, NetParameter* param_split); void ConfigureSplitLayer(const string& layer_name, const string& blob_name, - const int blob_idx, const int split_count, const float loss_weight, + const int_tp blob_idx, const int_tp split_count, const float loss_weight, LayerParameter* split_layer_param); string SplitLayerName(const string& layer_name, const string& blob_name, - const int blob_idx); + const int_tp blob_idx); string SplitBlobName(const string& layer_name, const string& blob_name, - const int blob_idx, const int split_idx); + const int_tp blob_idx, const int_tp split_idx); } // namespace caffe diff --git a/include/caffe/util/io.hpp b/include/caffe/util/io.hpp index 1a599883ca3..3baf259e7ac 100644 --- a/include/caffe/util/io.hpp +++ b/include/caffe/util/io.hpp @@ -90,38 +90,38 @@ inline void WriteProtoToBinaryFile( WriteProtoToBinaryFile(proto, filename.c_str()); } -bool ReadFileToDatum(const string& filename, const int label, Datum* datum); +bool ReadFileToDatum(const string& filename, const int_tp label, Datum* datum); inline bool ReadFileToDatum(const string& filename, Datum* datum) { return ReadFileToDatum(filename, -1, datum); } -bool ReadImageToDatum(const string& filename, const int label, - const int height, const int width, const bool is_color, +bool ReadImageToDatum(const string& filename, const int_tp label, + const int_tp height, const int_tp width, const bool is_color, const std::string & encoding, Datum* datum); -inline bool ReadImageToDatum(const string& filename, const int label, - const int height, const int width, const bool is_color, Datum* datum) { - return ReadImageToDatum(filename, label, height, width, is_color, - "", datum); +inline bool ReadImageToDatum(const string& filename, const int_tp label, + const int_tp height, const int_tp width, + const bool is_color, Datum* datum) { + return ReadImageToDatum(filename, label, height, width, is_color, "", datum); } -inline bool ReadImageToDatum(const string& filename, const int label, - const int height, const int width, Datum* datum) { +inline bool ReadImageToDatum(const string& filename, const int_tp label, + const int_tp height, const int_tp width, Datum* datum) { return ReadImageToDatum(filename, label, height, width, true, datum); } -inline bool ReadImageToDatum(const string& filename, const int label, +inline bool ReadImageToDatum(const string& filename, const int_tp label, const bool is_color, Datum* datum) { return ReadImageToDatum(filename, label, 0, 0, is_color, datum); } -inline bool ReadImageToDatum(const string& filename, const int label, +inline bool ReadImageToDatum(const string& filename, const int_tp label, Datum* datum) { return ReadImageToDatum(filename, label, 0, 0, true, datum); } -inline bool ReadImageToDatum(const string& filename, const int label, +inline bool ReadImageToDatum(const string& filename, const int_tp label, const std::string & encoding, Datum* datum) { return ReadImageToDatum(filename, label, 0, 0, true, encoding, datum); } @@ -131,10 +131,10 @@ bool DecodeDatum(Datum* datum, bool is_color); #ifdef USE_OPENCV cv::Mat ReadImageToCVMat(const string& filename, - const int height, const int width, const bool is_color); + const int_tp height, const int_tp width, const bool is_color); cv::Mat ReadImageToCVMat(const string& filename, - const int height, const int width); + const int_tp height, const int_tp width); cv::Mat ReadImageToCVMat(const string& filename, const bool is_color); diff --git a/include/caffe/util/math_functions.hpp b/include/caffe/util/math_functions.hpp index 6f6d3feeae2..86c9fe633c1 100644 --- a/include/caffe/util/math_functions.hpp +++ b/include/caffe/util/math_functions.hpp @@ -14,96 +14,97 @@ namespace caffe { // Caffe gemm provides a simpler interface to the gemm functions, with the // limitation that the data has to be contiguous in memory. -template -void caffe_cpu_gemm(const CBLAS_TRANSPOSE TransA, - const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, - const Dtype alpha, const Dtype* A, const Dtype* B, const Dtype beta, - Dtype* C); +template +void caffe_cpu_gemm(const CBLAS_TRANSPOSE TransA, const CBLAS_TRANSPOSE TransB, + const int_tp M, const int_tp N, const int_tp K, + const Dtype alpha, const Dtype* A, const Dtype* B, + const Dtype beta, Dtype* C); -template -void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, const int N, - const Dtype alpha, const Dtype* A, const Dtype* x, const Dtype beta, - Dtype* y); +template +void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int_tp M, + const int_tp N, const Dtype alpha, const Dtype* A, + const Dtype* x, const Dtype beta, Dtype* y); -template -void caffe_axpy(const int N, const Dtype alpha, const Dtype* X, - Dtype* Y); +template +void caffe_axpy(const int_tp N, const Dtype alpha, const Dtype* X, Dtype* Y); -template -void caffe_cpu_axpby(const int N, const Dtype alpha, const Dtype* X, - const Dtype beta, Dtype* Y); +template +void caffe_cpu_axpby(const int_tp N, const Dtype alpha, const Dtype* X, + const Dtype beta, Dtype* Y); -template -void caffe_copy(const int N, const Dtype *X, Dtype *Y); +template +void caffe_cpu_copy(const int_tp N, const Dtype* X, Dtype* Y); -template -void caffe_set(const int N, const Dtype alpha, Dtype *X); +template +void caffe_copy(const int_tp N, const Dtype *X, Dtype *Y); -inline void caffe_memset(const size_t N, const int alpha, void* X) { +template +void caffe_set(const int_tp N, const Dtype alpha, Dtype *X); + +inline void caffe_memset(const uint_tp N, const int_tp alpha, void* X) { memset(X, alpha, N); // NOLINT(caffe/alt_fn) } -template -void caffe_add_scalar(const int N, const Dtype alpha, Dtype *X); +template +void caffe_add_scalar(const int_tp N, const Dtype alpha, Dtype *X); -template -void caffe_scal(const int N, const Dtype alpha, Dtype *X); +template +void caffe_scal(const int_tp N, const Dtype alpha, Dtype *X); -template -void caffe_sqr(const int N, const Dtype* a, Dtype* y); +template +void caffe_sqr(const int_tp N, const Dtype* a, Dtype* y); -template -void caffe_add(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_add(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_sub(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_sub(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_mul(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_mul(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_div(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_div(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_powx(const int n, const Dtype* a, const Dtype b, Dtype* y); +template +void caffe_powx(const int_tp n, const Dtype* a, const Dtype b, Dtype* y); -unsigned int caffe_rng_rand(); +uint_tp caffe_rng_rand(); -template +template Dtype caffe_nextafter(const Dtype b); -template -void caffe_rng_uniform(const int n, const Dtype a, const Dtype b, Dtype* r); +void caffe_rng_uniform(const int_tp n, uint_tp* r); -template -void caffe_rng_gaussian(const int n, const Dtype mu, const Dtype sigma, - Dtype* r); +template +void caffe_rng_uniform(const int_tp n, const Dtype a, const Dtype b, Dtype* r); -template -void caffe_rng_bernoulli(const int n, const Dtype p, int* r); +template +void caffe_rng_gaussian(const int_tp n, const Dtype mu, const Dtype sigma, + Dtype* r); -template -void caffe_rng_bernoulli(const int n, const Dtype p, unsigned int* r); +template +void caffe_rng_bernoulli(const int_tp n, const Dtype p, Itype* r); -template -void caffe_exp(const int n, const Dtype* a, Dtype* y); +template +void caffe_exp(const int_tp n, const Dtype* a, Dtype* y); -template -void caffe_log(const int n, const Dtype* a, Dtype* y); +template +void caffe_log(const int_tp n, const Dtype* a, Dtype* y); -template -void caffe_abs(const int n, const Dtype* a, Dtype* y); +template +void caffe_abs(const int_tp n, const Dtype* a, Dtype* y); -template -Dtype caffe_cpu_dot(const int n, const Dtype* x, const Dtype* y); +template +Dtype caffe_cpu_dot(const int_tp n, const Dtype* x, const Dtype* y); -template -Dtype caffe_cpu_strided_dot(const int n, const Dtype* x, const int incx, - const Dtype* y, const int incy); +template +Dtype caffe_cpu_strided_dot(const int_tp n, const Dtype* x, const int_tp incx, + const Dtype* y, const int_tp incy); // Returns the sum of the absolute values of the elements of vector x -template -Dtype caffe_cpu_asum(const int n, const Dtype* x); +template +Dtype caffe_cpu_asum(const int_tp n, const Dtype* x); // the branchless, type-safe version from // http://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c @@ -120,9 +121,9 @@ inline int8_t caffe_sign(Dtype val) { // So they have to be pasted here temporarily. #define DEFINE_CAFFE_CPU_UNARY_FUNC(name, operation) \ template \ - void caffe_cpu_##name(const int n, const Dtype* x, Dtype* y) { \ + void caffe_cpu_##name(const int_tp n, const Dtype* x, Dtype* y) { \ CHECK_GT(n, 0); CHECK(x); CHECK(y); \ - for (int i = 0; i < n; ++i) { \ + for (int_tp i = 0; i < n; ++i) { \ operation; \ } \ } @@ -134,138 +135,141 @@ DEFINE_CAFFE_CPU_UNARY_FUNC(sign, y[i] = caffe_sign(x[i])); // The name sngbit is meant to avoid conflicts with std::signbit in the macro. // The extra parens are needed because CUDA < 6.5 defines signbit as a macro, // and we don't want that to expand here when CUDA headers are also included. -DEFINE_CAFFE_CPU_UNARY_FUNC(sgnbit, \ - y[i] = static_cast((std::signbit)(x[i]))); +DEFINE_CAFFE_CPU_UNARY_FUNC(sgnbit, + y[i] = static_cast((std::signbit)(x[i]))); DEFINE_CAFFE_CPU_UNARY_FUNC(fabs, y[i] = std::fabs(x[i])); -template -void caffe_cpu_scale(const int n, const Dtype alpha, const Dtype *x, Dtype* y); +template +void caffe_cpu_scale(const int_tp n, const Dtype alpha, const Dtype *x, + Dtype* y); #ifndef CPU_ONLY // GPU +#ifdef USE_CUDA // Decaf gpu gemm provides an interface that is almost the same as the cpu // gemm function - following the c convention and calling the fortran-order // gpu code under the hood. -template -void caffe_gpu_gemm(const CBLAS_TRANSPOSE TransA, - const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, - const Dtype alpha, const Dtype* A, const Dtype* B, const Dtype beta, - Dtype* C); +template +void caffe_gpu_gemm(const CBLAS_TRANSPOSE TransA, const CBLAS_TRANSPOSE TransB, + const int_tp M, const int_tp N, const int_tp K, + const Dtype alpha, const Dtype* A, const Dtype* B, + const Dtype beta, Dtype* C); -template -void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, const int N, - const Dtype alpha, const Dtype* A, const Dtype* x, const Dtype beta, - Dtype* y); +template +void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int_tp M, + const int_tp N, const Dtype alpha, const Dtype* A, + const Dtype* x, const Dtype beta, Dtype* y); -template -void caffe_gpu_axpy(const int N, const Dtype alpha, const Dtype* X, - Dtype* Y); +template +void caffe_gpu_axpy(const int_tp N, const Dtype alpha, const Dtype* X, + Dtype* Y); -template -void caffe_gpu_axpby(const int N, const Dtype alpha, const Dtype* X, - const Dtype beta, Dtype* Y); +template +void caffe_gpu_axpby(const int_tp N, const Dtype alpha, const Dtype* X, + const Dtype beta, Dtype* Y); -void caffe_gpu_memcpy(const size_t N, const void *X, void *Y); +void caffe_gpu_memcpy(const uint_tp N, const void *X, void *Y); -template -void caffe_gpu_set(const int N, const Dtype alpha, Dtype *X); +template +void caffe_gpu_set(const int_tp N, const Dtype alpha, Dtype *X); -inline void caffe_gpu_memset(const size_t N, const int alpha, void* X) { -#ifndef CPU_ONLY +inline void caffe_gpu_memset(const uint_tp N, const int_tp alpha, void* X) { CUDA_CHECK(cudaMemset(X, alpha, N)); // NOLINT(caffe/alt_fn) -#else - NO_GPU; -#endif } -template -void caffe_gpu_add_scalar(const int N, const Dtype alpha, Dtype *X); +template +void caffe_gpu_add_scalar(const int_tp N, const Dtype alpha, Dtype *X); -template -void caffe_gpu_scal(const int N, const Dtype alpha, Dtype *X); +template +void caffe_gpu_scal(const int_tp N, const Dtype alpha, Dtype *X); -template -void caffe_gpu_add(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_gpu_add(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_gpu_sub(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_gpu_sub(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_gpu_mul(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_gpu_mul(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_gpu_div(const int N, const Dtype* a, const Dtype* b, Dtype* y); +template +void caffe_gpu_div(const int_tp N, const Dtype* a, const Dtype* b, Dtype* y); -template -void caffe_gpu_abs(const int n, const Dtype* a, Dtype* y); +template +void caffe_gpu_abs(const int_tp n, const Dtype* a, Dtype* y); -template -void caffe_gpu_exp(const int n, const Dtype* a, Dtype* y); +template +void caffe_gpu_exp(const int_tp n, const Dtype* a, Dtype* y); -template -void caffe_gpu_log(const int n, const Dtype* a, Dtype* y); +template +void caffe_gpu_log(const int_tp n, const Dtype* a, Dtype* y); -template -void caffe_gpu_powx(const int n, const Dtype* a, const Dtype b, Dtype* y); +template +void caffe_gpu_powx(const int_tp n, const Dtype* a, const Dtype b, Dtype* y); // caffe_gpu_rng_uniform with two arguments generates integers in the range // [0, UINT_MAX]. -void caffe_gpu_rng_uniform(const int n, unsigned int* r); +void caffe_gpu_rng_uniform(const int_tp n, unsigned int* r); // NOLINT +void caffe_gpu_rng_uniform(const int_tp n, unsigned long long* r); // NOLINT // caffe_gpu_rng_uniform with four arguments generates floats in the range // (a, b] (strictly greater than a, less than or equal to b) due to the // specification of curandGenerateUniform. With a = 0, b = 1, just calls // curandGenerateUniform; with other limits will shift and scale the outputs // appropriately after calling curandGenerateUniform. -template -void caffe_gpu_rng_uniform(const int n, const Dtype a, const Dtype b, Dtype* r); +template +void caffe_gpu_rng_uniform(const int_tp n, const Dtype a, const Dtype b, + Dtype* r); -template -void caffe_gpu_rng_gaussian(const int n, const Dtype mu, const Dtype sigma, +template +void caffe_gpu_rng_gaussian(const int_tp n, const Dtype mu, const Dtype sigma, Dtype* r); -template -void caffe_gpu_rng_bernoulli(const int n, const Dtype p, int* r); +template +void caffe_gpu_rng_bernoulli(const int_tp n, const Dtype p, int_tp* r); + +template +void caffe_gpu_dot(const int_tp n, const Dtype* x, const Dtype* y, Dtype* out); -template -void caffe_gpu_dot(const int n, const Dtype* x, const Dtype* y, Dtype* out); -template -void caffe_gpu_asum(const int n, const Dtype* x, Dtype* y); +template +void caffe_gpu_asum(const int_tp n, const Dtype* x, Dtype* y); template -void caffe_gpu_sign(const int n, const Dtype* x, Dtype* y); +void caffe_gpu_sign(const int_tp n, const Dtype* x, Dtype* y); template -void caffe_gpu_sgnbit(const int n, const Dtype* x, Dtype* y); +void caffe_gpu_sgnbit(const int_tp n, const Dtype* x, Dtype* y); -template -void caffe_gpu_fabs(const int n, const Dtype* x, Dtype* y); +template +void caffe_gpu_fabs(const int_tp n, const Dtype* x, Dtype* y); -template -void caffe_gpu_scale(const int n, const Dtype alpha, const Dtype *x, Dtype* y); +template +void caffe_gpu_scale(const int_tp n, const Dtype alpha, const Dtype *x, + Dtype* y); #define DEFINE_AND_INSTANTIATE_GPU_UNARY_FUNC(name, operation) \ template \ -__global__ void name##_kernel(const int n, const Dtype* x, Dtype* y) { \ +__global__ void name##_kernel(const int_tp n, const Dtype* x, Dtype* y) { \ CUDA_KERNEL_LOOP(index, n) { \ operation; \ } \ } \ template <> \ -void caffe_gpu_##name(const int n, const float* x, float* y) { \ +void caffe_gpu_##name(const int_tp n, const float* x, float* y) { \ /* NOLINT_NEXT_LINE(whitespace/operators) */ \ name##_kernel<<>>( \ n, x, y); \ } \ template <> \ -void caffe_gpu_##name(const int n, const double* x, double* y) { \ +void caffe_gpu_##name(const int_tp n, const double* x, double* y) { \ /* NOLINT_NEXT_LINE(whitespace/operators) */ \ name##_kernel<<>>( \ n, x, y); \ } +#endif // USE_CUDA #endif // !CPU_ONLY } // namespace caffe diff --git a/include/caffe/util/mkl_alternate.hpp b/include/caffe/util/mkl_alternate.hpp index 3355b6658a3..6db58cb665a 100644 --- a/include/caffe/util/mkl_alternate.hpp +++ b/include/caffe/util/mkl_alternate.hpp @@ -18,16 +18,16 @@ extern "C" { // be in the form e.g. y[i] = sqrt(a[i]) #define DEFINE_VSL_UNARY_FUNC(name, operation) \ template \ - void v##name(const int n, const Dtype* a, Dtype* y) { \ + void v##name(const int_tp n, const Dtype* a, Dtype* y) { \ CHECK_GT(n, 0); CHECK(a); CHECK(y); \ - for (int i = 0; i < n; ++i) { operation; } \ + for (int_tp i = 0; i < n; ++i) { operation; } \ } \ inline void vs##name( \ - const int n, const float* a, float* y) { \ + const int_tp n, const float* a, float* y) { \ v##name(n, a, y); \ } \ inline void vd##name( \ - const int n, const double* a, double* y) { \ + const int_tp n, const double* a, double* y) { \ v##name(n, a, y); \ } @@ -40,16 +40,16 @@ DEFINE_VSL_UNARY_FUNC(Abs, y[i] = fabs(a[i])); // The operation should be in the form e.g. y[i] = pow(a[i], b) #define DEFINE_VSL_UNARY_FUNC_WITH_PARAM(name, operation) \ template \ - void v##name(const int n, const Dtype* a, const Dtype b, Dtype* y) { \ + void v##name(const int_tp n, const Dtype* a, const Dtype b, Dtype* y) { \ CHECK_GT(n, 0); CHECK(a); CHECK(y); \ - for (int i = 0; i < n; ++i) { operation; } \ + for (int_tp i = 0; i < n; ++i) { operation; } \ } \ inline void vs##name( \ - const int n, const float* a, const float b, float* y) { \ + const int_tp n, const float* a, const float b, float* y) { \ v##name(n, a, b, y); \ } \ inline void vd##name( \ - const int n, const double* a, const float b, double* y) { \ + const int_tp n, const double* a, const float b, double* y) { \ v##name(n, a, b, y); \ } @@ -59,16 +59,16 @@ DEFINE_VSL_UNARY_FUNC_WITH_PARAM(Powx, y[i] = pow(a[i], b)); // be in the form e.g. y[i] = a[i] + b[i] #define DEFINE_VSL_BINARY_FUNC(name, operation) \ template \ - void v##name(const int n, const Dtype* a, const Dtype* b, Dtype* y) { \ + void v##name(const int_tp n, const Dtype* a, const Dtype* b, Dtype* y) { \ CHECK_GT(n, 0); CHECK(a); CHECK(b); CHECK(y); \ - for (int i = 0; i < n; ++i) { operation; } \ + for (int_tp i = 0; i < n; ++i) { operation; } \ } \ inline void vs##name( \ - const int n, const float* a, const float* b, float* y) { \ + const int_tp n, const float* a, const float* b, float* y) { \ v##name(n, a, b, y); \ } \ inline void vd##name( \ - const int n, const double* a, const double* b, double* y) { \ + const int_tp n, const double* a, const double* b, double* y) { \ v##name(n, a, b, y); \ } @@ -80,15 +80,15 @@ DEFINE_VSL_BINARY_FUNC(Div, y[i] = a[i] / b[i]); // In addition, MKL comes with an additional function axpby that is not present // in standard blas. We will simply use a two-step (inefficient, of course) way // to mimic that. -inline void cblas_saxpby(const int N, const float alpha, const float* X, - const int incX, const float beta, float* Y, - const int incY) { +inline void cblas_saxpby(const int_tp N, const float alpha, const float* X, + const int_tp incX, const float beta, float* Y, + const int_tp incY) { cblas_sscal(N, beta, Y, incY); cblas_saxpy(N, alpha, X, incX, Y, incY); } -inline void cblas_daxpby(const int N, const double alpha, const double* X, - const int incX, const double beta, double* Y, - const int incY) { +inline void cblas_daxpby(const int_tp N, const double alpha, const double* X, + const int_tp incX, const double beta, double* Y, + const int_tp incY) { cblas_dscal(N, beta, Y, incY); cblas_daxpy(N, alpha, X, incX, Y, incY); } diff --git a/include/caffe/util/rng.hpp b/include/caffe/util/rng.hpp index 8f1cf0d17c2..097c8d483eb 100644 --- a/include/caffe/util/rng.hpp +++ b/include/caffe/util/rng.hpp @@ -11,7 +11,7 @@ namespace caffe { -typedef boost::mt19937 rng_t; +typedef boost::mt19937_64 rng_t; inline rng_t* caffe_rng() { return static_cast(Caffe::rng_stream().generator()); diff --git a/matlab/+caffe/private/caffe_.cpp b/matlab/+caffe/private/caffe_.cpp index 1b1b2bff861..3065a99488e 100644 --- a/matlab/+caffe/private/caffe_.cpp +++ b/matlab/+caffe/private/caffe_.cpp @@ -17,7 +17,7 @@ #include "caffe/caffe.hpp" -#define MEX_ARGS int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs +#define MEX_ARGS int_tp nlhs, mxArray **plhs, int_tp nrhs, const mxArray **prhs using namespace caffe; // NOLINT(build/namespaces) @@ -78,9 +78,9 @@ static void mx_mat_to_blob(const mxArray* mx_mat, Blob* blob, // Copy Blob data or diff to matlab array static mxArray* blob_to_mx_mat(const Blob* blob, WhichMemory data_or_diff) { - const int num_axes = blob->num_axes(); + const int_tp num_axes = blob->num_axes(); vector dims(num_axes); - for (int blob_axis = 0, mat_axis = num_axes - 1; blob_axis < num_axes; + for (int_tp blob_axis = 0, mat_axis = num_axes - 1; blob_axis < num_axes; ++blob_axis, --mat_axis) { dims[mat_axis] = static_cast(blob->shape(blob_axis)); } @@ -106,11 +106,11 @@ static mxArray* blob_to_mx_mat(const Blob* blob, return mx_mat; } -// Convert vector to matlab row vector -static mxArray* int_vec_to_mx_vec(const vector& int_vec) { +// Convert vector to matlab row vector +static mxArray* int_vec_to_mx_vec(const vector& int_vec) { mxArray* mx_vec = mxCreateDoubleMatrix(int_vec.size(), 1, mxREAL); double* vec_mem_ptr = mxGetPr(mx_vec); - for (int i = 0; i < int_vec.size(); i++) { + for (int_tp i = 0; i < int_vec.size(); i++) { vec_mem_ptr[i] = static_cast(int_vec[i]); } return mx_vec; @@ -119,7 +119,7 @@ static mxArray* int_vec_to_mx_vec(const vector& int_vec) { // Convert vector to matlab cell vector of strings static mxArray* str_vec_to_mx_strcell(const vector& str_vec) { mxArray* mx_strcell = mxCreateCellMatrix(str_vec.size(), 1); - for (int i = 0; i < str_vec.size(); i++) { + for (int_tp i = 0; i < str_vec.size(); i++) { mxSetCell(mx_strcell, i, mxCreateString(str_vec[i].c_str())); } return mx_strcell; @@ -145,15 +145,15 @@ static T* handle_to_ptr(const mxArray* mx_handle) { // Create a handle struct vector, without setting up each handle in it template -static mxArray* create_handle_vec(int ptr_num) { - const int handle_field_num = 2; +static mxArray* create_handle_vec(int_tp ptr_num) { + const int_tp handle_field_num = 2; const char* handle_fields[handle_field_num] = { "ptr", "init_key" }; return mxCreateStructMatrix(ptr_num, 1, handle_field_num, handle_fields); } // Set up a handle in a handle struct vector by its index template -static void setup_handle(const T* ptr, int index, mxArray* mx_handle_vec) { +static void setup_handle(const T* ptr, int_tp index, mxArray* mx_handle_vec) { mxArray* mx_ptr = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL); *reinterpret_cast(mxGetData(mx_ptr)) = reinterpret_cast(ptr); @@ -173,7 +173,7 @@ static mxArray* ptr_to_handle(const T* ptr) { template static mxArray* ptr_vec_to_handle_vec(const vector >& ptr_vec) { mxArray* mx_handle_vec = create_handle_vec(ptr_vec.size()); - for (int i = 0; i < ptr_vec.size(); i++) { + for (int_tp i = 0; i < ptr_vec.size(); i++) { setup_handle(ptr_vec[i].get(), i, mx_handle_vec); } return mx_handle_vec; @@ -188,10 +188,7 @@ static void get_solver(MEX_ARGS) { "Usage: caffe_('get_solver', solver_file)"); char* solver_file = mxArrayToString(prhs[0]); mxCHECK_FILE_EXIST(solver_file); - SolverParameter solver_param; - ReadSolverParamsFromTextFileOrDie(solver_file, &solver_param); - shared_ptr > solver( - SolverRegistry::CreateSolver(solver_param)); + shared_ptr > solver(new caffe::SGDSolver(solver_file)); solvers_.push_back(solver); plhs[0] = ptr_to_handle >(solver.get()); mxFree(solver_file); @@ -202,7 +199,7 @@ static void solver_get_attr(MEX_ARGS) { mxCHECK(nrhs == 1 && mxIsStruct(prhs[0]), "Usage: caffe_('solver_get_attr', hSolver)"); Solver* solver = handle_to_ptr >(prhs[0]); - const int solver_attr_num = 2; + const int_tp solver_attr_num = 2; const char* solver_attrs[solver_attr_num] = { "hNet_net", "hNet_test_nets" }; mxArray* mx_solver_attr = mxCreateStructMatrix(1, 1, solver_attr_num, solver_attrs); @@ -245,7 +242,7 @@ static void solver_step(MEX_ARGS) { mxCHECK(nrhs == 2 && mxIsStruct(prhs[0]) && mxIsDouble(prhs[1]), "Usage: caffe_('solver_step', hSolver, iters)"); Solver* solver = handle_to_ptr >(prhs[0]); - int iters = mxGetScalar(prhs[1]); + int_tp iters = mxGetScalar(prhs[1]); solver->Step(iters); } @@ -276,7 +273,7 @@ static void net_get_attr(MEX_ARGS) { mxCHECK(nrhs == 1 && mxIsStruct(prhs[0]), "Usage: caffe_('net_get_attr', hNet)"); Net* net = handle_to_ptr >(prhs[0]); - const int net_attr_num = 6; + const int_tp net_attr_num = 6; const char* net_attrs[net_attr_num] = { "hLayer_layers", "hBlob_blobs", "input_blob_indices", "output_blob_indices", "layer_names", "blob_names"}; mxArray* mx_net_attr = mxCreateStructMatrix(1, 1, net_attr_num, @@ -348,7 +345,7 @@ static void layer_get_attr(MEX_ARGS) { mxCHECK(nrhs == 1 && mxIsStruct(prhs[0]), "Usage: caffe_('layer_get_attr', hLayer)"); Layer* layer = handle_to_ptr >(prhs[0]); - const int layer_attr_num = 1; + const int_tp layer_attr_num = 1; const char* layer_attrs[layer_attr_num] = { "hBlob_blobs" }; mxArray* mx_layer_attr = mxCreateStructMatrix(1, 1, layer_attr_num, layer_attrs); @@ -370,10 +367,10 @@ static void blob_get_shape(MEX_ARGS) { mxCHECK(nrhs == 1 && mxIsStruct(prhs[0]), "Usage: caffe_('blob_get_shape', hBlob)"); Blob* blob = handle_to_ptr >(prhs[0]); - const int num_axes = blob->num_axes(); + const int_tp num_axes = blob->num_axes(); mxArray* mx_shape = mxCreateDoubleMatrix(1, num_axes, mxREAL); double* shape_mem_mtr = mxGetPr(mx_shape); - for (int blob_axis = 0, mat_axis = num_axes - 1; blob_axis < num_axes; + for (int_tp blob_axis = 0, mat_axis = num_axes - 1; blob_axis < num_axes; ++blob_axis, --mat_axis) { shape_mem_mtr[mat_axis] = static_cast(blob->shape(blob_axis)); } @@ -387,11 +384,11 @@ static void blob_reshape(MEX_ARGS) { Blob* blob = handle_to_ptr >(prhs[0]); const mxArray* mx_shape = prhs[1]; double* shape_mem_mtr = mxGetPr(mx_shape); - const int num_axes = mxGetNumberOfElements(mx_shape); - vector blob_shape(num_axes); - for (int blob_axis = 0, mat_axis = num_axes - 1; blob_axis < num_axes; + const int_tp num_axes = mxGetNumberOfElements(mx_shape); + vector blob_shape(num_axes); + for (int_tp blob_axis = 0, mat_axis = num_axes - 1; blob_axis < num_axes; ++blob_axis, --mat_axis) { - blob_shape[blob_axis] = static_cast(shape_mem_mtr[mat_axis]); + blob_shape[blob_axis] = static_cast(shape_mem_mtr[mat_axis]); } blob->Reshape(blob_shape); } @@ -444,7 +441,7 @@ static void set_mode_gpu(MEX_ARGS) { static void set_device(MEX_ARGS) { mxCHECK(nrhs == 1 && mxIsDouble(prhs[0]), "Usage: caffe_('set_device', device_id)"); - int device_id = static_cast(mxGetScalar(prhs[0])); + int_tp device_id = static_cast(mxGetScalar(prhs[0])); Caffe::SetDevice(device_id); } @@ -486,12 +483,12 @@ static void write_mean(MEX_ARGS) { mxCHECK(nrhs == 2 && mxIsSingle(prhs[0]) && mxIsChar(prhs[1]), "Usage: caffe_('write_mean', mean_data, mean_proto_file)"); char* mean_proto_file = mxArrayToString(prhs[1]); - int ndims = mxGetNumberOfDimensions(prhs[0]); + int_tp ndims = mxGetNumberOfDimensions(prhs[0]); mxCHECK(ndims >= 2 && ndims <= 3, "mean_data must have at 2 or 3 dimensions"); const mwSize *dims = mxGetDimensions(prhs[0]); - int width = dims[0]; - int height = dims[1]; - int channels; + int_tp width = dims[0]; + int_tp height = dims[1]; + int_tp channels; if (ndims == 3) channels = dims[2]; else @@ -565,7 +562,7 @@ void mexFunction(MEX_ARGS) { char* cmd = mxArrayToString(prhs[0]); bool dispatched = false; // Dispatch to cmd handler - for (int i = 0; handlers[i].func != NULL; i++) { + for (int_tp i = 0; handlers[i].func != NULL; i++) { if (handlers[i].cmd.compare(cmd) == 0) { handlers[i].func(nlhs, plhs, nrhs-1, prhs+1); dispatched = true; diff --git a/matlab/+caffe/run_tests.m b/matlab/+caffe/run_tests.m index 6dbf6b23151..93896855ac2 100644 --- a/matlab/+caffe/run_tests.m +++ b/matlab/+caffe/run_tests.m @@ -11,8 +11,7 @@ % put all test cases here results = [... run(caffe.test.test_net) ... - run(caffe.test.test_solver) ... - run(caffe.test.test_io) ]; + run(caffe.test.test_solver) ]; % reset caffe after testing caffe.reset_all(); diff --git a/models/bvlc_reference_caffenet/train_val.prototxt b/models/bvlc_reference_caffenet/train_val.prototxt index e3e427968ab..c79472e09ab 100644 --- a/models/bvlc_reference_caffenet/train_val.prototxt +++ b/models/bvlc_reference_caffenet/train_val.prototxt @@ -45,7 +45,7 @@ layer { # mean_value: 104 # mean_value: 117 # mean_value: 123 -# mirror: false +# mirror: true # } data_param { source: "examples/imagenet/ilsvrc12_val_lmdb" diff --git a/protoc_generator.sh b/protoc_generator.sh new file mode 100644 index 00000000000..f19a4b7bb98 --- /dev/null +++ b/protoc_generator.sh @@ -0,0 +1,3 @@ +protoc src/caffe/proto/caffe.proto --cpp_out=. +mkdir -p include/caffe/proto +mv src/caffe/proto/caffe.pb.h include/caffe/proto diff --git a/python/caffe/__init__.py b/python/caffe/__init__.py index e2881b89c1b..13ec4f2ea32 100644 --- a/python/caffe/__init__.py +++ b/python/caffe/__init__.py @@ -1,5 +1,5 @@ -from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver -from ._caffe import set_mode_cpu, set_mode_gpu, set_device, Layer, get_solver, layer_type_list +from .pycaffe import SolverParameter, Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver +from ._caffe import set_mode_cpu, set_mode_gpu, set_device, Layer, set_devices, select_device, enumerate_devices, Layer, get_solver, get_solver_from_file, layer_type_list from ._caffe import __version__ from .proto.caffe_pb2 import TRAIN, TEST from .classifier import Classifier diff --git a/python/caffe/_caffe.cpp b/python/caffe/_caffe.cpp index 12a574556c3..48b73e71862 100644 --- a/python/caffe/_caffe.cpp +++ b/python/caffe/_caffe.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include // NOLINT #include "caffe/caffe.hpp" +#include "caffe/definitions.hpp" #include "caffe/layers/memory_data_layer.hpp" #include "caffe/layers/python_layer.hpp" #include "caffe/sgd_solvers.hpp" @@ -37,6 +39,14 @@ const int NPY_DTYPE = NPY_FLOAT32; // Selecting mode. void set_mode_cpu() { Caffe::set_mode(Caffe::CPU); } void set_mode_gpu() { Caffe::set_mode(Caffe::GPU); } +void select_device(int id, bool listId) { Caffe::SelectDevice(id, listId); } +void set_devices(bp::tuple args) { + vector devices(bp::len(args)); + for (int i = 0; i < bp::len(args); ++i) { + devices[i] = bp::extract(args[i]); + } + Caffe::SetDevices(devices); +} // For convenience, check that input files can be opened, and raise an // exception that boost will send to Python if not (caffe could still crash @@ -52,24 +62,27 @@ static void CheckFile(const string& filename) { } void CheckContiguousArray(PyArrayObject* arr, string name, - int channels, int height, int width) { + vector shape) { if (!(PyArray_FLAGS(arr) & NPY_ARRAY_C_CONTIGUOUS)) { throw std::runtime_error(name + " must be C contiguous"); } + // This does not have to hold anymore + /* if (PyArray_NDIM(arr) != 4) { throw std::runtime_error(name + " must be 4-d"); } + */ if (PyArray_TYPE(arr) != NPY_FLOAT32) { throw std::runtime_error(name + " must be float32"); } - if (PyArray_DIMS(arr)[1] != channels) { - throw std::runtime_error(name + " has wrong number of channels"); - } - if (PyArray_DIMS(arr)[2] != height) { - throw std::runtime_error(name + " has wrong height"); - } - if (PyArray_DIMS(arr)[3] != width) { - throw std::runtime_error(name + " has wrong width"); + for (int_tp i = 1; i < PyArray_NDIM(arr); ++i) { + if (PyArray_DIMS(arr)[i] != shape[i]) { + throw std::runtime_error( + "Shape dimension " + std::to_string(i) + " has wrong size (" + + std::to_string(static_cast + (PyArray_DIMS(arr)[i])) + " vs. " + + std::to_string(shape[i]) + ")"); + } } } @@ -79,7 +92,7 @@ shared_ptr > Net_Init( CheckFile(param_file); shared_ptr > net(new Net(param_file, - static_cast(phase))); + static_cast(phase), Caffe::GetDefaultDevice())); return net; } @@ -90,7 +103,7 @@ shared_ptr > Net_Init_Load( CheckFile(pretrained_param_file); shared_ptr > net(new Net(param_file, - static_cast(phase))); + static_cast(phase), Caffe::GetDefaultDevice())); net->CopyTrainedLayersFrom(pretrained_param_file); return net; } @@ -101,11 +114,11 @@ void Net_Save(const Net& net, string filename) { WriteProtoToBinaryFile(net_param, filename.c_str()); } -void Net_SetInputArrays(Net* net, bp::object data_obj, +void Net_SetInputArrays(Net* net, int index, bp::object data_obj, bp::object labels_obj) { // check that this network has an input MemoryDataLayer shared_ptr > md_layer = - boost::dynamic_pointer_cast >(net->layers()[0]); + boost::dynamic_pointer_cast >(net->layers()[index]); if (!md_layer) { throw std::runtime_error("set_input_arrays may only be called if the" " first layer is a MemoryDataLayer"); @@ -116,9 +129,8 @@ void Net_SetInputArrays(Net* net, bp::object data_obj, reinterpret_cast(data_obj.ptr()); PyArrayObject* labels_arr = reinterpret_cast(labels_obj.ptr()); - CheckContiguousArray(data_arr, "data array", md_layer->channels(), - md_layer->height(), md_layer->width()); - CheckContiguousArray(labels_arr, "labels array", 1, 1, 1); + CheckContiguousArray(data_arr, "data array", md_layer->shape()); + CheckContiguousArray(labels_arr, "labels array", md_layer->label_shape()); if (PyArray_DIMS(data_arr)[0] != PyArray_DIMS(labels_arr)[0]) { throw std::runtime_error("data and labels must have the same first" " dimension"); @@ -139,6 +151,10 @@ Solver* GetSolverFromFile(const string& filename) { return SolverRegistry::CreateSolver(param); } +Solver* GetSolver(const SolverParameter& solver_param) { + return SolverRegistry::CreateSolver(solver_param); +} + struct NdarrayConverterGenerator { template struct apply; }; @@ -166,8 +182,8 @@ struct NdarrayCallPolicies : public bp::default_call_policies { // the shape information from the blob. void* data = PyArray_DATA(reinterpret_cast(result)); Py_DECREF(result); - const int num_axes = blob->num_axes(); - vector dims(blob->shape().begin(), blob->shape().end()); + const int_tp num_axes = blob->num_axes(); + vector dims(blob->shape().begin(), blob->shape().end()); PyObject *arr_obj = PyArray_SimpleNewFromData(num_axes, dims.data(), NPY_FLOAT32, data); // SetBaseObject steals a ref, so we need to INCREF. @@ -183,9 +199,9 @@ bp::object Blob_Reshape(bp::tuple args, bp::dict kwargs) { throw std::runtime_error("Blob.reshape takes no kwargs"); } Blob* self = bp::extract*>(args[0]); - vector shape(bp::len(args) - 1); - for (int i = 1; i < bp::len(args); ++i) { - shape[i - 1] = bp::extract(args[i]); + vector shape(bp::len(args) - 1); + for (int_tp i = 1; i < bp::len(args); ++i) { + shape[i - 1] = bp::extract(args[i]); } self->Reshape(shape); // We need to explicitly return None to use bp::raw_function. @@ -198,18 +214,57 @@ bp::object BlobVec_add_blob(bp::tuple args, bp::dict kwargs) { } typedef vector > > BlobVec; BlobVec* self = bp::extract(args[0]); - vector shape(bp::len(args) - 1); - for (int i = 1; i < bp::len(args); ++i) { - shape[i - 1] = bp::extract(args[i]); + vector shape(bp::len(args) - 1); + for (int_tp i = 1; i < bp::len(args); ++i) { + shape[i - 1] = bp::extract(args[i]); } self->push_back(shared_ptr >(new Blob(shape))); // We need to explicitly return None to use bp::raw_function. return bp::object(); } +void exception_translator(std::exception ex) { + std::cout << ex.what() << std::endl; +} + +// NOLINT_NEXT_LINE(runtime/references) +Dtype ForwardFromTo_NoGIL(Net& net, int_tp start, int_tp end) { + Dtype loss; + Py_BEGIN_ALLOW_THREADS + loss = net.ForwardFromTo(start, end); + Py_END_ALLOW_THREADS + return loss; +} + +// NOLINT_NEXT_LINE(runtime/references) +void BackwardFromTo_NoGIL(Net& net, int_tp start, int_tp end) { + Py_BEGIN_ALLOW_THREADS + net.BackwardFromTo(start, end); + Py_END_ALLOW_THREADS +} + +// NOLINT_NEXT_LINE(runtime/references) +Dtype Step_NoGIL(Solver& solver, int_tp iters) { + Dtype smoothed_loss; + Py_BEGIN_ALLOW_THREADS + smoothed_loss = solver.Step(iters); + Py_END_ALLOW_THREADS + return smoothed_loss; +} + +// NOLINT_NEXT_LINE(runtime/references) +void Solve_NoGIL(Solver& solver, const char* resume_file) { + Py_BEGIN_ALLOW_THREADS + solver.Solve(resume_file); + Py_END_ALLOW_THREADS +} + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(SolveOverloads, Solve, 0, 1); BOOST_PYTHON_MODULE(_caffe) { + bp::register_exception_translator(&exception_translator); + // below, we prepend an underscore to methods that will be replaced // in Python @@ -219,6 +274,9 @@ BOOST_PYTHON_MODULE(_caffe) { bp::def("set_mode_cpu", &set_mode_cpu); bp::def("set_mode_gpu", &set_mode_gpu); bp::def("set_device", &Caffe::SetDevice); + bp::def("set_devices", &set_devices); + bp::def("select_device", &select_device); + bp::def("enumerate_devices", &Caffe::EnumerateDevices); bp::def("layer_type_list", &LayerRegistry::LayerTypeList); @@ -226,8 +284,8 @@ BOOST_PYTHON_MODULE(_caffe) { bp::no_init) .def("__init__", bp::make_constructor(&Net_Init)) .def("__init__", bp::make_constructor(&Net_Init_Load)) - .def("_forward", &Net::ForwardFromTo) - .def("_backward", &Net::BackwardFromTo) + .def("_forward", &ForwardFromTo_NoGIL) + .def("_backward", &BackwardFromTo_NoGIL) .def("reshape", &Net::Reshape) // The cast is to select a particular overload. .def("copy_from", static_cast::*)(const string)>( @@ -253,21 +311,22 @@ BOOST_PYTHON_MODULE(_caffe) { bp::make_function(&Net::output_blob_indices, bp::return_value_policy())) .def("_set_input_arrays", &Net_SetInputArrays, - bp::with_custodian_and_ward<1, 2, bp::with_custodian_and_ward<1, 3> >()) + bp::with_custodian_and_ward<1, 3, + bp::with_custodian_and_ward<1, 4> > ()) .def("save", &Net_Save); bp::class_, shared_ptr >, boost::noncopyable>( "Blob", bp::no_init) .add_property("shape", bp::make_function( - static_cast& (Blob::*)() const>( + static_cast& (Blob::*)() const>( &Blob::shape), bp::return_value_policy())) .add_property("num", &Blob::num) .add_property("channels", &Blob::channels) .add_property("height", &Blob::height) .add_property("width", &Blob::width) - .add_property("count", static_cast::*)() const>( + .add_property("count", static_cast::*)() const>( &Blob::count)) .def("reshape", bp::raw_function(&Blob_Reshape)) .add_property("data", bp::make_function(&Blob::mutable_cpu_data, @@ -289,15 +348,82 @@ BOOST_PYTHON_MODULE(_caffe) { bp::class_, shared_ptr >, boost::noncopyable>( "Solver", bp::no_init) .add_property("net", &Solver::net) + .add_property("max_iter", &Solver::max_iter) .add_property("test_nets", bp::make_function(&Solver::test_nets, bp::return_internal_reference<>())) .add_property("iter", &Solver::iter) - .def("solve", static_cast::*)(const char*)>( - &Solver::Solve), SolveOverloads()) - .def("step", &Solver::Step) + .add_property("solver_params", &Solver::GetSolverParams, + &Solver::UpdateSolverParams) + .def("step", &Step_NoGIL) + .def("solve", &Solve_NoGIL) .def("restore", &Solver::Restore) .def("snapshot", &Solver::Snapshot); + + bp::class_("SolverParameter", bp::init<>()) + .add_property("base_lr", &SolverParameter::base_lr, + &SolverParameter::set_base_lr) + .add_property("max_iter", &SolverParameter::max_iter, + &SolverParameter::set_max_iter) + .add_property("lr_policy", + bp::make_function(&SolverParameter::lr_policy, + bp::return_value_policy()), + static_cast( + &SolverParameter::set_lr_policy)) + .add_property("gamma", &SolverParameter::gamma, + &SolverParameter::set_gamma) + .add_property("power", &SolverParameter::power, + &SolverParameter::set_power) + .add_property("momentum", &SolverParameter::momentum, + &SolverParameter::set_momentum) + .add_property("momentum2", &SolverParameter::momentum2, + &SolverParameter::set_momentum2) + .add_property("delta", &SolverParameter::delta, + &SolverParameter::set_delta) + .add_property("rms_decay", &SolverParameter::rms_decay, + &SolverParameter::set_rms_decay) + .add_property("weight_decay", + &SolverParameter::weight_decay, + &SolverParameter::set_weight_decay) + .add_property("display", &SolverParameter::display, + &SolverParameter::set_display) + .add_property("regularization_type", + bp::make_function(&SolverParameter::regularization_type, + bp::return_value_policy()), + static_cast( + &SolverParameter::set_regularization_type)) + .add_property("stepsize", &SolverParameter::stepsize, + &SolverParameter::set_stepsize) + .add_property("snapshot", &SolverParameter::snapshot, + &SolverParameter::set_snapshot) + .add_property("snapshot_format", &SolverParameter::snapshot_format, + &SolverParameter::set_snapshot_format) + .add_property("snapshot_prefix", + bp::make_function(&SolverParameter::snapshot_prefix, + bp::return_value_policy()), + static_cast( + &SolverParameter::set_snapshot_prefix)) + .add_property("type", + bp::make_function(&SolverParameter::type, + bp::return_value_policy()), + static_cast( + &SolverParameter::set_type)) + .add_property("net", + bp::make_function(&SolverParameter::net, + bp::return_value_policy()), + static_cast( + &SolverParameter::set_net)) + .add_property("train_net", + bp::make_function(&SolverParameter::train_net, + bp::return_value_policy()), + static_cast( + &SolverParameter::set_train_net)); + + bp::enum_<::caffe::SolverParameter_SnapshotFormat>("snapshot_format") + .value("HDF5", SolverParameter_SnapshotFormat_HDF5) + .value("BINARYPROTO", SolverParameter_SnapshotFormat_BINARYPROTO); + + bp::class_, bp::bases >, shared_ptr >, boost::noncopyable>( "SGDSolver", bp::init()); @@ -317,7 +443,10 @@ BOOST_PYTHON_MODULE(_caffe) { shared_ptr >, boost::noncopyable>( "AdamSolver", bp::init()); - bp::def("get_solver", &GetSolverFromFile, + bp::def("get_solver_from_file", &GetSolverFromFile, + bp::return_value_policy()); + + bp::def("get_solver", &GetSolver, bp::return_value_policy()); // vector wrappers for all the vector types we use @@ -330,6 +459,8 @@ BOOST_PYTHON_MODULE(_caffe) { .def(bp::vector_indexing_suite > >, true>()); bp::class_ >("StringVec") .def(bp::vector_indexing_suite >()); + bp::class_ >("IntTpVec") + .def(bp::vector_indexing_suite >()); bp::class_ >("IntVec") .def(bp::vector_indexing_suite >()); bp::class_ >("DtypeVec") diff --git a/python/caffe/draw.py b/python/caffe/draw.py index cfa3fc5b1fb..b51a016ac1e 100644 --- a/python/caffe/draw.py +++ b/python/caffe/draw.py @@ -86,29 +86,33 @@ def get_layer_label(layer, rankdir): if layer.type == 'Convolution' or layer.type == 'Deconvolution': # Outer double quotes needed or else colon characters don't parse # properly - node_label = '"%s%s(%s)%skernel size: %d%sstride: %d%spad: %d"' %\ + node_label = '"%s%s(%s)%skernel size: %d%sstride: %d%spad: %d%sdilation: %d"' %\ (layer.name, separator, layer.type, separator, - layer.convolution_param.kernel_size[0] if len(layer.convolution_param.kernel_size._values) else 1, + layer.convolution_param.kernel_size[0] if len(layer.convolution_param.kernel_size) > 0 else 1, separator, - layer.convolution_param.stride[0] if len(layer.convolution_param.stride._values) else 1, + layer.convolution_param.stride[0] if len(layer.convolution_param.stride) > 0 else 1, separator, - layer.convolution_param.pad[0] if len(layer.convolution_param.pad._values) else 0) + layer.convolution_param.pad[0] if len(layer.convolution_param.pad) > 0 else 0, + separator, + layer.convolution_param.dilation[0] if len(layer.convolution_param.dilation) > 0 else 1) elif layer.type == 'Pooling': pooling_types_dict = get_pooling_types_dict() - node_label = '"%s%s(%s %s)%skernel size: %d%sstride: %d%spad: %d"' %\ + node_label = '"%s%s(%s %s)%skernel size: %d%sstride: %d%spad: %d%sdilation: %d"' %\ (layer.name, separator, pooling_types_dict[layer.pooling_param.pool], layer.type, separator, - layer.pooling_param.kernel_size, + layer.pooling_param.kernel_size[0] if len(layer.pooling_param.kernel_size) > 0 else 1, + separator, + layer.pooling_param.stride[0] if len(layer.pooling_param.stride) > 0 else 1, separator, - layer.pooling_param.stride, + layer.pooling_param.pad[0] if len(layer.pooling_param.pad) > 0 else 0, separator, - layer.pooling_param.pad) + layer.pooling_param.dilation[0] if len(layer.pooling_param.dilation) > 0 else 1) else: node_label = '"%s%s(%s)"' % (layer.name, separator, layer.type) return node_label @@ -127,7 +131,7 @@ def choose_color_by_layertype(layertype): return color -def get_pydot_graph(caffe_net, rankdir, label_edges=True): +def get_pydot_graph(caffe_net, rankdir, margin, page, pagesize, size, label_edges=True): """Create a data structure which represents the `caffe_net`. Parameters @@ -142,9 +146,17 @@ def get_pydot_graph(caffe_net, rankdir, label_edges=True): ------- pydot graph object """ + pydot_graph = pydot.Dot(caffe_net.name, graph_type='digraph', rankdir=rankdir) + + if margin != '': pydot_graph.set('margin',margin) + if page != '': pydot_graph.set('page', page) + if pagesize != '': pydot_graph.set('pagesize', pagesize) + if size != '': pydot_graph.set('size', size) + + pydot_nodes = {} pydot_edges = [] for layer in caffe_net.layer: @@ -186,7 +198,7 @@ def get_pydot_graph(caffe_net, rankdir, label_edges=True): return pydot_graph -def draw_net(caffe_net, rankdir, ext='png'): +def draw_net(caffe_net, rankdir, margin, page, pagesize, size, ext='png'): """Draws a caffe net and returns the image string encoded using the given extension. @@ -201,10 +213,10 @@ def draw_net(caffe_net, rankdir, ext='png'): string : Postscript representation of the graph. """ - return get_pydot_graph(caffe_net, rankdir).create(format=ext) + return get_pydot_graph(caffe_net, rankdir, margin, page, pagesize, size).create(format=ext) -def draw_net_to_file(caffe_net, filename, rankdir='LR'): +def draw_net_to_file(caffe_net, filename, rankdir='LR', margin='', page='', pagesize='', size=''): """Draws a caffe net, and saves it to file using the format given as the file extension. Use '.raw' to output raw text that you can manually feed to graphviz to draw graphs. @@ -219,4 +231,4 @@ def draw_net_to_file(caffe_net, filename, rankdir='LR'): """ ext = filename[filename.rfind('.')+1:] with open(filename, 'wb') as fid: - fid.write(draw_net(caffe_net, rankdir, ext)) + fid.write(draw_net(caffe_net, rankdir, margin, page, pagesize, size, ext)) diff --git a/python/caffe/net_spec.py b/python/caffe/net_spec.py index 93fc01927db..64e16e0fefe 100644 --- a/python/caffe/net_spec.py +++ b/python/caffe/net_spec.py @@ -76,8 +76,10 @@ def assign_proto(proto, name, val): for k, v in six.iteritems(val): assign_proto(getattr(proto, name), k, v) else: - setattr(proto, name, val) - + try: + setattr(proto, name, val) + except (AttributeError): + getattr(proto, name).append(val) class Top(object): """A Top specifies a single output blob (which could be one of several diff --git a/python/caffe/pycaffe.py b/python/caffe/pycaffe.py index 3054110771c..5b4b48a6ca6 100644 --- a/python/caffe/pycaffe.py +++ b/python/caffe/pycaffe.py @@ -10,8 +10,10 @@ from itertools import zip_longest as izip_longest import numpy as np -from ._caffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, \ - RMSPropSolver, AdaDeltaSolver, AdamSolver +from ._caffe import \ + SolverParameter, Net, SGDSolver, NesterovSolver, AdaGradSolver, \ + RMSPropSolver, AdaDeltaSolver, AdamSolver + import caffe.io # We directly update methods from Net here (rather than using composition or @@ -232,7 +234,7 @@ def _Net_forward_backward_all(self, blobs=None, diffs=None, **kwargs): return all_outs, all_diffs -def _Net_set_input_arrays(self, data, labels): +def _Net_set_input_arrays(self, index, data, labels): """ Set input arrays of the in-memory MemoryDataLayer. (Note: this is only for networks declared with the memory data layer.) @@ -240,7 +242,7 @@ def _Net_set_input_arrays(self, data, labels): if labels.ndim == 1: labels = np.ascontiguousarray(labels[:, np.newaxis, np.newaxis, np.newaxis]) - return self._set_input_arrays(data, labels) + return self._set_input_arrays(index, data, labels) def _Net_batch(self, blobs): diff --git a/python/draw_net.py b/python/draw_net.py index ec76a744da3..811274d976b 100755 --- a/python/draw_net.py +++ b/python/draw_net.py @@ -28,6 +28,18 @@ def parse_args(): 'http://www.graphviz.org/doc/info/' 'attrs.html#k:rankdir'), default='LR') + parser.add_argument('--margin', + help=('Margin parameter'), + default='') + parser.add_argument('--page', + help=('Page parameter'), + default='') + parser.add_argument('--pagesize', + help=('Pagesize parameter'), + default='') + parser.add_argument('--size', + help=('Size parameter'), + default='') args = parser.parse_args() return args @@ -38,7 +50,8 @@ def main(): net = caffe_pb2.NetParameter() text_format.Merge(open(args.input_net_proto_file).read(), net) print('Drawing net to %s' % args.output_image_file) - caffe.draw.draw_net_to_file(net, args.output_image_file, args.rankdir) + caffe.draw.draw_net_to_file(net, args.output_image_file, args.rankdir, + args.margin, args.page, args.pagesize, args.size) if __name__ == '__main__': diff --git a/scripts/travis/travis_build_and_test.sh b/scripts/travis/travis_build_and_test.sh index 174f1ee5a0a..317b1f75494 100755 --- a/scripts/travis/travis_build_and_test.sh +++ b/scripts/travis/travis_build_and_test.sh @@ -3,7 +3,8 @@ # Travis CI tests are CPU-only for lack of compatible hardware. set -e -MAKE="make --jobs=$NUM_THREADS --keep-going" +# Limit jobs to stay within available RAM/Swap +MAKE="make --jobs=2 --keep-going" if $WITH_CMAKE; then mkdir build diff --git a/scripts/travis/travis_install.sh b/scripts/travis/travis_install.sh index d18dc223a06..22bb3dd023a 100755 --- a/scripts/travis/travis_install.sh +++ b/scripts/travis/travis_install.sh @@ -8,16 +8,29 @@ MAKE="make --jobs=$NUM_THREADS" # This ppa is for gflags and glog add-apt-repository -y ppa:tuleu/precise-backports +# This ppa is for boost 1.54 +add-apt-repository -y ppa:boost-latest/ppa +# This ppa is for g++ 4.9 +add-apt-repository -y ppa:ubuntu-toolchain-r/test +# This ppa is for ViennaCL +add-apt-repository -y ppa:tsmithe/pyviennacl + apt-get -y update apt-get install \ - wget git curl \ + gcc-4.9 g++-4.9 wget git curl \ python-dev python-numpy python3-dev\ libleveldb-dev libsnappy-dev libopencv-dev \ + libboost1.54-dev libboost-system1.54-dev libboost-python1.54-dev libboost-thread1.54-dev \ libprotobuf-dev protobuf-compiler \ libatlas-dev libatlas-base-dev \ + fglrx opencl-headers \ + libviennacl-dev \ libhdf5-serial-dev libgflags-dev libgoogle-glog-dev \ bc +update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90 +update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 + # Add a special apt-repository to install CMake 2.8.9 for CMake Caffe build, # if needed. By default, Aptitude in Ubuntu 12.04 installs CMake 2.8.7, but # Caffe requires a minimum CMake version of 2.8.8. @@ -30,7 +43,7 @@ fi # Install CUDA, if needed if $WITH_CUDA; then - CUDA_URL=http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1204/x86_64/cuda-repo-ubuntu1204_6.5-14_amd64.deb + CUDA_URL=http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1204/x86_64/cuda-repo-ubuntu1204_7.0-28_amd64.deb CUDA_FILE=/tmp/cuda_install.deb curl $CUDA_URL -o $CUDA_FILE dpkg -i $CUDA_FILE @@ -38,11 +51,11 @@ if $WITH_CUDA; then apt-get -y update # Install the minimal CUDA subpackages required to test Caffe build. # For a full CUDA installation, add 'cuda' to the list of packages. - apt-get -y install cuda-core-6-5 cuda-cublas-6-5 cuda-cublas-dev-6-5 cuda-cudart-6-5 cuda-cudart-dev-6-5 cuda-curand-6-5 cuda-curand-dev-6-5 + apt-get -y install cuda-core-7-0 cuda-cublas-7-0 cuda-cublas-dev-7-0 cuda-cudart-7-0 cuda-cudart-dev-7-0 cuda-curand-7-0 cuda-curand-dev-7-0 # Create CUDA symlink at /usr/local/cuda # (This would normally be created by the CUDA installer, but we create it # manually since we did a partial installation.) - ln -s /usr/local/cuda-6.5 /usr/local/cuda + ln -s /usr/local/cuda-7.0 /usr/local/cuda fi # Install LMDB diff --git a/src/caffe/CMakeLists.txt b/src/caffe/CMakeLists.txt index 8a80c940488..3f2f19de865 100644 --- a/src/caffe/CMakeLists.txt +++ b/src/caffe/CMakeLists.txt @@ -12,7 +12,7 @@ caffe_default_properties(proto) # creates 'test_srcs', 'srcs', 'test_cuda', 'cuda' lists caffe_pickup_caffe_sources(${PROJECT_SOURCE_DIR}) -if(HAVE_CUDA) +if(USE_CUDA AND HAVE_CUDA) caffe_cuda_compile(cuda_objs ${cuda}) list(APPEND srcs ${cuda_objs} ${cuda}) endif() diff --git a/src/caffe/blob.cpp b/src/caffe/blob.cpp index c86fd5d1d94..5f5a7573b8f 100644 --- a/src/caffe/blob.cpp +++ b/src/caffe/blob.cpp @@ -2,143 +2,153 @@ #include #include "caffe/blob.hpp" + +#include "../../include/caffe/device.hpp" #include "caffe/common.hpp" #include "caffe/syncedmem.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -void Blob::Reshape(const int num, const int channels, const int height, - const int width) { - vector shape(4); +template +bool Blob::Reshape(const int_tp num, const int_tp channels, + const int_tp height, const int_tp width) { + vector shape(4); shape[0] = num; shape[1] = channels; shape[2] = height; shape[3] = width; - Reshape(shape); + return Reshape(shape); } -template -void Blob::Reshape(const vector& shape) { +template +bool Blob::Reshape(const vector& shape) { CHECK_LE(shape.size(), kMaxBlobAxes); count_ = 1; shape_.resize(shape.size()); - if (!shape_data_ || shape_data_->size() < shape.size() * sizeof(int)) { - shape_data_.reset(new SyncedMemory(shape.size() * sizeof(int))); + if (!shape_data_ || shape_data_->size() < shape.size() * sizeof(int_tp)) { + shape_data_.reset( + new SyncedMemory(shape.size() * sizeof(int_tp), device_)); } - int* shape_data = static_cast(shape_data_->mutable_cpu_data()); - for (int i = 0; i < shape.size(); ++i) { + int_tp* shape_data = static_cast(shape_data_->mutable_cpu_data()); + for (int_tp i = 0; i < shape.size(); ++i) { CHECK_GE(shape[i], 0); - CHECK_LE(shape[i], INT_MAX / count_) << "blob size exceeds INT_MAX"; + CHECK_LE(shape[i], LONG_MAX / count_)<< "blob size exceeds INT_MAX"; count_ *= shape[i]; shape_[i] = shape[i]; shape_data[i] = shape[i]; } if (count_ > capacity_) { capacity_ = count_; - data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype))); - diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype))); + data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype), device_)); + diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype), device_)); + return true; } + return false; } -template -void Blob::Reshape(const BlobShape& shape) { +template +bool Blob::Reshape(const BlobShape& shape) { CHECK_LE(shape.dim_size(), kMaxBlobAxes); - vector shape_vec(shape.dim_size()); - for (int i = 0; i < shape.dim_size(); ++i) { + vector shape_vec(shape.dim_size()); + for (int_tp i = 0; i < shape.dim_size(); ++i) { shape_vec[i] = shape.dim(i); } - Reshape(shape_vec); + return Reshape(shape_vec); } -template -void Blob::ReshapeLike(const Blob& other) { - Reshape(other.shape()); +template +bool Blob::ReshapeLike(const Blob& other) { + return Reshape(other.shape()); } -template -Blob::Blob(const int num, const int channels, const int height, - const int width) - // capacity_ must be initialized before calling Reshape - : capacity_(0) { +template +Blob::Blob(const int_tp num, const int_tp channels, const int_tp height, + const int_tp width, device *device_context) + // capacity_ must be initialized before calling Reshape + : capacity_(0), device_(device_context) { Reshape(num, channels, height, width); } -template -Blob::Blob(const vector& shape) - // capacity_ must be initialized before calling Reshape - : capacity_(0) { +template +Blob::Blob(const vector& shape, device *device_context) + // capacity_ must be initialized before calling Reshape + : capacity_(0), device_(device_context) { Reshape(shape); } template -const int* Blob::gpu_shape() const { +const int_tp* Blob::gpu_shape() const { CHECK(shape_data_); - return (const int*)shape_data_->gpu_data(); + return (const int_tp*)shape_data_->gpu_data(); } template const Dtype* Blob::cpu_data() const { CHECK(data_); - return (const Dtype*)data_->cpu_data(); + return (const Dtype*) data_->cpu_data(); } -template +template void Blob::set_cpu_data(Dtype* data) { CHECK(data); data_->set_cpu_data(data); } -template +template const Dtype* Blob::gpu_data() const { CHECK(data_); - return (const Dtype*)data_->gpu_data(); + return (const Dtype*) data_->gpu_data(); } -template +template const Dtype* Blob::cpu_diff() const { CHECK(diff_); - return (const Dtype*)diff_->cpu_data(); + return (const Dtype*) diff_->cpu_data(); } -template +template const Dtype* Blob::gpu_diff() const { CHECK(diff_); - return (const Dtype*)diff_->gpu_data(); + return (const Dtype*) diff_->gpu_data(); } -template +template Dtype* Blob::mutable_cpu_data() { CHECK(data_); return static_cast(data_->mutable_cpu_data()); } -template +template Dtype* Blob::mutable_gpu_data() { CHECK(data_); return static_cast(data_->mutable_gpu_data()); } -template +template Dtype* Blob::mutable_cpu_diff() { CHECK(diff_); return static_cast(diff_->mutable_cpu_data()); } -template +template Dtype* Blob::mutable_gpu_diff() { CHECK(diff_); return static_cast(diff_->mutable_gpu_data()); } -template +template void Blob::ShareData(const Blob& other) { CHECK_EQ(count_, other.count()); data_ = other.data(); } -template +template void Blob::ShareDiff(const Blob& other) { CHECK_EQ(count_, other.count()); diff_ = other.diff(); @@ -146,308 +156,423 @@ void Blob::ShareDiff(const Blob& other) { // The "update" method is used for parameter blobs in a Net, which are stored // as Blob or Blob -- hence we do not define it for -// Blob or Blob. -template <> void Blob::Update() { NOT_IMPLEMENTED; } -template <> void Blob::Update() { NOT_IMPLEMENTED; } +// Blob or Blob. +template<> void Blob::Update() { + NOT_IMPLEMENTED; +} +template<> void Blob::Update() { + NOT_IMPLEMENTED; +} -template +template void Blob::Update() { // We will perform update based on where the data is located. switch (data_->head()) { - case SyncedMemory::HEAD_AT_CPU: - // perform computation on CPU - caffe_axpy(count_, Dtype(-1), - static_cast(diff_->cpu_data()), - static_cast(data_->mutable_cpu_data())); - break; - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + case SyncedMemory::HEAD_AT_CPU: { + // perform computation on CPU + caffe_axpy(count_, Dtype(-1), + static_cast(diff_->cpu_data()), + static_cast(data_->mutable_cpu_data())); + + break; + } + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - // perform computation on GPU - caffe_gpu_axpy(count_, Dtype(-1), - static_cast(diff_->gpu_data()), - static_cast(data_->mutable_gpu_data())); + // perform computation on GPU + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_axpy(count_, Dtype(-1), + static_cast(diff_->gpu_data()), + static_cast(data_->mutable_gpu_data())); +#endif + } else { +#ifdef USE_GREENTEA + greentea_gpu_axpy(device_->id(), count_, Dtype(-1), + (cl_mem) (diff_->gpu_data()), 0, + (cl_mem) (data_->mutable_gpu_data()), 0); +#endif + } #else - NO_GPU; + NO_GPU; #endif - break; - default: - LOG(FATAL) << "Syncedmem not initialized."; + break; + } + default: + LOG(FATAL)<< "Syncedmem not initialized."; + } } -} -template <> unsigned int Blob::asum_data() const { +template<> uint_tp Blob::asum_data() const { NOT_IMPLEMENTED; return 0; } -template <> int Blob::asum_data() const { +template +device *Blob::get_device() { + return device_; +} + +template<> int_tp Blob::asum_data() const { NOT_IMPLEMENTED; return 0; } -template +template Dtype Blob::asum_data() const { - if (!data_) { return 0; } + if (!data_) { + return 0; + } switch (data_->head()) { - case SyncedMemory::HEAD_AT_CPU: - return caffe_cpu_asum(count_, cpu_data()); - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + case SyncedMemory::HEAD_AT_CPU: + return caffe_cpu_asum(count_, cpu_data()); + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - { - Dtype asum; - caffe_gpu_asum(count_, gpu_data(), &asum); - return asum; - } + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + Dtype asum; + caffe_gpu_asum(count_, gpu_data(), &asum); + return asum; +#endif + } else { +#ifdef USE_GREENTEA + Dtype asum; + greentea_gpu_asum(device_->id(), count_, (cl_mem) gpu_data(), 0, + &asum); + return asum; +#endif + } #else - NO_GPU; + NO_GPU; #endif - case SyncedMemory::UNINITIALIZED: - return 0; - default: - LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head(); - } + } + case SyncedMemory::UNINITIALIZED: + return 0; + default: + LOG(FATAL)<< "Unknown SyncedMemory head state: " << data_->head(); + } return 0; } -template <> unsigned int Blob::asum_diff() const { +template<> uint_tp Blob::asum_diff() const { NOT_IMPLEMENTED; return 0; } -template <> int Blob::asum_diff() const { +template<> int_tp Blob::asum_diff() const { NOT_IMPLEMENTED; return 0; } -template +template Dtype Blob::asum_diff() const { - if (!diff_) { return 0; } + if (!diff_) { + return 0; + } switch (diff_->head()) { - case SyncedMemory::HEAD_AT_CPU: - return caffe_cpu_asum(count_, cpu_diff()); - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + case SyncedMemory::HEAD_AT_CPU: + return caffe_cpu_asum(count_, cpu_diff()); + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - { - Dtype asum; - caffe_gpu_asum(count_, gpu_diff(), &asum); - return asum; - } + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + Dtype asum; + caffe_gpu_asum(count_, gpu_diff(), &asum); + return asum; +#endif + } else { +#ifdef USE_GREENTEA + Dtype asum; + greentea_gpu_asum(device_->id(), count_, (cl_mem) gpu_diff(), 0, + &asum); + return asum; +#endif + } #else - NO_GPU; + NO_GPU; #endif - case SyncedMemory::UNINITIALIZED: - return 0; - default: - LOG(FATAL) << "Unknown SyncedMemory head state: " << diff_->head(); - } + } + case SyncedMemory::UNINITIALIZED: + return 0; + default: + LOG(FATAL)<< "Unknown SyncedMemory head state: " << diff_->head(); + } return 0; } -template <> unsigned int Blob::sumsq_data() const { +template<> uint_tp Blob::sumsq_data() const { NOT_IMPLEMENTED; return 0; } -template <> int Blob::sumsq_data() const { +template<> int_tp Blob::sumsq_data() const { NOT_IMPLEMENTED; return 0; } -template +template Dtype Blob::sumsq_data() const { Dtype sumsq; const Dtype* data; - if (!data_) { return 0; } + if (!data_) { + return 0; + } switch (data_->head()) { - case SyncedMemory::HEAD_AT_CPU: - data = cpu_data(); - sumsq = caffe_cpu_dot(count_, data, data); - break; - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + case SyncedMemory::HEAD_AT_CPU: { + data = cpu_data(); + sumsq = caffe_cpu_dot(count_, data, data); + break; + } + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - data = gpu_data(); - caffe_gpu_dot(count_, data, data, &sumsq); + data = gpu_data(); + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_dot(count_, data, data, &sumsq); +#endif + } else { +#ifdef USE_GREENTEA + greentea_gpu_dot(device_->id(), count_, (cl_mem) data, 0, + (cl_mem) data, 0, &sumsq); +#endif + } #else - NO_GPU; + NO_GPU; #endif - break; - case SyncedMemory::UNINITIALIZED: - return 0; - default: - LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head(); - } + break; + } + case SyncedMemory::UNINITIALIZED: + return 0; + default: + LOG(FATAL)<< "Unknown SyncedMemory head state: " << data_->head(); + } return sumsq; } -template <> unsigned int Blob::sumsq_diff() const { +template<> uint_tp Blob::sumsq_diff() const { NOT_IMPLEMENTED; return 0; } -template <> int Blob::sumsq_diff() const { +template<> int_tp Blob::sumsq_diff() const { NOT_IMPLEMENTED; return 0; } -template +template Dtype Blob::sumsq_diff() const { Dtype sumsq; const Dtype* diff; - if (!diff_) { return 0; } + if (!diff_) { + return 0; + } switch (diff_->head()) { - case SyncedMemory::HEAD_AT_CPU: - diff = cpu_diff(); - sumsq = caffe_cpu_dot(count_, diff, diff); - break; - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + case SyncedMemory::HEAD_AT_CPU: { + diff = cpu_diff(); + sumsq = caffe_cpu_dot(count_, diff, diff); + break; + } + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - diff = gpu_diff(); - caffe_gpu_dot(count_, diff, diff, &sumsq); - break; + diff = gpu_diff(); + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_dot(count_, diff, diff, &sumsq); +#endif + } else { +#ifdef USE_GREENTEA + greentea_gpu_dot(device_->id(), count_, (cl_mem) diff, 0, + (cl_mem) diff, 0, &sumsq); +#endif + } #else - NO_GPU; + NO_GPU; #endif - case SyncedMemory::UNINITIALIZED: - return 0; - default: - LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head(); - } + break; + } + case SyncedMemory::UNINITIALIZED: + return 0; + default: + LOG(FATAL)<< "Unknown SyncedMemory head state: " << data_->head(); + } return sumsq; } -template <> void Blob::scale_data(unsigned int scale_factor) { +template<> void Blob::scale_data(uint_tp scale_factor) { NOT_IMPLEMENTED; } -template <> void Blob::scale_data(int scale_factor) { +template<> void Blob::scale_data(int_tp scale_factor) { NOT_IMPLEMENTED; } -template +template void Blob::scale_data(Dtype scale_factor) { Dtype* data; - if (!data_) { return; } - switch (data_->head()) { - case SyncedMemory::HEAD_AT_CPU: - data = mutable_cpu_data(); - caffe_scal(count_, scale_factor, data); + if (!data_) { return; - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + } + switch (data_->head()) { + case SyncedMemory::HEAD_AT_CPU: { + data = mutable_cpu_data(); + caffe_scal(count_, scale_factor, data); + return; + } + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - data = mutable_gpu_data(); - caffe_gpu_scal(count_, scale_factor, data); - return; + data = mutable_gpu_data(); + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_scal(count_, scale_factor, data); +#endif + } else { +#ifdef USE_GREENTEA + greentea_gpu_scal(device_->id(), count_, scale_factor, + (cl_mem) data, 0); +#endif + } + return; #else - NO_GPU; + NO_GPU; #endif - case SyncedMemory::UNINITIALIZED: - return; - default: - LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head(); + } + case SyncedMemory::UNINITIALIZED: + return; + default: + LOG(FATAL)<< "Unknown SyncedMemory head state: " << data_->head(); + } } -} -template <> void Blob::scale_diff(unsigned int scale_factor) { +template<> void Blob::scale_diff(uint_tp scale_factor) { NOT_IMPLEMENTED; } -template <> void Blob::scale_diff(int scale_factor) { +template<> void Blob::scale_diff(int_tp scale_factor) { NOT_IMPLEMENTED; } -template +template void Blob::scale_diff(Dtype scale_factor) { Dtype* diff; - if (!diff_) { return; } - switch (diff_->head()) { - case SyncedMemory::HEAD_AT_CPU: - diff = mutable_cpu_diff(); - caffe_scal(count_, scale_factor, diff); + if (!diff_) { return; - case SyncedMemory::HEAD_AT_GPU: - case SyncedMemory::SYNCED: + } + switch (diff_->head()) { + case SyncedMemory::HEAD_AT_CPU: { + diff = mutable_cpu_diff(); + caffe_scal(count_, scale_factor, diff); + return; + } + case SyncedMemory::HEAD_AT_GPU: + case SyncedMemory::SYNCED: { #ifndef CPU_ONLY - diff = mutable_gpu_diff(); - caffe_gpu_scal(count_, scale_factor, diff); - return; + diff = mutable_gpu_diff(); + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_scal(count_, scale_factor, diff); +#endif + } else { +#ifdef USE_GREENTEA + greentea_gpu_scal(device_->id(), count_, scale_factor, + (cl_mem) diff, 0); +#endif + } + return; #else - NO_GPU; + NO_GPU; #endif - case SyncedMemory::UNINITIALIZED: - return; - default: - LOG(FATAL) << "Unknown SyncedMemory head state: " << diff_->head(); + } + case SyncedMemory::UNINITIALIZED: + return; + default: + LOG(FATAL)<< "Unknown SyncedMemory head state: " << diff_->head(); + } } -} -template +template bool Blob::ShapeEquals(const BlobProto& other) { - if (other.has_num() || other.has_channels() || - other.has_height() || other.has_width()) { + if (other.has_num() || other.has_channels() || other.has_height() + || other.has_width()) { // Using deprecated 4D Blob dimensions -- // shape is (num, channels, height, width). // Note: we do not use the normal Blob::num(), Blob::channels(), etc. // methods as these index from the beginning of the blob shape, where legacy // parameter blobs were indexed from the end of the blob shape (e.g., bias // Blob shape (1 x 1 x 1 x N), IP layer weight Blob shape (1 x 1 x M x N)). - return shape_.size() <= 4 && - LegacyShape(-4) == other.num() && - LegacyShape(-3) == other.channels() && - LegacyShape(-2) == other.height() && - LegacyShape(-1) == other.width(); + return shape_.size() <= 4 && LegacyShape(-4) == other.num() + && LegacyShape(-3) == other.channels() + && LegacyShape(-2) == other.height() + && LegacyShape(-1) == other.width(); } - vector other_shape(other.shape().dim_size()); - for (int i = 0; i < other.shape().dim_size(); ++i) { + vector other_shape(other.shape().dim_size()); + for (int_tp i = 0; i < other.shape().dim_size(); ++i) { other_shape[i] = other.shape().dim(i); } return shape_ == other_shape; } -template +template void Blob::CopyFrom(const Blob& source, bool copy_diff, bool reshape) { if (source.count() != count_ || source.shape() != shape_) { if (reshape) { ReshapeLike(source); } else { - LOG(FATAL) << "Trying to copy blobs of different sizes."; + LOG(FATAL)<< "Trying to copy blobs of different sizes."; } } switch (Caffe::mode()) { - case Caffe::GPU: - if (copy_diff) { - caffe_copy(count_, source.gpu_diff(), - static_cast(diff_->mutable_gpu_data())); - } else { - caffe_copy(count_, source.gpu_data(), - static_cast(data_->mutable_gpu_data())); + case Caffe::GPU: { + if (device_->backend() == BACKEND_CUDA) { + if (copy_diff) { + caffe_copy(count_, source.gpu_diff(), + static_cast(diff_->mutable_gpu_data())); + } else { + caffe_copy(count_, source.gpu_data(), + static_cast(data_->mutable_gpu_data())); + } + } else { +#ifdef USE_GREENTEA + if (copy_diff) { + greentea_copy( + count_, (cl_mem) (source.gpu_diff()), 0, + (cl_mem) (diff_->mutable_gpu_data()), 0, + &viennacl::ocl::get_context(device_->id())); + } else { + greentea_copy( + count_, (cl_mem) (source.gpu_data()), 0, + (cl_mem) (data_->mutable_gpu_data()), 0, + &viennacl::ocl::get_context(device_->id())); + } +#endif + } + break; } - break; - case Caffe::CPU: - if (copy_diff) { - caffe_copy(count_, source.cpu_diff(), - static_cast(diff_->mutable_cpu_data())); - } else { - caffe_copy(count_, source.cpu_data(), - static_cast(data_->mutable_cpu_data())); + case Caffe::CPU: { + if (copy_diff) { + caffe_cpu_copy(count_, source.cpu_diff(), + static_cast(diff_->mutable_cpu_data())); + } else { + caffe_cpu_copy(count_, source.cpu_data(), + static_cast(data_->mutable_cpu_data())); + } + break; } - break; - default: - LOG(FATAL) << "Unknown caffe mode."; + default: + LOG(FATAL)<< "Unknown caffe mode."; } } -template +template void Blob::FromProto(const BlobProto& proto, bool reshape) { if (reshape) { - vector shape; - if (proto.has_num() || proto.has_channels() || - proto.has_height() || proto.has_width()) { + vector shape; + if (proto.has_num() || proto.has_channels() || proto.has_height() + || proto.has_width()) { // Using deprecated 4D Blob dimensions -- // shape is (num, channels, height, width). shape.resize(4); @@ -457,7 +582,7 @@ void Blob::FromProto(const BlobProto& proto, bool reshape) { shape[3] = proto.width(); } else { shape.resize(proto.shape().dim_size()); - for (int i = 0; i < proto.shape().dim_size(); ++i) { + for (int_tp i = 0; i < proto.shape().dim_size(); ++i) { shape[i] = proto.shape().dim(i); } } @@ -469,25 +594,25 @@ void Blob::FromProto(const BlobProto& proto, bool reshape) { Dtype* data_vec = mutable_cpu_data(); if (proto.double_data_size() > 0) { CHECK_EQ(count_, proto.double_data_size()); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { data_vec[i] = proto.double_data(i); } } else { CHECK_EQ(count_, proto.data_size()); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { data_vec[i] = proto.data(i); } } if (proto.double_diff_size() > 0) { CHECK_EQ(count_, proto.double_diff_size()); Dtype* diff_vec = mutable_cpu_diff(); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { diff_vec[i] = proto.double_diff(i); } } else if (proto.diff_size() > 0) { CHECK_EQ(count_, proto.diff_size()); Dtype* diff_vec = mutable_cpu_diff(); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { diff_vec[i] = proto.diff(i); } } @@ -496,18 +621,18 @@ void Blob::FromProto(const BlobProto& proto, bool reshape) { template <> void Blob::ToProto(BlobProto* proto, bool write_diff) const { proto->clear_shape(); - for (int i = 0; i < shape_.size(); ++i) { + for (int_tp i = 0; i < shape_.size(); ++i) { proto->mutable_shape()->add_dim(shape_[i]); } proto->clear_double_data(); proto->clear_double_diff(); const double* data_vec = cpu_data(); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { proto->add_double_data(data_vec[i]); } if (write_diff) { const double* diff_vec = cpu_diff(); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { proto->add_double_diff(diff_vec[i]); } } @@ -516,26 +641,26 @@ void Blob::ToProto(BlobProto* proto, bool write_diff) const { template <> void Blob::ToProto(BlobProto* proto, bool write_diff) const { proto->clear_shape(); - for (int i = 0; i < shape_.size(); ++i) { + for (int_tp i = 0; i < shape_.size(); ++i) { proto->mutable_shape()->add_dim(shape_[i]); } proto->clear_data(); proto->clear_diff(); const float* data_vec = cpu_data(); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { proto->add_data(data_vec[i]); } if (write_diff) { const float* diff_vec = cpu_diff(); - for (int i = 0; i < count_; ++i) { + for (int_tp i = 0; i < count_; ++i) { proto->add_diff(diff_vec[i]); } } } INSTANTIATE_CLASS(Blob); -template class Blob; -template class Blob; +template class Blob; +template class Blob; } // namespace caffe diff --git a/src/caffe/common.cpp b/src/caffe/common.cpp index 299d67d4bec..57ef08921e3 100644 --- a/src/caffe/common.cpp +++ b/src/caffe/common.cpp @@ -1,20 +1,49 @@ #include #include + +#include #include #include #include +#include +#include #include "caffe/common.hpp" + +#include "caffe/device.hpp" #include "caffe/util/rng.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/cl_kernels.hpp" +#ifdef USE_CLBLAS +#include +#endif // USE_CLBLAS +#endif + namespace caffe { // Make sure each thread can have different values. static boost::thread_specific_ptr thread_instance_; +// Pointer to the global instance of Caffe +static Caffe* global_instance_; +static std::atomic first(true); + +// Device contexts are initialized once and shared on all threads +std::vector< shared_ptr > Caffe::devices_; + Caffe& Caffe::Get() { - if (!thread_instance_.get()) { + if (first.exchange(false)) { + // The first call must be single threaded + // and defines the global instance thread_instance_.reset(new Caffe()); + global_instance_ = thread_instance_.get(); + } + if (!thread_instance_.get()) { + // Every thread initially gets a copy of the global initialization. + // Later, every thread can switch to a different default device + // or change other aspects of the Caffe object + thread_instance_.reset(new Caffe(*global_instance_)); } return *(thread_instance_.get()); } @@ -28,8 +57,8 @@ int64_t cluster_seedgen(void) { return seed; } - LOG(INFO) << "System entropy source not available, " - "using fallback algorithm to generate seed instead."; + LOG(INFO)<< "System entropy source not available, " + "using fallback algorithm to generate seed instead."; if (f) fclose(f); @@ -39,7 +68,6 @@ int64_t cluster_seedgen(void) { return seed; } - void GlobalInit(int* pargc, char*** pargv) { // Google flags. ::gflags::ParseCommandLineFlags(pargc, pargv, true); @@ -49,15 +77,117 @@ void GlobalInit(int* pargc, char*** pargv) { ::google::InstallFailureSignalHandler(); } + +device *Caffe::GetDevice(int id, bool listId) { + if (listId) { + return + id == -1 ? + Get().default_device_ : + Get().devices_[id % Get().devices_.size()].get(); + } else { + for (int i = 0; i < Get().devices_.size(); ++i) { + device* device = Get().devices_[i].get(); + if (device->id() == id) { + return device; + } + } + return GetDefaultDevice(); + } +} + +device *Caffe::GetDefaultDevice() { + return Get().default_device_; +} + +device *Caffe::GetCPUDevice() { + return Get().cpu_device_.get(); +} + +// Copy constructor for thread-local copy +Caffe::Caffe(const Caffe &obj) + : +#ifdef USE_CUDA + cublas_handle_(NULL), + curand_generator_(NULL), + curand_generator64_(NULL), +#endif // USE_CUDA + random_generator_(), + mode_(Caffe::CPU), + cpu_device_(new device(-1, -1, Backend::BACKEND_CPU)), + default_device_(cpu_device_.get()), + solver_count_(1), + root_solver_(true) { + mode_ = obj.mode_; + default_device_ = obj.default_device_; + cpu_device_ = obj.cpu_device_; + root_solver_ = obj.root_solver_; + solver_count_ = obj.solver_count_; +} + +void Caffe::SelectDevice(int id, bool listId) { + Caffe::SelectDevice(GetDevice(id, listId)); +} + +void Caffe::SelectDevice(device* device_context) { +#ifndef CPU_ONLY + Get().default_device_ = device_context; + + if (device_context->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + CUDA_CHECK(cudaSetDevice(device_context->id())); + + if (Get().cublas_handle_) { + CUBLAS_CHECK(cublasDestroy(Get().cublas_handle_)); + } + if (Get().curand_generator_) { + CURAND_CHECK(curandDestroyGenerator(Get().curand_generator_)); + } + if (Get().curand_generator64_) { + CURAND_CHECK(curandDestroyGenerator(Get().curand_generator64_)); + } + CUBLAS_CHECK(cublasCreate(&Get().cublas_handle_)); + + if (cublasCreate(&(Get().cublas_handle_)) != CUBLAS_STATUS_SUCCESS) { + LOG(ERROR)<< "Cannot create Cublas handle. Cublas won't be available."; + } + // Try to create a curand handler. + if (curandCreateGenerator(&(Get().curand_generator_), + CURAND_RNG_PSEUDO_DEFAULT) + != CURAND_STATUS_SUCCESS + || curandSetPseudoRandomGeneratorSeed((Get().curand_generator_), + cluster_seedgen()) + != CURAND_STATUS_SUCCESS) { + LOG(ERROR)<< "Cannot create Curand generator. Curand won't be available."; + } + if (curandCreateGenerator(&(Get().curand_generator64_), + CURAND_RNG_QUASI_SOBOL64) + != CURAND_STATUS_SUCCESS) { + LOG(ERROR)<< "Cannot create Curand generator. Curand won't be available."; + } + +#endif // USE_CUDA + } else if (device_context->backend() == Backend::BACKEND_OpenCL) { +#ifdef USE_GREENTEA +#ifdef USE_CLBLAS + clblasSetup(); +#endif // USE_CLBLAS +#endif // USE_GREENTEA + } +#endif // !CPU_ONLY +} + #ifdef CPU_ONLY // CPU-only Caffe. Caffe::Caffe() - : random_generator_(), mode_(Caffe::CPU), - solver_count_(1), root_solver_(true) { } +: random_generator_(), +mode_(Caffe::CPU), +default_device_(nullptr), +solver_count_(1), +root_solver_(true) {} -Caffe::~Caffe() { } +Caffe::~Caffe() {} -void Caffe::set_random_seed(const unsigned int seed) { +void Caffe::set_random_seed(const size_t seed) { // RNG seed Get().random_generator_.reset(new RNG(seed)); } @@ -70,19 +200,25 @@ void Caffe::DeviceQuery() { NO_GPU; } +void Caffe::Synchronize(int device_id) { +} + +int Caffe::EnumerateDevices(bool silent) { + return 0; +} class Caffe::RNG::Generator { public: Generator() : rng_(new caffe::rng_t(cluster_seedgen())) {} - explicit Generator(unsigned int seed) : rng_(new caffe::rng_t(seed)) {} - caffe::rng_t* rng() { return rng_.get(); } + explicit Generator(size_t seed) : rng_(new caffe::rng_t(seed)) {} + caffe::rng_t* rng() {return rng_.get();} private: shared_ptr rng_; }; -Caffe::RNG::RNG() : generator_(new Generator()) { } +Caffe::RNG::RNG() : generator_(new Generator()) {} -Caffe::RNG::RNG(unsigned int seed) : generator_(new Generator(seed)) { } +Caffe::RNG::RNG(size_t seed) : generator_(new Generator(seed)) {} Caffe::RNG& Caffe::RNG::operator=(const RNG& other) { generator_ = other.generator_; @@ -96,115 +232,322 @@ void* Caffe::RNG::generator() { #else // Normal GPU + CPU Caffe. Caffe::Caffe() - : cublas_handle_(NULL), curand_generator_(NULL), random_generator_(), - mode_(Caffe::CPU), solver_count_(1), root_solver_(true) { - // Try to create a cublas handler, and report an error if failed (but we will - // keep the program running as one might just want to run CPU code). - if (cublasCreate(&cublas_handle_) != CUBLAS_STATUS_SUCCESS) { - LOG(ERROR) << "Cannot create Cublas handle. Cublas won't be available."; - } - // Try to create a curand handler. - if (curandCreateGenerator(&curand_generator_, CURAND_RNG_PSEUDO_DEFAULT) - != CURAND_STATUS_SUCCESS || - curandSetPseudoRandomGeneratorSeed(curand_generator_, cluster_seedgen()) - != CURAND_STATUS_SUCCESS) { - LOG(ERROR) << "Cannot create Curand generator. Curand won't be available."; - } + : +#ifdef USE_CUDA + cublas_handle_(NULL), + curand_generator_(NULL), + curand_generator64_(NULL), +#endif // USE_CUDA + random_generator_(), + mode_(Caffe::CPU), + cpu_device_(new device(-1, -1, Backend::BACKEND_CPU)), + default_device_(cpu_device_.get()), + solver_count_(1), root_solver_(true) { } Caffe::~Caffe() { - if (cublas_handle_) CUBLAS_CHECK(cublasDestroy(cublas_handle_)); + // Make sure all device contexts and + // dependent memory blocks are freed properly + if (this == global_instance_) { + devices_.clear(); + } +#ifdef USE_CUDA + if (cublas_handle_) + CUBLAS_CHECK(cublasDestroy(cublas_handle_)); + cublas_handle_ = nullptr; if (curand_generator_) { CURAND_CHECK(curandDestroyGenerator(curand_generator_)); + curand_generator_ = nullptr; } + if (curand_generator64_) { + CURAND_CHECK(curandDestroyGenerator(curand_generator64_)); + curand_generator64_ = nullptr; + } +#endif // USE_CUDA } -void Caffe::set_random_seed(const unsigned int seed) { - // Curand seed - static bool g_curand_availability_logged = false; - if (Get().curand_generator_) { - CURAND_CHECK(curandSetPseudoRandomGeneratorSeed(curand_generator(), - seed)); - CURAND_CHECK(curandSetGeneratorOffset(curand_generator(), 0)); - } else { - if (!g_curand_availability_logged) { - LOG(ERROR) << - "Curand not available. Skipping setting the curand seed."; +void Caffe::set_random_seed(const size_t seed, device* device_context) { + if (device_context->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // Curand seed + static bool g_curand_availability_logged = false; + if (Get().curand_generator_) { + CURAND_CHECK( + curandSetPseudoRandomGeneratorSeed(curand_generator(), seed)); + CURAND_CHECK(curandSetGeneratorOffset(curand_generator(), 0)); + } else { + if (!g_curand_availability_logged) { + LOG(ERROR)<< + "Curand not available. Skipping setting the curand seed."; g_curand_availability_logged = true; + } } + if (Get().curand_generator64_) { + CURAND_CHECK(curandSetGeneratorOffset(curand_generator64(), 0)); + } else { + if (!g_curand_availability_logged) { + LOG(ERROR)<< + "Curand not available. Skipping setting the curand seed."; + g_curand_availability_logged = true; + } + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA +// TODO: Proper RNG and Seed for OpenCL +#endif // USE_GREENTEA } // RNG seed Get().random_generator_.reset(new RNG(seed)); } -void Caffe::SetDevice(const int device_id) { - int current_device; - CUDA_CHECK(cudaGetDevice(¤t_device)); - if (current_device == device_id) { - return; +void Caffe::Synchronize(int device_id) { + if (Caffe::mode() == Brew::GPU) { + device * device_context = Caffe::GetDevice(device_id, true); + if (device_context->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + cudaDeviceSynchronize(); +#endif + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + GetDevice(device_id, true)->id()); + ctx.get_queue().finish(); +#endif + } + } +} + +int Caffe::EnumerateDevices(bool silent) { + int cuda_device_count = 0; + int greentea_device_count = 0; + +#ifdef USE_CUDA + cudaGetDeviceCount(&cuda_device_count); +#endif + +#ifdef USE_GREENTEA + typedef std::vector platforms_type; + platforms_type platforms = viennacl::ocl::get_platforms(); + + std::vector> platform_devices; + + // Loop through devices + for (std::size_t platform_id = 0; platform_id < platforms.size(); + ++platform_id) { + typedef std::vector devices_type; + try { + devices_type devices = platforms[platform_id].devices(CL_DEVICE_TYPE_ALL); + for (std::size_t device_id = 0; device_id < devices.size(); ++device_id) { + platform_devices.push_back( + std::make_tuple(platforms[platform_id], devices[device_id])); + greentea_device_count++; + } + } catch (...) { + if (!silent) { + LOG(INFO)<< "OpenCL platform: " + << platforms[platform_id].info() + << " does not work correctly."; + } + } } - // The call to cudaSetDevice must come before any calls to Get, which - // may perform initialization using the GPU. - CUDA_CHECK(cudaSetDevice(device_id)); - if (Get().cublas_handle_) CUBLAS_CHECK(cublasDestroy(Get().cublas_handle_)); - if (Get().curand_generator_) { - CURAND_CHECK(curandDestroyGenerator(Get().curand_generator_)); +#endif + + if (!silent) { + LOG(INFO)<< "Total devices: " << cuda_device_count + greentea_device_count; + LOG(INFO)<< "CUDA devices: " << cuda_device_count; + LOG(INFO)<< "OpenCL devices: " << greentea_device_count; + + // Display info for all devices +#ifdef USE_CUDA + for (int i = 0; i < cuda_device_count; ++i) { + cudaDeviceProp prop; + CUDA_CHECK(cudaGetDeviceProperties(&prop, i)); + LOG(INFO)<< "Device id: " + << i; + LOG(INFO)<< "Device backend: " + << "CUDA"; + LOG(INFO)<< "Backend details: " + << "CUDA"; + LOG(INFO)<< "Device vendor: " + << "NVIDIA Corporation"; + LOG(INFO)<< "Name: " + << prop.name; + LOG(INFO)<< "Total global memory: " + << prop.totalGlobalMem; + } +#endif // USE_CUDA + +#ifdef USE_GREENTEA + for (int i = 0; i < greentea_device_count; ++i) { + LOG(INFO)<< "Device id: " + << cuda_device_count + i; + LOG(INFO)<< "Device backend: " + << "OpenCL"; + LOG(INFO)<< "Backend details: " + << std::get<0>(platform_devices[i]).info(); + LOG(INFO)<< "Device vendor: " + << std::get<1>(platform_devices[i]).vendor(); + LOG(INFO)<< "Name: " + << std::get<1>(platform_devices[i]).name(); + LOG(INFO)<< "Total global memory: " + << std::get<1>(platform_devices[i]).global_mem_size(); + } +#endif // USE_GREENTEA } - CUBLAS_CHECK(cublasCreate(&Get().cublas_handle_)); - CURAND_CHECK(curandCreateGenerator(&Get().curand_generator_, - CURAND_RNG_PSEUDO_DEFAULT)); - CURAND_CHECK(curandSetPseudoRandomGeneratorSeed(Get().curand_generator_, - cluster_seedgen())); + + return cuda_device_count + greentea_device_count; } -void Caffe::DeviceQuery() { - cudaDeviceProp prop; - int device; - if (cudaSuccess != cudaGetDevice(&device)) { - printf("No cuda device present.\n"); - return; +void Caffe::SetDevices(std::vector device_ids) { + int initcount = 0; + Get().devices_.clear(); + int cuda_device_count = 0; +#ifdef USE_CUDA + cudaGetDeviceCount(&cuda_device_count); +#endif // USE_CUDA + for (int i = 0; i < cuda_device_count; ++i) { + for (int j = 0; j < device_ids.size(); ++j) { + if (device_ids[j] == i) { + shared_ptr dev( + new device(i, initcount, Backend::BACKEND_CUDA)); + Get().devices_.emplace_back(dev); + dev->Init(); + ++initcount; + } + } + } + + // Initialize GreenTea devices +#ifdef USE_GREENTEA + int greentea_device_count = 0; + + typedef std::vector platforms_type; + platforms_type platforms = viennacl::ocl::get_platforms(); + + std::vector< std::tuple > platform_devices; + + // Loop through devices + for (int platform_id = 0; platform_id < platforms.size(); + ++platform_id) { + typedef std::vector devices_type; + try { + devices_type devices = platforms[platform_id].devices( + CL_DEVICE_TYPE_ALL); + for (int device_id = 0; device_id < devices.size(); ++device_id) { + platform_devices.push_back( + std::make_tuple(platforms[platform_id], devices[device_id])); + // Check if this device is really used and initialize + for (int i = 0; i < device_ids.size(); ++i) { + int device_id = device_ids[i]; + if (device_id == cuda_device_count + greentea_device_count) { + // Setup actual context and compile kernels for this device + viennacl::ocl::setup_context( + device_id, + std::get<1>(platform_devices[greentea_device_count])); + + shared_ptr dev( + new device(device_id, + initcount, Backend::BACKEND_OpenCL)); + Get().devices_.emplace_back(dev); + dev->Init(); + ++initcount; + } + } + greentea_device_count++; + } + } catch (...) { + LOG(INFO)<< "OpenCL platform: " + << platforms[platform_id].info() + << " does not work correctly."; + } } - CUDA_CHECK(cudaGetDeviceProperties(&prop, device)); - LOG(INFO) << "Device id: " << device; - LOG(INFO) << "Major revision number: " << prop.major; - LOG(INFO) << "Minor revision number: " << prop.minor; - LOG(INFO) << "Name: " << prop.name; - LOG(INFO) << "Total global memory: " << prop.totalGlobalMem; - LOG(INFO) << "Total shared memory per block: " << prop.sharedMemPerBlock; - LOG(INFO) << "Total registers per block: " << prop.regsPerBlock; - LOG(INFO) << "Warp size: " << prop.warpSize; - LOG(INFO) << "Maximum memory pitch: " << prop.memPitch; - LOG(INFO) << "Maximum threads per block: " << prop.maxThreadsPerBlock; - LOG(INFO) << "Maximum dimension of block: " +#endif // USE_GREENTEA + + Get().default_device_ = GetDevice(0, true); + Caffe::SelectDevice(Get().default_device_); +} + +void Caffe::SetDevice(const int device_id) { + // Fix for compability to python and other interfaces that do not + // know or call SetDevices directly + if (Get().devices_.size() == 0) { + // No device has been initialized so far + Caffe::SetDevices(std::vector { device_id }); + } + + Get().default_device_ = GetDevice(0, true); +} + +// TODO: Fix this for the new backend +void Caffe::DeviceQuery() { + if (Get().default_device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + cudaDeviceProp prop; + int device; + if (cudaSuccess != cudaGetDevice(&device)) { + printf("No cuda device present.\n"); + } else { + CUDA_CHECK(cudaGetDeviceProperties(&prop, device)); + LOG(INFO)<< "Device id: " << device; + LOG(INFO)<< "Major revision number: " << prop.major; + LOG(INFO)<< "Minor revision number: " << prop.minor; + LOG(INFO)<< "Name: " << prop.name; + LOG(INFO)<< "Total global memory: " << prop.totalGlobalMem; + LOG(INFO)<< "Total shared memory per block: " << prop.sharedMemPerBlock; + LOG(INFO)<< "Total registers per block: " << prop.regsPerBlock; + LOG(INFO)<< "Warp size: " << prop.warpSize; + LOG(INFO)<< "Maximum memory pitch: " << prop.memPitch; + LOG(INFO)<< "Maximum threads per block: " << prop.maxThreadsPerBlock; + LOG(INFO)<< "Maximum dimension of block: " << prop.maxThreadsDim[0] << ", " << prop.maxThreadsDim[1] << ", " << prop.maxThreadsDim[2]; - LOG(INFO) << "Maximum dimension of grid: " + LOG(INFO)<< "Maximum dimension of grid: " << prop.maxGridSize[0] << ", " << prop.maxGridSize[1] << ", " << prop.maxGridSize[2]; - LOG(INFO) << "Clock rate: " << prop.clockRate; - LOG(INFO) << "Total constant memory: " << prop.totalConstMem; - LOG(INFO) << "Texture alignment: " << prop.textureAlignment; - LOG(INFO) << "Concurrent copy and execution: " + LOG(INFO)<< "Clock rate: " << prop.clockRate; + LOG(INFO)<< "Total constant memory: " << prop.totalConstMem; + LOG(INFO)<< "Texture alignment: " << prop.textureAlignment; + LOG(INFO)<< "Concurrent copy and execution: " << (prop.deviceOverlap ? "Yes" : "No"); - LOG(INFO) << "Number of multiprocessors: " << prop.multiProcessorCount; - LOG(INFO) << "Kernel execution timeout: " + LOG(INFO)<< "Number of multiprocessors: " << prop.multiProcessorCount; + LOG(INFO)<< "Kernel execution timeout: " << (prop.kernelExecTimeoutEnabled ? "Yes" : "No"); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + // TODO: Complete OpenCL device information of current device +#endif // USE_GREENTEA + } + return; } - class Caffe::RNG::Generator { public: - Generator() : rng_(new caffe::rng_t(cluster_seedgen())) {} - explicit Generator(unsigned int seed) : rng_(new caffe::rng_t(seed)) {} - caffe::rng_t* rng() { return rng_.get(); } + Generator() + : rng_(new caffe::rng_t(cluster_seedgen())) { + } + explicit Generator(size_t seed) + : rng_(new caffe::rng_t(seed)) { + } + caffe::rng_t* rng() { + return rng_.get(); + } private: shared_ptr rng_; }; -Caffe::RNG::RNG() : generator_(new Generator()) { } +Caffe::RNG::RNG() + : generator_(new Generator()) { +} -Caffe::RNG::RNG(unsigned int seed) : generator_(new Generator(seed)) { } +Caffe::RNG::RNG(size_t seed) + : generator_(new Generator(seed)) { +} Caffe::RNG& Caffe::RNG::operator=(const RNG& other) { generator_.reset(other.generator_.get()); @@ -215,31 +558,32 @@ void* Caffe::RNG::generator() { return static_cast(generator_->rng()); } +#ifdef USE_CUDA const char* cublasGetErrorString(cublasStatus_t error) { switch (error) { - case CUBLAS_STATUS_SUCCESS: - return "CUBLAS_STATUS_SUCCESS"; - case CUBLAS_STATUS_NOT_INITIALIZED: - return "CUBLAS_STATUS_NOT_INITIALIZED"; - case CUBLAS_STATUS_ALLOC_FAILED: - return "CUBLAS_STATUS_ALLOC_FAILED"; - case CUBLAS_STATUS_INVALID_VALUE: - return "CUBLAS_STATUS_INVALID_VALUE"; - case CUBLAS_STATUS_ARCH_MISMATCH: - return "CUBLAS_STATUS_ARCH_MISMATCH"; - case CUBLAS_STATUS_MAPPING_ERROR: - return "CUBLAS_STATUS_MAPPING_ERROR"; - case CUBLAS_STATUS_EXECUTION_FAILED: - return "CUBLAS_STATUS_EXECUTION_FAILED"; - case CUBLAS_STATUS_INTERNAL_ERROR: - return "CUBLAS_STATUS_INTERNAL_ERROR"; + case CUBLAS_STATUS_SUCCESS: + return "CUBLAS_STATUS_SUCCESS"; + case CUBLAS_STATUS_NOT_INITIALIZED: + return "CUBLAS_STATUS_NOT_INITIALIZED"; + case CUBLAS_STATUS_ALLOC_FAILED: + return "CUBLAS_STATUS_ALLOC_FAILED"; + case CUBLAS_STATUS_INVALID_VALUE: + return "CUBLAS_STATUS_INVALID_VALUE"; + case CUBLAS_STATUS_ARCH_MISMATCH: + return "CUBLAS_STATUS_ARCH_MISMATCH"; + case CUBLAS_STATUS_MAPPING_ERROR: + return "CUBLAS_STATUS_MAPPING_ERROR"; + case CUBLAS_STATUS_EXECUTION_FAILED: + return "CUBLAS_STATUS_EXECUTION_FAILED"; + case CUBLAS_STATUS_INTERNAL_ERROR: + return "CUBLAS_STATUS_INTERNAL_ERROR"; #if CUDA_VERSION >= 6000 - case CUBLAS_STATUS_NOT_SUPPORTED: - return "CUBLAS_STATUS_NOT_SUPPORTED"; + case CUBLAS_STATUS_NOT_SUPPORTED: + return "CUBLAS_STATUS_NOT_SUPPORTED"; #endif #if CUDA_VERSION >= 6050 - case CUBLAS_STATUS_LICENSE_ERROR: - return "CUBLAS_STATUS_LICENSE_ERROR"; + case CUBLAS_STATUS_LICENSE_ERROR: + return "CUBLAS_STATUS_LICENSE_ERROR"; #endif } return "Unknown cublas status"; @@ -247,35 +591,36 @@ const char* cublasGetErrorString(cublasStatus_t error) { const char* curandGetErrorString(curandStatus_t error) { switch (error) { - case CURAND_STATUS_SUCCESS: - return "CURAND_STATUS_SUCCESS"; - case CURAND_STATUS_VERSION_MISMATCH: - return "CURAND_STATUS_VERSION_MISMATCH"; - case CURAND_STATUS_NOT_INITIALIZED: - return "CURAND_STATUS_NOT_INITIALIZED"; - case CURAND_STATUS_ALLOCATION_FAILED: - return "CURAND_STATUS_ALLOCATION_FAILED"; - case CURAND_STATUS_TYPE_ERROR: - return "CURAND_STATUS_TYPE_ERROR"; - case CURAND_STATUS_OUT_OF_RANGE: - return "CURAND_STATUS_OUT_OF_RANGE"; - case CURAND_STATUS_LENGTH_NOT_MULTIPLE: - return "CURAND_STATUS_LENGTH_NOT_MULTIPLE"; - case CURAND_STATUS_DOUBLE_PRECISION_REQUIRED: - return "CURAND_STATUS_DOUBLE_PRECISION_REQUIRED"; - case CURAND_STATUS_LAUNCH_FAILURE: - return "CURAND_STATUS_LAUNCH_FAILURE"; - case CURAND_STATUS_PREEXISTING_FAILURE: - return "CURAND_STATUS_PREEXISTING_FAILURE"; - case CURAND_STATUS_INITIALIZATION_FAILED: - return "CURAND_STATUS_INITIALIZATION_FAILED"; - case CURAND_STATUS_ARCH_MISMATCH: - return "CURAND_STATUS_ARCH_MISMATCH"; - case CURAND_STATUS_INTERNAL_ERROR: - return "CURAND_STATUS_INTERNAL_ERROR"; + case CURAND_STATUS_SUCCESS: + return "CURAND_STATUS_SUCCESS"; + case CURAND_STATUS_VERSION_MISMATCH: + return "CURAND_STATUS_VERSION_MISMATCH"; + case CURAND_STATUS_NOT_INITIALIZED: + return "CURAND_STATUS_NOT_INITIALIZED"; + case CURAND_STATUS_ALLOCATION_FAILED: + return "CURAND_STATUS_ALLOCATION_FAILED"; + case CURAND_STATUS_TYPE_ERROR: + return "CURAND_STATUS_TYPE_ERROR"; + case CURAND_STATUS_OUT_OF_RANGE: + return "CURAND_STATUS_OUT_OF_RANGE"; + case CURAND_STATUS_LENGTH_NOT_MULTIPLE: + return "CURAND_STATUS_LENGTH_NOT_MULTIPLE"; + case CURAND_STATUS_DOUBLE_PRECISION_REQUIRED: + return "CURAND_STATUS_DOUBLE_PRECISION_REQUIRED"; + case CURAND_STATUS_LAUNCH_FAILURE: + return "CURAND_STATUS_LAUNCH_FAILURE"; + case CURAND_STATUS_PREEXISTING_FAILURE: + return "CURAND_STATUS_PREEXISTING_FAILURE"; + case CURAND_STATUS_INITIALIZATION_FAILED: + return "CURAND_STATUS_INITIALIZATION_FAILED"; + case CURAND_STATUS_ARCH_MISMATCH: + return "CURAND_STATUS_ARCH_MISMATCH"; + case CURAND_STATUS_INTERNAL_ERROR: + return "CURAND_STATUS_INTERNAL_ERROR"; } return "Unknown curand status"; } +#endif // USE_CUDA #endif // CPU_ONLY diff --git a/src/caffe/cuda/cuda_dev_ptr.cpp b/src/caffe/cuda/cuda_dev_ptr.cpp new file mode 100644 index 00000000000..656cf4ead01 --- /dev/null +++ b/src/caffe/cuda/cuda_dev_ptr.cpp @@ -0,0 +1,24 @@ +#include "caffe/cuda/cuda_dev_ptr.hpp" + +#ifdef USE_CUDA + +namespace caffe { + +template +cuda_dev_ptr::cuda_dev_ptr(Type* ptr) + : raw_ptr_(ptr) { +} + +template +void* cuda_dev_ptr::get() { + return raw_ptr_; +} + +template +int_tp cuda_dev_ptr::off() { + return 0; +} + +} // namespace caffe + +#endif // USE_GREENTEA diff --git a/src/caffe/data_reader.cpp b/src/caffe/data_reader.cpp index 9f019bbfcb7..069ac269c6b 100644 --- a/src/caffe/data_reader.cpp +++ b/src/caffe/data_reader.cpp @@ -17,14 +17,15 @@ static boost::mutex bodies_mutex_; DataReader::DataReader(const LayerParameter& param) : queue_pair_(new QueuePair( // - param.data_param().prefetch() * param.data_param().batch_size())) { + param.data_param().prefetch() * param.data_param().batch_size())), + device_(Caffe::GetDevice(param.device(), true)) { // Get or create a body boost::mutex::scoped_lock lock(bodies_mutex_); string key = source_key(param); weak_ptr& weak = bodies_[key]; body_ = weak.lock(); if (!body_) { - body_.reset(new Body(param)); + body_.reset(new Body(param, device_)); bodies_[key] = weak_ptr(body_); } body_->new_queue_pairs_.push(queue_pair_); @@ -41,9 +42,9 @@ DataReader::~DataReader() { // -DataReader::QueuePair::QueuePair(int size) { +DataReader::QueuePair::QueuePair(int_tp size) { // Initialize the free queue with requested number of datums - for (int i = 0; i < size; ++i) { + for (int_tp i = 0; i < size; ++i) { free_.push(new Datum()); } } @@ -60,10 +61,10 @@ DataReader::QueuePair::~QueuePair() { // -DataReader::Body::Body(const LayerParameter& param) +DataReader::Body::Body(const LayerParameter& param, device* device_context) : param_(param), new_queue_pairs_() { - StartInternalThread(); + StartInternalThread(device_context); } DataReader::Body::~Body() { @@ -76,19 +77,19 @@ void DataReader::Body::InternalThreadEntry() { shared_ptr cursor(db->NewCursor()); vector > qps; try { - int solver_count = param_.phase() == TRAIN ? Caffe::solver_count() : 1; + int_tp solver_count = param_.phase() == TRAIN ? Caffe::solver_count() : 1; // To ensure deterministic runs, only start running once all solvers // are ready. But solvers need to peek on one item during initialization, // so read one item, then wait for the next solver. - for (int i = 0; i < solver_count; ++i) { + for (int_tp i = 0; i < solver_count; ++i) { shared_ptr qp(new_queue_pairs_.pop()); read_one(cursor.get(), qp.get()); qps.push_back(qp); } // Main loop while (!must_stop()) { - for (int i = 0; i < solver_count; ++i) { + for (int_tp i = 0; i < solver_count; ++i) { read_one(cursor.get(), qps[i].get()); } // Check no additional readers have been created. This can happen if diff --git a/src/caffe/data_transformer.cpp b/src/caffe/data_transformer.cpp index 7189d67e289..509cac186cf 100644 --- a/src/caffe/data_transformer.cpp +++ b/src/caffe/data_transformer.cpp @@ -14,12 +14,14 @@ namespace caffe { template DataTransformer::DataTransformer(const TransformationParameter& param, - Phase phase) - : param_(param), phase_(phase) { + Phase phase, + device *device_context) + : param_(param), + phase_(phase), device_(device_context) { // check if we want to use mean_file if (param_.has_mean_file()) { - CHECK_EQ(param_.mean_value_size(), 0) << - "Cannot specify mean_file and mean_value at the same time"; + CHECK_EQ(param_.mean_value_size(), 0)<< + "Cannot specify mean_file and mean_value at the same time"; const string& mean_file = param.mean_file(); if (Caffe::root_solver()) { LOG(INFO) << "Loading mean file from: " << mean_file; @@ -31,8 +33,8 @@ DataTransformer::DataTransformer(const TransformationParameter& param, // check if we want to use mean_value if (param_.mean_value_size() > 0) { CHECK(param_.has_mean_file() == false) << - "Cannot specify mean_file and mean_value at the same time"; - for (int c = 0; c < param_.mean_value_size(); ++c) { + "Cannot specify mean_file and mean_value at the same time"; + for (int_tp c = 0; c < param_.mean_value_size(); ++c) { mean_values_.push_back(param_.mean_value(c)); } } @@ -42,11 +44,11 @@ template void DataTransformer::Transform(const Datum& datum, Dtype* transformed_data) { const string& data = datum.data(); - const int datum_channels = datum.channels(); - const int datum_height = datum.height(); - const int datum_width = datum.width(); + const int_tp datum_channels = datum.channels(); + const int_tp datum_height = datum.height(); + const int_tp datum_width = datum.width(); - const int crop_size = param_.crop_size(); + const int_tp crop_size = param_.crop_size(); const Dtype scale = param_.scale(); const bool do_mirror = param_.mirror() && Rand(2); const bool has_mean_file = param_.has_mean_file(); @@ -65,21 +67,22 @@ void DataTransformer::Transform(const Datum& datum, mean = data_mean_.mutable_cpu_data(); } if (has_mean_values) { - CHECK(mean_values_.size() == 1 || mean_values_.size() == datum_channels) << - "Specify either 1 mean_value or as many as channels: " << datum_channels; + CHECK(mean_values_.size() == 1 || mean_values_.size() == datum_channels) + << "Specify either 1 mean_value or as many as channels: " + << datum_channels; if (datum_channels > 1 && mean_values_.size() == 1) { // Replicate the mean_value for simplicity - for (int c = 1; c < datum_channels; ++c) { + for (int_tp c = 1; c < datum_channels; ++c) { mean_values_.push_back(mean_values_[0]); } } } - int height = datum_height; - int width = datum_width; + int_tp height = datum_height; + int_tp width = datum_width; - int h_off = 0; - int w_off = 0; + int_tp h_off = 0; + int_tp w_off = 0; if (crop_size) { height = crop_size; width = crop_size; @@ -94,10 +97,10 @@ void DataTransformer::Transform(const Datum& datum, } Dtype datum_element; - int top_index, data_index; - for (int c = 0; c < datum_channels; ++c) { - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { + int_tp top_index, data_index; + for (int_tp c = 0; c < datum_channels; ++c) { + for (int_tp h = 0; h < height; ++h) { + for (int_tp w = 0; w < width; ++w) { data_index = (c * datum_height + h_off + h) * datum_width + w_off + w; if (do_mirror) { top_index = (c * height + h) * width + (width - 1 - w); @@ -106,17 +109,17 @@ void DataTransformer::Transform(const Datum& datum, } if (has_uint8) { datum_element = - static_cast(static_cast(data[data_index])); + static_cast(static_cast(data[data_index])); } else { datum_element = datum.float_data(data_index); } if (has_mean_file) { - transformed_data[top_index] = - (datum_element - mean[data_index]) * scale; + transformed_data[top_index] = (datum_element - mean[data_index]) + * scale; } else { if (has_mean_values) { - transformed_data[top_index] = - (datum_element - mean_values_[c]) * scale; + transformed_data[top_index] = (datum_element - mean_values_[c]) + * scale; } else { transformed_data[top_index] = datum_element * scale; } @@ -153,16 +156,16 @@ void DataTransformer::Transform(const Datum& datum, } } - const int crop_size = param_.crop_size(); - const int datum_channels = datum.channels(); - const int datum_height = datum.height(); - const int datum_width = datum.width(); + const int_tp crop_size = param_.crop_size(); + const int_tp datum_channels = datum.channels(); + const int_tp datum_height = datum.height(); + const int_tp datum_width = datum.width(); // Check dimensions. - const int channels = transformed_blob->channels(); - const int height = transformed_blob->height(); - const int width = transformed_blob->width(); - const int num = transformed_blob->num(); + const int_tp channels = transformed_blob->channels(); + const int_tp height = transformed_blob->height(); + const int_tp width = transformed_blob->width(); + const int_tp num = transformed_blob->num(); CHECK_EQ(channels, datum_channels); CHECK_LE(height, datum_height); @@ -184,18 +187,18 @@ void DataTransformer::Transform(const Datum& datum, template void DataTransformer::Transform(const vector & datum_vector, Blob* transformed_blob) { - const int datum_num = datum_vector.size(); - const int num = transformed_blob->num(); - const int channels = transformed_blob->channels(); - const int height = transformed_blob->height(); - const int width = transformed_blob->width(); - - CHECK_GT(datum_num, 0) << "There is no datum to add"; - CHECK_LE(datum_num, num) << - "The size of datum_vector must be no greater than transformed_blob->num()"; - Blob uni_blob(1, channels, height, width); - for (int item_id = 0; item_id < datum_num; ++item_id) { - int offset = transformed_blob->offset(item_id); + const int_tp datum_num = datum_vector.size(); + const int_tp num = transformed_blob->num(); + const int_tp channels = transformed_blob->channels(); + const int_tp height = transformed_blob->height(); + const int_tp width = transformed_blob->width(); + + CHECK_GT(datum_num, 0)<< "There is no datum to add"; + CHECK_LE(datum_num, num)<< + "The size of datum_vector must be no greater than transformed_blob->num()"; + Blob uni_blob(1, channels, height, width, device_); + for (int_tp item_id = 0; item_id < datum_num; ++item_id) { + int_tp offset = transformed_blob->offset(item_id); uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset); Transform(datum_vector[item_id], &uni_blob); } @@ -205,18 +208,18 @@ void DataTransformer::Transform(const vector & datum_vector, template void DataTransformer::Transform(const vector & mat_vector, Blob* transformed_blob) { - const int mat_num = mat_vector.size(); - const int num = transformed_blob->num(); - const int channels = transformed_blob->channels(); - const int height = transformed_blob->height(); - const int width = transformed_blob->width(); - - CHECK_GT(mat_num, 0) << "There is no MAT to add"; - CHECK_EQ(mat_num, num) << - "The size of mat_vector must be equals to transformed_blob->num()"; - Blob uni_blob(1, channels, height, width); - for (int item_id = 0; item_id < mat_num; ++item_id) { - int offset = transformed_blob->offset(item_id); + const int_tp mat_num = mat_vector.size(); + const int_tp num = transformed_blob->num(); + const int_tp channels = transformed_blob->channels(); + const int_tp height = transformed_blob->height(); + const int_tp width = transformed_blob->width(); + + CHECK_GT(mat_num, 0)<< "There is no MAT to add"; + CHECK_EQ(mat_num, num)<< + "The size of mat_vector must be equals to transformed_blob->num()"; + Blob uni_blob(1, channels, height, width, device_); + for (int_tp item_id = 0; item_id < mat_num; ++item_id) { + int_tp offset = transformed_blob->offset(item_id); uni_blob.set_cpu_data(transformed_blob->mutable_cpu_data() + offset); Transform(mat_vector[item_id], &uni_blob); } @@ -225,23 +228,25 @@ void DataTransformer::Transform(const vector & mat_vector, template void DataTransformer::Transform(const cv::Mat& cv_img, Blob* transformed_blob) { - const int crop_size = param_.crop_size(); - const int img_channels = cv_img.channels(); - const int img_height = cv_img.rows; - const int img_width = cv_img.cols; + const int_tp crop_size = param_.crop_size(); + const int_tp img_channels = cv_img.channels(); + const int_tp img_height = cv_img.rows; + const int_tp img_width = cv_img.cols; // Check dimensions. - const int channels = transformed_blob->channels(); - const int height = transformed_blob->height(); - const int width = transformed_blob->width(); - const int num = transformed_blob->num(); + const int_tp channels = transformed_blob->channels(); + const int_tp height = transformed_blob->height(); + const int_tp width = transformed_blob->width(); + const int_tp num = transformed_blob->num(); CHECK_EQ(channels, img_channels); CHECK_LE(height, img_height); CHECK_LE(width, img_width); CHECK_GE(num, 1); - CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte"; + // (FTschopp) Fixed for float data + CHECK(cv_img.depth() == CV_8U || cv_img.depth() == CV_32F) + << "Image data type must be unsigned byte or 4 byte float"; const Dtype scale = param_.scale(); const bool do_mirror = param_.mirror() && Rand(2); @@ -260,18 +265,19 @@ void DataTransformer::Transform(const cv::Mat& cv_img, mean = data_mean_.mutable_cpu_data(); } if (has_mean_values) { - CHECK(mean_values_.size() == 1 || mean_values_.size() == img_channels) << - "Specify either 1 mean_value or as many as channels: " << img_channels; + CHECK(mean_values_.size() == 1 || mean_values_.size() == img_channels) + << "Specify either 1 mean_value or as many as channels: " + << img_channels; if (img_channels > 1 && mean_values_.size() == 1) { // Replicate the mean_value for simplicity - for (int c = 1; c < img_channels; ++c) { + for (int_tp c = 1; c < img_channels; ++c) { mean_values_.push_back(mean_values_[0]); } } } - int h_off = 0; - int w_off = 0; + int_tp h_off = 0; + int_tp w_off = 0; cv::Mat cv_cropped_img = cv_img; if (crop_size) { CHECK_EQ(crop_size, height); @@ -294,27 +300,32 @@ void DataTransformer::Transform(const cv::Mat& cv_img, CHECK(cv_cropped_img.data); Dtype* transformed_data = transformed_blob->mutable_cpu_data(); - int top_index; - for (int h = 0; h < height; ++h) { + int_tp top_index; + for (int_tp h = 0; h < height; ++h) { const uchar* ptr = cv_cropped_img.ptr(h); - int img_index = 0; - for (int w = 0; w < width; ++w) { - for (int c = 0; c < img_channels; ++c) { + int_tp img_index = 0; + for (int_tp w = 0; w < width; ++w) { + for (int_tp c = 0; c < img_channels; ++c) { if (do_mirror) { top_index = (c * height + h) * width + (width - 1 - w); } else { top_index = (c * height + h) * width + w; } - // int top_index = (c * height + h) * width + w; - Dtype pixel = static_cast(ptr[img_index++]); + // int_tp top_index = (c * height + h) * width + w; + Dtype pixel; + if (cv_img.depth() == CV_8U) { + pixel = static_cast(ptr[img_index++]); + } else { + pixel = static_cast((reinterpret_cast(ptr)) + [img_index++]); + } if (has_mean_file) { - int mean_index = (c * img_height + h_off + h) * img_width + w_off + w; - transformed_data[top_index] = - (pixel - mean[mean_index]) * scale; + int_tp mean_index = (c * img_height + h_off + h) * img_width + w_off + + w; + transformed_data[top_index] = (pixel - mean[mean_index]) * scale; } else { if (has_mean_values) { - transformed_data[top_index] = - (pixel - mean_values_[c]) * scale; + transformed_data[top_index] = (pixel - mean_values_[c]) * scale; } else { transformed_data[top_index] = pixel * scale; } @@ -328,11 +339,11 @@ void DataTransformer::Transform(const cv::Mat& cv_img, template void DataTransformer::Transform(Blob* input_blob, Blob* transformed_blob) { - const int crop_size = param_.crop_size(); - const int input_num = input_blob->num(); - const int input_channels = input_blob->channels(); - const int input_height = input_blob->height(); - const int input_width = input_blob->width(); + const int_tp crop_size = param_.crop_size(); + const int_tp input_num = input_blob->num(); + const int_tp input_channels = input_blob->channels(); + const int_tp input_height = input_blob->height(); + const int_tp input_width = input_blob->width(); if (transformed_blob->count() == 0) { // Initialize transformed_blob with the right shape. @@ -345,11 +356,11 @@ void DataTransformer::Transform(Blob* input_blob, } } - const int num = transformed_blob->num(); - const int channels = transformed_blob->channels(); - const int height = transformed_blob->height(); - const int width = transformed_blob->width(); - const int size = transformed_blob->count(); + const int_tp num = transformed_blob->num(); + const int_tp channels = transformed_blob->channels(); + const int_tp height = transformed_blob->height(); + const int_tp width = transformed_blob->width(); + const int_tp size = transformed_blob->count(); CHECK_LE(input_num, num); CHECK_EQ(input_channels, channels); @@ -362,8 +373,8 @@ void DataTransformer::Transform(Blob* input_blob, const bool has_mean_file = param_.has_mean_file(); const bool has_mean_values = mean_values_.size() > 0; - int h_off = 0; - int w_off = 0; + int_tp h_off = 0; + int_tp w_off = 0; if (crop_size) { CHECK_EQ(crop_size, height); CHECK_EQ(crop_size, width); @@ -385,24 +396,25 @@ void DataTransformer::Transform(Blob* input_blob, CHECK_EQ(input_channels, data_mean_.channels()); CHECK_EQ(input_height, data_mean_.height()); CHECK_EQ(input_width, data_mean_.width()); - for (int n = 0; n < input_num; ++n) { - int offset = input_blob->offset(n); - caffe_sub(data_mean_.count(), input_data + offset, - data_mean_.cpu_data(), input_data + offset); + for (int_tp n = 0; n < input_num; ++n) { + int_tp offset = input_blob->offset(n); + caffe_sub(data_mean_.count(), input_data + offset, data_mean_.cpu_data(), + input_data + offset); } } if (has_mean_values) { - CHECK(mean_values_.size() == 1 || mean_values_.size() == input_channels) << - "Specify either 1 mean_value or as many as channels: " << input_channels; + CHECK(mean_values_.size() == 1 || mean_values_.size() == input_channels) + << "Specify either 1 mean_value or as many as channels: " + << input_channels; if (mean_values_.size() == 1) { caffe_add_scalar(input_blob->count(), -(mean_values_[0]), input_data); } else { - for (int n = 0; n < input_num; ++n) { - for (int c = 0; c < input_channels; ++c) { - int offset = input_blob->offset(n, c); + for (int_tp n = 0; n < input_num; ++n) { + for (int_tp c = 0; c < input_channels; ++c) { + int_tp offset = input_blob->offset(n, c); caffe_add_scalar(input_height * input_width, -(mean_values_[c]), - input_data + offset); + input_data + offset); } } } @@ -410,22 +422,22 @@ void DataTransformer::Transform(Blob* input_blob, Dtype* transformed_data = transformed_blob->mutable_cpu_data(); - for (int n = 0; n < input_num; ++n) { - int top_index_n = n * channels; - int data_index_n = n * channels; - for (int c = 0; c < channels; ++c) { - int top_index_c = (top_index_n + c) * height; - int data_index_c = (data_index_n + c) * input_height + h_off; - for (int h = 0; h < height; ++h) { - int top_index_h = (top_index_c + h) * width; - int data_index_h = (data_index_c + h) * input_width + w_off; + for (int_tp n = 0; n < input_num; ++n) { + int_tp top_index_n = n * channels; + int_tp data_index_n = n * channels; + for (int_tp c = 0; c < channels; ++c) { + int_tp top_index_c = (top_index_n + c) * height; + int_tp data_index_c = (data_index_n + c) * input_height + h_off; + for (int_tp h = 0; h < height; ++h) { + int_tp top_index_h = (top_index_c + h) * width; + int_tp data_index_h = (data_index_c + h) * input_width + w_off; if (do_mirror) { - int top_index_w = top_index_h + width - 1; - for (int w = 0; w < width; ++w) { - transformed_data[top_index_w-w] = input_data[data_index_h + w]; + int_tp top_index_w = top_index_h + width - 1; + for (int_tp w = 0; w < width; ++w) { + transformed_data[top_index_w - w] = input_data[data_index_h + w]; } } else { - for (int w = 0; w < width; ++w) { + for (int_tp w = 0; w < width; ++w) { transformed_data[top_index_h + w] = input_data[data_index_h + w]; } } @@ -433,13 +445,13 @@ void DataTransformer::Transform(Blob* input_blob, } } if (scale != Dtype(1)) { - DLOG(INFO) << "Scale: " << scale; + DLOG(INFO)<< "Scale: " << scale; caffe_scal(size, scale, transformed_data); } } template -vector DataTransformer::InferBlobShape(const Datum& datum) { +vector DataTransformer::InferBlobShape(const Datum& datum) { if (datum.encoded()) { #ifdef USE_OPENCV CHECK(!(param_.force_color() && param_.force_gray())) @@ -457,16 +469,16 @@ vector DataTransformer::InferBlobShape(const Datum& datum) { LOG(FATAL) << "Encoded datum requires OpenCV; compile with USE_OPENCV."; #endif // USE_OPENCV } - const int crop_size = param_.crop_size(); - const int datum_channels = datum.channels(); - const int datum_height = datum.height(); - const int datum_width = datum.width(); + const int_tp crop_size = param_.crop_size(); + const int_tp datum_channels = datum.channels(); + const int_tp datum_height = datum.height(); + const int_tp datum_width = datum.width(); // Check dimensions. CHECK_GT(datum_channels, 0); CHECK_GE(datum_height, crop_size); CHECK_GE(datum_width, crop_size); // Build BlobShape. - vector shape(4); + vector shape(4); shape[0] = 1; shape[1] = datum_channels; shape[2] = (crop_size)? crop_size: datum_height; @@ -475,12 +487,12 @@ vector DataTransformer::InferBlobShape(const Datum& datum) { } template -vector DataTransformer::InferBlobShape( +vector DataTransformer::InferBlobShape( const vector & datum_vector) { - const int num = datum_vector.size(); + const int_tp num = datum_vector.size(); CHECK_GT(num, 0) << "There is no datum to in the vector"; // Use first datum in the vector to InferBlobShape. - vector shape = InferBlobShape(datum_vector[0]); + vector shape = InferBlobShape(datum_vector[0]); // Adjust num to the size of the vector. shape[0] = num; return shape; @@ -488,17 +500,17 @@ vector DataTransformer::InferBlobShape( #ifdef USE_OPENCV template -vector DataTransformer::InferBlobShape(const cv::Mat& cv_img) { - const int crop_size = param_.crop_size(); - const int img_channels = cv_img.channels(); - const int img_height = cv_img.rows; - const int img_width = cv_img.cols; +vector DataTransformer::InferBlobShape(const cv::Mat& cv_img) { + const int_tp crop_size = param_.crop_size(); + const int_tp img_channels = cv_img.channels(); + const int_tp img_height = cv_img.rows; + const int_tp img_width = cv_img.cols; // Check dimensions. CHECK_GT(img_channels, 0); CHECK_GE(img_height, crop_size); CHECK_GE(img_width, crop_size); // Build BlobShape. - vector shape(4); + vector shape(4); shape[0] = 1; shape[1] = img_channels; shape[2] = (crop_size)? crop_size: img_height; @@ -507,12 +519,12 @@ vector DataTransformer::InferBlobShape(const cv::Mat& cv_img) { } template -vector DataTransformer::InferBlobShape( +vector DataTransformer::InferBlobShape( const vector & mat_vector) { - const int num = mat_vector.size(); + const int_tp num = mat_vector.size(); CHECK_GT(num, 0) << "There is no cv_img to in the vector"; // Use first cv_img in the vector to InferBlobShape. - vector shape = InferBlobShape(mat_vector[0]); + vector shape = InferBlobShape(mat_vector[0]); // Adjust num to the size of the vector. shape[0] = num; return shape; @@ -521,22 +533,21 @@ vector DataTransformer::InferBlobShape( template void DataTransformer::InitRand() { - const bool needs_rand = param_.mirror() || - (phase_ == TRAIN && param_.crop_size()); + const bool needs_rand = param_.mirror() + || (phase_ == TRAIN && param_.crop_size()); if (needs_rand) { - const unsigned int rng_seed = caffe_rng_rand(); + const uint_tp rng_seed = caffe_rng_rand(); rng_.reset(new Caffe::RNG(rng_seed)); } else { rng_.reset(); } } -template -int DataTransformer::Rand(int n) { +template +int_tp DataTransformer::Rand(int_tp n) { CHECK(rng_); CHECK_GT(n, 0); - caffe::rng_t* rng = - static_cast(rng_->generator()); + caffe::rng_t* rng = static_cast(rng_->generator()); return ((*rng)() % n); } diff --git a/src/caffe/device.cpp b/src/caffe/device.cpp new file mode 100644 index 00000000000..49cb4eef087 --- /dev/null +++ b/src/caffe/device.cpp @@ -0,0 +1,202 @@ +/* + * device_context.cpp + * + * Created on: Jun 26, 2015 + * Author: Fabian Tschopp + */ + +#include +#include +#include + +#include "caffe/device.hpp" +#include "caffe/greentea/greentea.hpp" +#include "caffe/util/device_alternate.hpp" + +#ifdef USE_GREENTEA +#include "caffe/greentea/cl_kernels.hpp" +#endif // USE_GREENTEA + +namespace caffe { + +device::device() + : current_queue_id_(0), workgroup_sizes_(3, 0), id_(0), list_id_(0), + backend_(Backend::BACKEND_CPU), memory_usage_(0), peak_memory_usage_(0) { +} + +device::device(int id, int list_id, Backend backend) + : current_queue_id_(0), workgroup_sizes_(3, 0), id_(id), list_id_(list_id), + backend_(backend), memory_usage_(0), peak_memory_usage_(0) { +} + +void device::Init() { +#ifndef CPU_ONLY + if (backend_ == BACKEND_CUDA) { +#ifdef USE_CUDA + workgroup_sizes_[0] = CAFFE_CUDA_NUM_THREADS; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(id_); + + std::vector temp(3); + clGetDeviceInfo(ctx.devices()[0].id(), + CL_DEVICE_MAX_WORK_ITEM_SIZES, + sizeof(uint_tp), &temp[0], NULL); + workgroup_sizes_[0] = temp[0]; + workgroup_sizes_[1] = temp[1]; + workgroup_sizes_[2] = temp[2]; + + SetProgram(); + + for (int q = 0; q < GREENTEA_QUEUE_COUNT - 1; ++q) { + ctx.add_queue(ctx.devices()[0]); + } +#endif // USE_GREENTEA + } +#endif // !CPU_ONLY +} + +Backend device::backend() const { + return backend_; +} + +int device::id() const { + return id_; +} + +int device::list_id() const { + return list_id_; +} + +int device::WorkgroupSize(int id) { + return workgroup_sizes_[id]; + return 0; +} + +int device::num_queues() { + if (backend_ == BACKEND_CUDA) { +#ifdef USE_CUDA + return 1; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + return GREENTEA_QUEUE_COUNT; +#endif // USE_GREENTEA + } + return 1; +} + +template<> +shared_ptr > device::Buffer(int id) { + if (buff_f_.size() <= id) { + shared_ptr > blob_pointer(new Blob(this)); + buff_f_.push_back(blob_pointer); + } + return buff_f_[id]; +} + +template<> +shared_ptr > device::Buffer(int id) { + if (buff_d_.size() <= id) { + shared_ptr > blob_pointer(new Blob(this)); + buff_d_.push_back(blob_pointer); + } + return buff_d_[id]; +} + +int device::current_queue_id() { + return current_queue_id_; +} + +void device::SwitchQueue(int id) { + if (backend_ == BACKEND_CUDA) { +#ifdef USE_CUDA + (void) id; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(id_); + ctx.switch_queue(id % num_queues()); + current_queue_id_ = id % num_queues(); +#endif // USE_GREENTEA + } +} + +void device::FinishQueues() { + if (backend_ == BACKEND_CUDA) { +#ifdef USE_CUDA +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(id_); + for (int i = 0; i < num_queues(); ++i) { + ctx.switch_queue(i); + ctx.get_queue().finish(); + } + ctx.switch_queue(0); + current_queue_id_ = 0; +#endif // USE_GREENTEA + } +} + +uint_tp device::memory_usage() { + return memory_usage_; +} + +uint_tp device::peak_memory_usage() { + return peak_memory_usage_; +} + +void device::IncreaseMemoryUsage(uint_tp bytes) { + memory_usage_ += bytes; + if (memory_usage_ > peak_memory_usage_) { + peak_memory_usage_ = memory_usage_; + } +} + +void device::DecreaseMemoryUsage(uint_tp bytes) { + memory_usage_ -= bytes; +} + +void device::ResetPeakMemoryUsage() { + peak_memory_usage_ = memory_usage_; +} + +bool device::CheckCapability(std::string cap) { + if (backend_ == BACKEND_OpenCL) { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(id_); + + size_t size; + size_t max_size = 1024 * 1024; + clGetDeviceInfo(ctx.devices()[0].id(), CL_DEVICE_EXTENSIONS, + 0, NULL, &size); + + // Cap at 1 MB to capture faulty OpenCL implementations (nVidia) + std::vector exts(std::min(size, max_size)); + + clGetDeviceInfo(ctx.devices()[0].id(), CL_DEVICE_EXTENSIONS, + size, &(exts[0]), NULL); + + std::string extsstr(&(exts[0])); + return extsstr.find(cap) != std::string::npos; +#endif + } + return true; +} + +#ifdef USE_GREENTEA +viennacl::ocl::program &device::program() { + return ocl_program_; +} + +void device::SetProgram() { + ocl_program_ = RegisterKernels( + &(viennacl::ocl::get_context(static_cast(id_)))); +} + + +#endif // USE_GREENTEA + +} // namespace caffe diff --git a/src/caffe/greentea/cl_headers/definitions_32.cl b/src/caffe/greentea/cl_headers/definitions_32.cl new file mode 100644 index 00000000000..706cde9f8be --- /dev/null +++ b/src/caffe/greentea/cl_headers/definitions_32.cl @@ -0,0 +1,7 @@ +// Types used for parameters, offset computations and so on +#define int_tp int +#define uint_tp unsigned int + +// Definitions used to cast the types above as needed +#define int_tpc int +#define uint_tpc unsigned int diff --git a/src/caffe/greentea/cl_headers/definitions_64.cl b/src/caffe/greentea/cl_headers/definitions_64.cl new file mode 100644 index 00000000000..99e41d9ee56 --- /dev/null +++ b/src/caffe/greentea/cl_headers/definitions_64.cl @@ -0,0 +1,7 @@ +// Types used for parameters, offset computations and so on +#define int_tp long +#define uint_tp unsigned long + +// Definitions used to cast the types above as needed +#define int_tpc long +#define uint_tpc unsigned long diff --git a/src/caffe/greentea/cl_headers/header.cl b/src/caffe/greentea/cl_headers/header.cl new file mode 100644 index 00000000000..50a10afeda2 --- /dev/null +++ b/src/caffe/greentea/cl_headers/header.cl @@ -0,0 +1,44 @@ +#ifndef __OPENCL_VERSION__ +#define __kernel +#define __global +#define __constant +#define __local +#define get_global_id(x) 0 +#define get_global_size(x) 0 +#define get_local_id(x) 0 +#define get_local_size(x) 0 +#define FLT_MAX 0 +#define FLT_MIN 0 +#define cl_khr_fp64 +#define cl_amd_fp64 +#define DOUBLE_SUPPORT_AVAILABLE +#define CLK_LOCAL_MEM_FENCE +#define CLK_GLOBAL_MEM_FENCE +#define Dtype float +#define barrier(x) +#define atomic_cmpxchg(x, y, z) x +#define signbit(x) x +#define int_tp long +#define uint_tp unsigned long +#define int_tpc long +#define uint_tpc unsigned long +#endif + +#define CONCAT(A,B) A##_##B +#define TEMPLATE(name,type) CONCAT(name,type) + +#define TYPE_FLOAT 1 +#define TYPE_DOUBLE 2 + +#if defined(cl_khr_fp64) +#pragma OPENCL EXTENSION cl_khr_fp64 : enable +#define DOUBLE_SUPPORT_AVAILABLE +#elif defined(cl_amd_fp64) +#pragma OPENCL EXTENSION cl_amd_fp64 : enable +#define DOUBLE_SUPPORT_AVAILABLE +#endif + +#if defined(cl_khr_int64_base_atomics) +#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable +#define ATOMICS_64_AVAILABLE +#endif diff --git a/src/caffe/greentea/cl_kernels.cpp b/src/caffe/greentea/cl_kernels.cpp new file mode 100644 index 00000000000..4a1b28b1ef7 --- /dev/null +++ b/src/caffe/greentea/cl_kernels.cpp @@ -0,0 +1,140 @@ +// AUTOMATICALLY GENERATED FILE, DO NOT EDIT +#include "caffe/common.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/cl_kernels.hpp" +#include +#include +namespace caffe { +#ifdef USE_INDEX_64 +static std::string header = "#ifndef __OPENCL_VERSION__\n#define __kernel\n#define __global\n#define __constant\n#define __local\n#define get_global_id(x) 0\n#define get_global_size(x) 0\n#define get_local_id(x) 0\n#define get_local_size(x) 0\n#define FLT_MAX 0\n#define FLT_MIN 0\n#define cl_khr_fp64\n#define cl_amd_fp64\n#define DOUBLE_SUPPORT_AVAILABLE\n#define CLK_LOCAL_MEM_FENCE\n#define CLK_GLOBAL_MEM_FENCE\n#define Dtype float\n#define barrier(x)\n#define atomic_cmpxchg(x, y, z) x\n#define signbit(x) x\n#define int_tp long\n#define uint_tp unsigned long\n#define int_tpc long\n#define uint_tpc unsigned long\n#endif\n\n#define CONCAT(A,B) A##_##B\n#define TEMPLATE(name,type) CONCAT(name,type)\n\n#define TYPE_FLOAT 1\n#define TYPE_DOUBLE 2\n\n#if defined(cl_khr_fp64)\n#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n#define DOUBLE_SUPPORT_AVAILABLE\n#elif defined(cl_amd_fp64)\n#pragma OPENCL EXTENSION cl_amd_fp64 : enable\n#define DOUBLE_SUPPORT_AVAILABLE\n#endif\n\n#if defined(cl_khr_int64_base_atomics)\n#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable\n#define ATOMICS_64_AVAILABLE\n#endif"; // NOLINT +static std::string definitions_64 = "// Types used for parameters, offset computations and so on\n#define int_tp long\n#define uint_tp unsigned long\n\n// Definitions used to cast the types above as needed\n#define int_tpc long\n#define uint_tpc unsigned long"; // NOLINT +#else +static std::string header = "#ifndef __OPENCL_VERSION__\n#define __kernel\n#define __global\n#define __constant\n#define __local\n#define get_global_id(x) 0\n#define get_global_size(x) 0\n#define get_local_id(x) 0\n#define get_local_size(x) 0\n#define FLT_MAX 0\n#define FLT_MIN 0\n#define cl_khr_fp64\n#define cl_amd_fp64\n#define DOUBLE_SUPPORT_AVAILABLE\n#define CLK_LOCAL_MEM_FENCE\n#define CLK_GLOBAL_MEM_FENCE\n#define Dtype float\n#define barrier(x)\n#define atomic_cmpxchg(x, y, z) x\n#define signbit(x) x\n#define int_tp long\n#define uint_tp unsigned long\n#define int_tpc long\n#define uint_tpc unsigned long\n#endif\n\n#define CONCAT(A,B) A##_##B\n#define TEMPLATE(name,type) CONCAT(name,type)\n\n#define TYPE_FLOAT 1\n#define TYPE_DOUBLE 2\n\n#if defined(cl_khr_fp64)\n#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n#define DOUBLE_SUPPORT_AVAILABLE\n#elif defined(cl_amd_fp64)\n#pragma OPENCL EXTENSION cl_amd_fp64 : enable\n#define DOUBLE_SUPPORT_AVAILABLE\n#endif\n\n#if defined(cl_khr_int64_base_atomics)\n#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable\n#define ATOMICS_64_AVAILABLE\n#endif"; // NOLINT +static std::string definitions_32 = "// Types used for parameters, offset computations and so on\n#define int_tp int\n#define uint_tp unsigned int\n\n// Definitions used to cast the types above as needed\n#define int_tpc int\n#define uint_tpc unsigned int"; // NOLINT +#endif +static std::string activation_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(relu_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out,\n Dtype negative_slope) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] > 0 ? in[index] : in[index] * negative_slope;\n }\n}\n\n__kernel void TEMPLATE(relu_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff,\n Dtype negative_slope) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] = in_diff[index]\n * ((in_data[index] > 0?1.0:0.0) + (in_data[index] <= 0?1.0:0.0) * negative_slope);\n }\n}\n\n__kernel void TEMPLATE(tanh_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = tanh(in[index]);\n }\n}\n\n__kernel void TEMPLATE(tanh_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* out_data,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n Dtype tanhx = out_data[index];\n out_diff[index] = in_diff[index] * (1 - tanhx * tanhx);\n }\n}\n\n__kernel void TEMPLATE(sigmoid_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = 1.0 / (1.0 + exp(-in[index]));\n }\n}\n\n__kernel void TEMPLATE(sigmoid_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* out_data,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n const Dtype sigmoid_x = out_data[index];\n out_diff[index] = in_diff[index] * sigmoid_x * (1 - sigmoid_x);\n }\n}\n\n__kernel void TEMPLATE(threshold,Dtype)(const int_tp n, const Dtype threshold,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] > threshold ? 1.0 : 0.0;\n }\n}\n\n__kernel void TEMPLATE(prelu_forward,Dtype)(const int_tp n, const int_tp channels,\n const int_tp dim,\n __global const Dtype* in,\n __global Dtype* out,\n __global const Dtype* slope_data,\n const int_tp div_factor) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n int_tp c = (index / dim) % channels / div_factor;\n out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[c];\n }\n}\n\n__kernel void TEMPLATE(prelu_backward,Dtype)(const int_tp n, const int_tp channels,\n const int_tp dim,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff,\n __global const Dtype* slope_data,\n const int_tp div_factor) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n int_tp c = (index / dim) % channels / div_factor;\n out_diff[index] = in_diff[index]\n * ((in_data[index] > 0?1.0:0.0) + (in_data[index] <= 0?1.0:0.0) * slope_data[c]);\n }\n}\n\n__kernel void TEMPLATE(prelu_param_backward,Dtype)(const int_tp n, const int_tp rows,\n const int_tp rowPitch,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] = in_diff[index] * in_data[index] * (in_data[index] <= 0?1.0:0.0);\n for (int k = 1; k < rows; k++) {\n out_diff[index] += in_diff[index + k * rowPitch]\n * in_data[index + k * rowPitch]\n * (in_data[index + k * rowPitch] <= 0?1.0:0.0);\n }\n }\n}"; // NOLINT +static std::string auxiliary_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(gpu_set,Dtype)(const int_tp n, const Dtype alpha, __global Dtype* y) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index] = alpha;\n }\n}"; // NOLINT +static std::string batch_reindex_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(br_forward,Dtype)(const int_tp count, const int_tp inner_dim,\n __global const Dtype* in,\n __global const Dtype* permut,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / (inner_dim);\n int_tp in_n = (int_tp) (permut[n]);\n out[index] = in[in_n * (inner_dim) + index % (inner_dim)];\n }\n}\n\n__kernel void TEMPLATE(br_backward,Dtype)(const int_tp count, const int_tp inner_dim,\n __global const Dtype* in,\n __global const Dtype* top_indexes,\n __global const Dtype* begins,\n __global const Dtype* counts,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / (inner_dim);\n out[index] = 0;\n int_tp lower = (int_tp) (begins[n]);\n int_tp upper = lower + (int_tp) (counts[n]);\n for (int_tp i = lower; i < upper; ++i) {\n int_tp in_n = (int_tp) (top_indexes[i]);\n out[index] += in[in_n * (inner_dim) + index % (inner_dim)];\n }\n }\n}"; // NOLINT +static std::string bias_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(bias_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const Dtype* bias,\n const int_tp bias_dim,\n const int_tp inner_dim,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp bias_index = (index / inner_dim) % bias_dim;\n out[index] = in[index] + bias[bias_index];\n }\n}\n\n__kernel void TEMPLATE(scale_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const Dtype* scale,\n const int_tp scale_dim,\n const int_tp inner_dim,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp scale_index = (index / inner_dim) % scale_dim;\n out[index] = in[index] * scale[scale_index];\n }\n}\n\n__kernel void TEMPLATE(scale_bias_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const Dtype* scale,\n __global const Dtype* bias,\n const int_tp scale_dim,\n const int_tp inner_dim,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp scale_index = (index / inner_dim) % scale_dim;\n out[index] = in[index] * scale[scale_index] + bias[scale_index];\n }\n}"; // NOLINT +static std::string bnll_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(bnll_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n if (in[index] > 0.0f) {\n out[index] = in[index] + log((Dtype) (1.0 + exp(-in[index])));\n } else {\n out[index] = log((Dtype) (1.0 + exp(in[index])));\n }\n }\n}\n\n__kernel void TEMPLATE(bnll_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff) {\n Dtype kBNLL_THRESHOLD = 50.;\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n Dtype expval = exp(min(in_data[index], kBNLL_THRESHOLD));\n out_diff[index] = in_diff[index] * expval / (expval + 1.);\n }\n}"; // NOLINT +static std::string channel_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(kernel_channel_max,Dtype)(const int_tp num, const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* data,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < num * spatial_dim; index +=\n get_global_size(0)) {\n int_tp n = index / spatial_dim;\n int_tp s = index % spatial_dim;\n float maxval = -FLT_MAX;\n for (int_tp c = 0; c < channels; ++c) {\n maxval = max((Dtype)(data[(n * channels + c) * spatial_dim + s]), (Dtype)maxval);\n }\n out[index] = maxval;\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_subtract,Dtype)(const int_tp count, const int_tp num,\n const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* channel_max,\n __global Dtype* data) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / channels / spatial_dim;\n int_tp s = index % spatial_dim;\n data[index] -= channel_max[n * spatial_dim + s];\n }\n}\n\n__kernel void TEMPLATE(kernel_exp,Dtype)(const int_tp count, __global const Dtype* data,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n out[index] = exp(data[index]);\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_sum,Dtype)(const int_tp num, const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* data,\n __global Dtype* channel_sum) {\n for (int_tp index = get_global_id(0); index < num * spatial_dim; index +=\n get_global_size(0)) {\n int_tp n = index / spatial_dim;\n int_tp s = index % spatial_dim;\n Dtype sum = 0;\n for (int_tp c = 0; c < channels; ++c) {\n sum += data[(n * channels + c) * spatial_dim + s];\n }\n channel_sum[index] = sum;\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_div,Dtype)(const int_tp count, const int_tp num,\n const int_tp channels, const int_tp spatial_dim,\n __global const Dtype* channel_sum,\n __global Dtype* data) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / channels / spatial_dim;\n int_tp s = index % spatial_dim;\n data[index] /= channel_sum[n * spatial_dim + s];\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_dot,Dtype)(const int_tp num, const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* data_1,\n __global const Dtype* data_2,\n __global Dtype* channel_dot) {\n for (int_tp index = get_global_id(0); index < num * spatial_dim; index +=\n get_global_size(0)) {\n int_tp n = index / spatial_dim;\n int_tp s = index % spatial_dim;\n Dtype dot = 0;\n for (int_tp c = 0; c < channels; ++c) {\n dot += (data_1[(n * channels + c) * spatial_dim + s]\n * data_2[(n * channels + c) * spatial_dim + s]);\n }\n channel_dot[index] = dot;\n }\n}"; // NOLINT +static std::string concat_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(concat,Dtype)(const int_tp nthreads, __global const Dtype* in_data,\n const int forward, const int_tp num_concats,\n const int_tp concat_size,\n const int_tp top_concat_axis,\n const int_tp bottom_concat_axis,\n const int_tp offset_concat_axis,\n __global Dtype* out_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp total_concat_size = concat_size * bottom_concat_axis;\n const int_tp concat_num = index / total_concat_size;\n const int_tp concat_index = index % total_concat_size;\n const int_tp top_index = concat_index\n + (concat_num * top_concat_axis + offset_concat_axis) * concat_size;\n if (forward == 1) {\n out_data[top_index] = in_data[index];\n } else {\n out_data[index] = in_data[top_index];\n }\n }\n}"; // NOLINT +static std::string contrastive_loss_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(cll_backward,Dtype)(const int_tp count, const int_tp channels,\n const Dtype margin, const int legacy_version,\n const Dtype alpha, __global const Dtype* y,\n __global const Dtype* diff, __global const Dtype* dist_sq,\n __global Dtype *bottom_diff) {\n for (int_tp i = get_global_id(0); i < count;\n i += get_global_size(0)) {\n int_tp n = i / channels; // the num index, to access y and dist_sq\n if ((int_tp)(y[n])) { // similar pairs\n bottom_diff[i] = alpha * diff[i];\n } else { // dissimilar pairs\n Dtype mdist = 0.0;\n Dtype beta = 0.0;\n if (legacy_version == 1) {\n mdist = (margin - dist_sq[n]);\n beta = -alpha;\n } else {\n Dtype dist = sqrt(dist_sq[n]);\n mdist = (margin - dist);\n beta = -alpha * mdist / (dist + 1e-4) * diff[i];\n }\n if (mdist > 0.0) {\n bottom_diff[i] = beta;\n } else {\n bottom_diff[i] = 0;\n }\n }\n }\n}"; // NOLINT +static std::string dropout_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(dropout_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const uint_tp* mask,\n const uint_tp threshold,\n const Dtype scale,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] * ((mask[index] > threshold)?1.0:0.0) * scale;\n }\n}\n\n__kernel void TEMPLATE(dropout_backward,Dtype)(\n const int_tp n, __global const Dtype* in_diff,\n __global const uint_tp* mask, const uint_tp threshold,\n const Dtype scale,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] = in_diff[index] * ((mask[index] > threshold)?1.0:0.0) * scale;\n }\n}"; // NOLINT +static std::string eltwise_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(eltwise_max_forward,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data_a,\n __global const Dtype* bottom_data_b, const int_tp blob_idx,\n __global Dtype* top_data,\n __global int_tp* mask) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n if (bottom_data_a[index] > bottom_data_b[index]) {\n // only update for very first bottom_data blob (blob_idx == 0)\n if (blob_idx == 0) {\n maxval = bottom_data_a[index];\n top_data[index] = maxval;\n maxidx = blob_idx;\n mask[index] = maxidx;\n }\n } else {\n maxval = bottom_data_b[index];\n top_data[index] = maxval;\n maxidx = blob_idx + 1;\n mask[index] = maxidx;\n }\n }\n}\n\n__kernel void TEMPLATE(eltwise_max_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int_tp blob_idx,\n __global const int_tp* mask,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n Dtype gradient = 0;\n if (mask[index] == blob_idx) {\n gradient += top_diff[index];\n }\n bottom_diff[index] = gradient;\n }\n}"; // NOLINT +static std::string elu_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(elu_forward,Dtype)(const int n, __global const Dtype* in,\n __global Dtype* out,\n Dtype alpha) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] > 0 ? in[index] : alpha * (exp(in[index]) - 1.0);\n }\n}\n\n__kernel void TEMPLATE(elu_backward,Dtype)(const int n, __global const Dtype* in_diff,\n __global const Dtype* out_data,\n __global const Dtype* in_data,\n __global Dtype* out_diff,\n Dtype alpha) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] =\n in_data[index] > 0 ?\n in_diff[index] : in_diff[index] * (out_data[index] + alpha);\n }\n}"; // NOLINT +static std::string embed_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(embed_forward,Dtype)(const int_tp nthreads,\n __global const Dtype* bottom_data,\n __global const Dtype* weight,\n const int_tp M, const int_tp N,\n const int_tp K,\n __global Dtype* top_data) {\n for (int_tp top_index = get_global_id(0); top_index < nthreads;\n top_index += get_global_size(0)) {\n const int_tp n = top_index / N;\n const int_tp d = top_index % N;\n const int_tp index = (int_tp)(bottom_data[n]);\n const int_tp weight_index = index * N + d;\n top_data[top_index] = weight[weight_index];\n }\n }\n\n// atomic_add from: http://suhorukov.blogspot.com/2011/12/opencl-11-atomic-operations-on-floating.html\n#if (TYPE == TYPE_FLOAT)\ninline void TEMPLATE(atomic_add,Dtype)(volatile __global Dtype *source, const Dtype operand) {\n union {\n uint_tp intVal;\n Dtype floatVal;\n } newVal;\n union {\n uint_tp intVal;\n Dtype floatVal;\n } prevVal;\n do {\n prevVal.floatVal = *source;\n newVal.floatVal = prevVal.floatVal + operand;\n } while (atomic_cmpxchg((volatile __global unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);\n}\n\n__kernel void TEMPLATE(embed_backward,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data,\n __global const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K,\n __global Dtype* weight_diff) {\n for (int_tp top_index = get_global_id(0); top_index < nthreads;\n top_index += get_global_size(0)) {\n const int_tp n = top_index / N;\n const int_tp d = top_index % N;\n const int_tp index = (int_tp)(bottom_data[n]);\n const int_tp weight_index = index * N + d;\n\n TEMPLATE(atomic_add,Dtype)((weight_diff + weight_index), *(top_diff + top_index));\n }\n}\n#endif\n\n#if (TYPE == TYPE_DOUBLE)\n#ifdef ATOMICS_64_AVAILABLE\ninline void TEMPLATE(atomic_add,Dtype)(volatile __global Dtype *source, const Dtype operand) {\n union {\n unsigned long intVal;\n Dtype floatVal;\n } newVal;\n union {\n unsigned long intVal;\n Dtype floatVal;\n } prevVal;\n do {\n prevVal.floatVal = *source;\n newVal.floatVal = prevVal.floatVal + operand;\n } while (atom_cmpxchg((volatile __global unsigned long *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);\n}\n\n__kernel void TEMPLATE(embed_backward,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data,\n __global const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K,\n __global Dtype* weight_diff) {\n for (int_tp top_index = get_global_id(0); top_index < nthreads;\n top_index += get_global_size(0)) {\n const int_tp n = top_index / N;\n const int_tp d = top_index % N;\n const int_tp index = (int_tp)(bottom_data[n]);\n const int_tp weight_index = index * N + d;\n\n TEMPLATE(atomic_add,Dtype)((weight_diff + weight_index), *(top_diff + top_index));\n }\n}\n#endif\n#endif"; // NOLINT +static std::string fillbuffer_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(fillbuffer,Dtype)(const int_tp n, const char alpha, __global char* x,\n const int_tp offx) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n x[index + offx] = alpha;\n }\n}\n\n__kernel void TEMPLATE(fill,Dtype)(const int_tp n, const Dtype alpha, __global Dtype* x,\n const int_tp offx) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n x[index + offx] = alpha;\n }\n}"; // NOLINT +static std::string im2col_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(im2col,Dtype)(const int_tp n,\n __global const Dtype* data_im,\n const int_tp data_im_off,\n const int_tp height, const int_tp width,\n const int_tp kernel_h,\n const int_tp kernel_w, const int_tp pad_h,\n const int_tp pad_w, const int_tp stride_h,\n const int_tp stride_w,\n const int_tp dilation_h,\n const int_tp dilation_w,\n const int_tp height_col,\n const int_tp width_col,\n __global Dtype* data_col,\n const int_tp data_col_off) {\n\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp h_index = index / width_col;\n const int_tp h_col = h_index % height_col;\n const int_tp w_col = index % width_col;\n const int_tp c_im = h_index / height_col;\n const int_tp c_col = c_im * kernel_h * kernel_w;\n const int_tp h_offset = h_col * stride_h - pad_h;\n const int_tp w_offset = w_col * stride_w - pad_w;\n __global Dtype* data_col_ptr = data_col + data_col_off;\n data_col_ptr += (c_col * height_col + h_col) * width_col + w_col;\n __global const Dtype* data_im_ptr = data_im + data_im_off;\n data_im_ptr += (c_im * height + h_offset) * width + w_offset;\n for (int_tp i = 0; i < kernel_h; ++i) {\n for (int_tp j = 0; j < kernel_w; ++j) {\n int_tp h_im = h_offset + i * dilation_h;\n int_tp w_im = w_offset + j * dilation_w;\n *data_col_ptr =\n (h_im >= 0 && w_im >= 0 && h_im < height && w_im < width) ?\n data_im_ptr[i * dilation_h * width + j * dilation_w] : 0;\n data_col_ptr += height_col * width_col;\n }\n }\n }\n}\n\n__kernel void TEMPLATE(col2im,Dtype)(const int_tp n,\n __global const Dtype* data_col,\n const int_tp data_col_off,\n const int_tp height, const int_tp width,\n const int_tp channels,\n const int_tp kernel_h,\n const int_tp kernel_w, const int_tp pad_h,\n const int_tp pad_w, const int_tp stride_h,\n const int_tp stride_w,\n const int_tp dilation_h,\n const int_tp dilation_w,\n const int_tp height_col,\n const int_tp width_col,\n __global Dtype* data_im,\n const int_tp data_im_off) {\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n Dtype val = 0;\n const int_tp w_im = index % width + pad_w;\n const int_tp h_im = (index / width) % height + pad_h;\n const int_tp c_im = index / (width * height);\n int_tp kernel_extent_w = (kernel_w - 1) * dilation_w + 1;\n int_tp kernel_extent_h = (kernel_h - 1) * dilation_h + 1;\n // compute the start and end of the output\n const int_tp w_col_start =\n (w_im < kernel_extent_w) ? 0 : (w_im - kernel_extent_w) / stride_w + 1;\n const int_tp w_col_end = min(w_im / stride_w + 1, width_col);\n const int_tp h_col_start =\n (h_im < kernel_extent_h) ? 0 : (h_im - kernel_extent_h) / stride_h + 1;\n const int_tp h_col_end = min(h_im / stride_h + 1, height_col);\n // TODO: use LCM of stride and dilation to avoid unnecessary loops\n for (int_tp h_col = h_col_start; h_col < h_col_end; h_col += 1) {\n for (int_tp w_col = w_col_start; w_col < w_col_end; w_col += 1) {\n int_tp h_k = (h_im - h_col * stride_h);\n int_tp w_k = (w_im - w_col * stride_w);\n if (h_k % dilation_h == 0 && w_k % dilation_w == 0) {\n h_k /= dilation_h;\n w_k /= dilation_w;\n int_tp data_col_index = (((c_im * kernel_h + h_k) * kernel_w + w_k) *\n height_col + h_col) * width_col + w_col;\n val += data_col[data_col_off + data_col_index];\n }\n }\n }\n data_im[data_im_off + index] = val;\n }\n}"; // NOLINT +static std::string im2col_nd_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(im2col_nd, Dtype)(const int_tp n, const int_tp num_axes,\n const int_tp channel_axis,\n __global const Dtype* data_im,\n const int_tp data_im_off,\n __global const int_tp* im_shape,\n __global const int_tp* col_shape,\n __global const int_tp* kernel_shape,\n __global const int_tp* pad,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global Dtype* data_col,\n const int_tp data_col_off) {\n int_tp d_temp[6];\n int_tp d_iter[6];\n int_tp i;\n\n __global const int_tp* im_shape_ptr = im_shape + channel_axis;\n __global const int_tp* col_shape_ptr = col_shape + channel_axis;\n\n __local int_tp shared_dilation[6];\n __local int_tp shared_kernel_shape[6];\n __local int_tp shared_pad[6];\n __local int_tp shared_stride[6];\n __local int_tp shared_col_shape[6 + 1];\n __local int_tp shared_im_shape[6 + 1];\n\n for (int li = get_local_id(0); li < num_axes; li += get_local_size(0)) {\n shared_dilation[li] = dilation[li];\n shared_kernel_shape[li] = kernel_shape[li];\n shared_pad[li] = pad[li];\n shared_stride[li] = stride[li];\n }\n\n for (int li = get_local_id(0); li < num_axes + 1; li += get_local_size(0)) {\n shared_col_shape[li] = col_shape_ptr[li];\n shared_im_shape[li] = im_shape_ptr[li];\n }\n\n barrier(CLK_LOCAL_MEM_FENCE);\n\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n // Initialize channel_in, computed in the loop below, with int_tpermediate\n // computations used to compute the spatial indices.\n int_tp channel_in = index;\n int_tp channel_out = 1;\n for (i = num_axes - 1; i >= 0; --i) {\n d_temp[i] = channel_in % shared_col_shape[i + 1];\n channel_in /= shared_col_shape[i + 1];\n channel_out *= shared_kernel_shape[i];\n }\n channel_out *= channel_in;\n int_tp data_col_inc = 1;\n for (i = 0; i < num_axes; ++i) {\n channel_out *= shared_col_shape[i + 1];\n channel_out += d_temp[i];\n d_temp[i] = d_temp[i] * shared_stride[i] - shared_pad[i];\n channel_in *= shared_im_shape[i + 1];\n channel_in += d_temp[i];\n data_col_inc *= shared_col_shape[i + 1];\n d_iter[i] = 0;\n }\n __global Dtype* data_col_ptr = data_col + data_col_off + channel_out;\n __global const Dtype* data_im_ptr = data_im + data_im_off + channel_in;\n bool incremented;\n do {\n bool in_range = true;\n for (i = 0; i < num_axes; ++i) {\n const int_tp d_iter_im = d_iter[i] * shared_dilation[i] + d_temp[i];\n in_range &= d_iter_im >= 0 && d_iter_im < shared_im_shape[i + 1];\n if (!in_range) {\n break;\n }\n }\n if (in_range) {\n int_tp data_im_offset = d_iter[0] * shared_dilation[0];\n for (i = 1; i < num_axes; ++i) {\n data_im_offset *= shared_im_shape[i + 1];\n data_im_offset += d_iter[i] * shared_dilation[i];\n }\n *data_col_ptr = data_im_ptr[data_im_offset];\n } else {\n *data_col_ptr = 0;\n }\n data_col_ptr += data_col_inc;\n incremented = false;\n for (i = num_axes - 1; i >= 0; --i) {\n const int_tp d_max = shared_kernel_shape[i];\n if (d_iter[i] == d_max - 1) {\n d_iter[i] = 0;\n } else { // d_iter[i] < d_max - 1\n ++d_iter[i];\n incremented = true;\n break;\n }\n } // for (int_tp i = num_axes - 1; i >= 0; --i)\n } while (incremented); // do\n }\n}\n\n__kernel void TEMPLATE(col2im_nd, Dtype)(const int_tp n, const int_tp num_axes,\n const int_tp channel_axis,\n __global const Dtype* data_col,\n const int_tp data_col_off,\n __global const int_tp* im_shape,\n __global const int_tp* col_shape,\n __global const int_tp* kernel_shape,\n __global const int_tp* pad,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global Dtype* data_im,\n const int_tp data_im_off) {\n int_tp d_im[6];\n int_tp d_col_iter[6];\n int_tp d_col_start[6];\n int_tp d_col_end[6];\n\n __global const int_tp* im_shape_ptr = im_shape + channel_axis;\n __global const int_tp* col_shape_ptr = col_shape + channel_axis;\n\n __local int_tp shared_dilation[6];\n __local int_tp shared_kernel_shape[6];\n __local int_tp shared_pad[6];\n __local int_tp shared_stride[6];\n __local int_tp shared_col_shape[6 + 1];\n __local int_tp shared_im_shape[6 + 1];\n\n for (int li = get_local_id(0); li < num_axes; li += get_local_size(0)) {\n shared_dilation[li] = dilation[li];\n shared_kernel_shape[li] = kernel_shape[li];\n shared_pad[li] = pad[li];\n shared_stride[li] = stride[li];\n }\n for (int li = get_local_id(0); li < num_axes + 1; li += get_local_size(0)) {\n shared_col_shape[li] = col_shape_ptr[li];\n shared_im_shape[li] = im_shape_ptr[li];\n }\n\n barrier(CLK_LOCAL_MEM_FENCE);\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n // Initialize channel_in, computed in the loop below, with intermediate\n // computations used to compute the spatial indices.\n int_tp c_im = index;\n // Calculate d_im (image dimensions).\n for (int_tp i = num_axes - 1; i >= 0; --i) {\n d_im[i] = c_im % shared_im_shape[i + 1] + shared_pad[i];\n c_im /= shared_im_shape[i + 1];\n }\n // Calculate col start/end indices.\n bool done = false;\n for (int_tp i = 0; i < num_axes; ++i) {\n const int_tp kernel_extent = shared_dilation[i]\n * (shared_kernel_shape[i] - 1) + 1;\n d_col_start[i] = d_col_iter[i] =\n (d_im[i] < kernel_extent) ?\n 0 : (d_im[i] - kernel_extent) / shared_stride[i] + 1;\n d_col_end[i] = min(d_im[i] / shared_stride[i] + 1,\n shared_col_shape[i + 1]);\n if (d_col_start[i] >= d_col_end[i]) {\n // Skip computation if the dimension is 0 at any spatial axis --\n // final val will be 0.\n data_im[index] = 0;\n done = true;\n break; // for (int_tp i = 0; i < num_axes; ++i)\n }\n }\n if (!done) {\n // Loop over the col to compute the output val.\n Dtype val = 0;\n bool incremented = true;\n bool skip = false;\n do {\n // Compute the final offset.\n int_tp final_offset = 0;\n int_tp kernel_shape_prod = 1;\n int_tp kernel_index;\n for (int_tp i = num_axes - 1; i >= 0; --i) {\n kernel_index = d_im[i] - d_col_iter[i] * shared_stride[i];\n if (kernel_index % shared_dilation[i]) {\n skip = true;\n break;\n } else {\n kernel_index /= shared_dilation[i];\n final_offset += kernel_index * kernel_shape_prod;\n kernel_shape_prod *= shared_kernel_shape[i];\n }\n }\n if (!skip) {\n final_offset += kernel_shape_prod * c_im;\n for (int_tp i = 0; i < num_axes; ++i) {\n final_offset *= shared_col_shape[i + 1];\n final_offset += d_col_iter[i];\n }\n val += data_col[data_col_off + final_offset];\n }\n skip = false;\n incremented = false;\n for (int_tp i = num_axes - 1; i >= 0; --i) {\n const int_tp d_max = d_col_end[i];\n if (d_col_iter[i] == d_max - 1) {\n d_col_iter[i] = d_col_start[i];\n } else { // d_col_iter[i] < d_max - 1\n ++d_col_iter[i];\n incremented = true;\n break; // for (int_tp i = num_axes - 1; i >= 0; --i)\n }\n } // for (int_tp i = num_axes - 1; i >= 0; --i)\n } while (incremented);\n data_im[data_im_off + index] = val;\n }\n }\n}"; // NOLINT +static std::string lrn_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(lrn_compute_output,Dtype)(const int_tp nthreads,\n __global const Dtype* in,\n __global const Dtype* scale,\n const Dtype negative_beta,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n out[index] = in[index] * pow(scale[index], negative_beta);\n }\n}\n\n__kernel void TEMPLATE(lrn_fill_scale,Dtype)(const int_tp nthreads, __global const Dtype* in,\n const int_tp num, const int_tp channels,\n const int_tp height, const int_tp width, const int_tp size,\n const Dtype alpha_over_size, const Dtype k,\n __global Dtype* const scale) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp n = index / width / height;\n const int_tp offset = (n * channels * height + h) * width + w;\n const int_tp step = height * width;\n __global const Dtype* in_off = in + offset;\n __global Dtype* scale_off = scale + offset;\n int_tp head = 0;\n const int_tp pre_pad = (size - 1) / 2;\n const int_tp post_pad = size - pre_pad - 1;\n Dtype accum_scale = 0;\n // fill the scale at [n, :, h, w]\n // accumulate values\n while (head < post_pad && head < channels) {\n accum_scale += in_off[head * step] * in_off[head * step];\n ++head;\n }\n // both add and subtract\n while (head < channels) {\n accum_scale += in_off[head * step] * in_off[head * step];\n if (head - size >= 0) {\n accum_scale -= in_off[(head - size) * step]\n * in_off[(head - size) * step];\n }\n scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size;\n ++head;\n }\n // subtract only\n while (head < channels + post_pad) {\n if (head - size >= 0) {\n accum_scale -= in_off[(head - size) * step]\n * in_off[(head - size) * step];\n }\n scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size;\n ++head;\n }\n }\n}\n\n__kernel void TEMPLATE(lrn_compute_diff,Dtype)(const int_tp nthreads,\n __global const Dtype* bottom_data,\n __global const Dtype* top_data,\n __global const Dtype* scale,\n __global const Dtype* top_diff, const int_tp num,\n const int_tp channels, const int_tp height,\n const int_tp width, const int_tp size,\n const Dtype negative_beta,\n const Dtype cache_ratio,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp n = index / width / height;\n const int_tp offset = (n * channels * height + h) * width + w;\n const int_tp step = height * width;\n __global const Dtype* bottom_off = bottom_data + offset;\n __global const Dtype* top_off = top_data + offset;\n __global const Dtype* scale_off = scale + offset;\n __global const Dtype* top_diff_off = top_diff + offset;\n __global Dtype* bottom_diff_off = bottom_diff + offset;\n int_tp head = 0;\n const int_tp pre_pad = size - (size + 1) / 2;\n const int_tp post_pad = size - pre_pad - 1;\n Dtype accum_ratio = 0;\n // accumulate values\n while (head < post_pad && head < channels) {\n accum_ratio += top_diff_off[head * step] * top_off[head * step]\n / scale_off[head * step];\n ++head;\n }\n // both add and subtract\n while (head < channels) {\n accum_ratio += top_diff_off[head * step] * top_off[head * step]\n / scale_off[head * step];\n if (head - size >= 0) {\n accum_ratio -= top_diff_off[(head - size) * step]\n * top_off[(head - size) * step] / scale_off[(head - size) * step];\n }\n bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad)\n * step] * pow(scale_off[(head - post_pad) * step], negative_beta)\n - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio;\n ++head;\n }\n // subtract only\n while (head < channels + post_pad) {\n if (head - size >= 0) {\n accum_ratio -= top_diff_off[(head - size) * step]\n * top_off[(head - size) * step] / scale_off[(head - size) * step];\n }\n bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad)\n * step] * pow(scale_off[(head - post_pad) * step], negative_beta)\n - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio;\n ++head;\n }\n }\n}"; // NOLINT +static std::string math_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(mul,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa,\n __global Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = a[index + offa] * b[index + offb];\n }\n}\n\n__kernel void TEMPLATE(div,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa,\n __global Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = a[index + offa] / b[index + offb];\n }\n}\n\n__kernel void TEMPLATE(add_scalar,Dtype)(const int_tp N, const Dtype alpha,\n__global Dtype* Y,\n const int_tp offY) {\n for (int_tp index = get_global_id(0); index < N; index += get_global_size(0)) {\n Y[offY + index] += alpha;\n }\n}\n\n__kernel void TEMPLATE(add,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global const Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = a[offa + index] + b[offb + index];\n }\n}\n\n__kernel void TEMPLATE(sub,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global const Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = a[offa + index] - b[offb + index];\n }\n}\n\n__kernel void TEMPLATE(abs,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = fabs((Dtype)(a[offa + index]));\n }\n}\n\n__kernel void TEMPLATE(exp,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = exp(a[offa + index]);\n }\n}\n\n__kernel void TEMPLATE(log,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = log((Dtype)(a[offa + index]));\n }\n}\n\n__kernel void TEMPLATE(powx,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, Dtype alpha,\n __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n if(alpha == 2.0) {\n y[offy + index] = pow((Dtype)fabs(a[offa + index]), (Dtype)alpha);\n } else {\n y[offy + index] = pow((Dtype)a[offa + index], (Dtype)alpha);\n }\n }\n}\n\n__kernel void TEMPLATE(sign,Dtype)(const int_tp n, __global const Dtype* x,\n const int_tp offx, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = (0.0 < x[index + offx])\n - (x[index + offx] < 0.0);\n }\n}\n\n__kernel void TEMPLATE(sgnbit,Dtype)(const int_tp n, __global const Dtype* x,\n const int_tp offx, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = signbit(x[index + offx]);\n }\n}"; // NOLINT +static std::string mergecrop_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(merge_copy_forward, Dtype)(const int_tp nthreads,\n const int_tp dims,\n __global const Dtype* bottom_a,\n const int_tp forward_a,\n __global const Dtype* bottom_b,\n const int_tp forward_b,\n __global Dtype* top,\n const int_tp num,\n const int_tp channels_a,\n const int_tp channels_b,\n __global const int_tp* shape_a,\n __global const int_tp* shape_b) {\n int_tp pad[6];\n int_tp tmp_idx[6];\n int_tp size_a = 1;\n int_tp size_b = 1;\n\n for (int_tp i = 0; i < dims; ++i) {\n pad[i] = (shape_b[i] - shape_a[i]) / 2;\n size_a *= shape_a[i];\n size_b *= shape_b[i];\n }\n\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n int_tp batch_id = index / ((channels_a + channels_b) * size_a);\n int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a)\n / (channels_a * size_a)) % 2;\n int_tp counter = index;\n for (int_tp i = dims - 1; i >= 0; --i) {\n tmp_idx[i] = counter % shape_a[i];\n counter /= shape_a[i];\n }\n\n if (bottom_id == 0) {\n int_tp channel_id = (index / size_a) % channels_a;\n int_tp aidx = batch_id * channels_a + channel_id;\n for (int_tp i = 0; i < dims; ++i) {\n aidx *= shape_a[i];\n aidx += tmp_idx[i];\n }\n top[index] = (forward_a == 1) ? bottom_a[aidx] : 0;\n } else {\n int_tp channel_id = (index / size_a) % channels_b;\n int_tp bidx = (batch_id * channels_b + channel_id) * size_b;\n int_tp btemp = 1;\n for (int_tp i = dims - 1; i >= 0; --i) {\n bidx += btemp * (tmp_idx[i] + pad[i]);\n btemp *= shape_b[i];\n }\n top[index] = (forward_b == 1) ? bottom_b[bidx] : 0;\n }\n }\n}\n\n__kernel void TEMPLATE(merge_copy_backward,Dtype)(const int_tp nthreads,\n const int_tp dims,\n __global Dtype* bottom_a,\n const int_tp backward_a,\n __global Dtype* bottom_b,\n const int_tp backward_b,\n __global const Dtype* top,\n const int_tp num,\n const int_tp channels_a,\n const int_tp channels_b,\n __global const int_tp* shape_a,\n __global const int_tp* shape_b) {\n int_tp pad[6];\n int_tp tmp_idx[6];\n int_tp size_a = 1;\n int_tp size_b = 1;\n\n for (int_tp i = 0; i < dims; ++i) {\n pad[i] = (shape_b[i] - shape_a[i]) / 2;\n size_a *= shape_a[i];\n size_b *= shape_b[i];\n }\n\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n int_tp batch_id = index / ((channels_a + channels_b) * size_a);\n int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a)\n / (channels_a * size_a)) % 2;\n int_tp counter = index;\n for (int_tp i = dims - 1; i >= 0; --i) {\n tmp_idx[i] = counter % shape_a[i];\n counter /= shape_a[i];\n }\n\n if (bottom_id == 0) {\n int_tp channel_id = (index / size_a) % channels_a;\n int_tp aidx = batch_id * channels_a + channel_id;\n for (int_tp i = 0; i < dims; ++i) {\n aidx *= shape_a[i];\n aidx += tmp_idx[i];\n }\n bottom_a[aidx] = (backward_a == 1) ? top[index] : 0;\n } else {\n int_tp channel_id = (index / size_a) % channels_b;\n int_tp bidx = (batch_id * channels_b + channel_id) * size_b;\n int_tp btemp = 1;\n for (int_tp i = dims - 1; i >= 0; --i) {\n bidx += btemp * (tmp_idx[i] + pad[i]);\n btemp *= shape_b[i];\n }\n bottom_b[bidx] = (backward_b == 1) ? top[index] : 0;\n }\n }\n}"; // NOLINT +static std::string pooling_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(max_pool_forward,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* top_data,\n const int use_mask, __global int_tp* mask, __global Dtype* top_mask) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n const int_tp hend = min(hstart + kernel_h, height);\n const int_tp wend = min(wstart + kernel_w, width);\n hstart = max(hstart, (int_tp)0);\n wstart = max(wstart, (int_tp)0);\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n if (bottom_slice[h * width + w] > maxval) {\n maxidx = h * width + w;\n maxval = bottom_slice[maxidx];\n }\n }\n }\n top_data[index] = maxval;\n if (use_mask == 1) {\n mask[index] = maxidx;\n } else {\n top_mask[index] = maxidx;\n }\n }\n}\n\n__kernel void TEMPLATE(ave_pool_forward,Dtype)(\n const int_tp nthreads, __global const Dtype* const bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, const int_tp pad_h,\n const int_tp pad_w, __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + kernel_h, height + pad_h);\n int_tp wend = min(wstart + kernel_w, width + pad_w);\n const int_tp pool_size = (hend - hstart) * (wend - wstart);\n hstart = max(hstart, (int_tp)0);\n wstart = max(wstart, (int_tp)0);\n hend = min(hend, height);\n wend = min(wend, width);\n Dtype aveval = 0;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n aveval += bottom_slice[h * width + w];\n }\n }\n top_data[index] = aveval / pool_size;\n }\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_train,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w,\n __global Dtype* rand_idx,\n __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n const int_tp hstart = ph * stride_h;\n const int_tp hend = min(hstart + kernel_h, height);\n const int_tp wstart = pw * stride_w;\n const int_tp wend = min(wstart + kernel_w, width);\n Dtype cumsum = 0.;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n cumsum += bottom_slice[h * width + w];\n }\n }\n const float thres = rand_idx[index] * cumsum;\n // Second pass: get value, and set index.\n cumsum = 0;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n cumsum += bottom_slice[h * width + w];\n if (cumsum >= thres) {\n rand_idx[index] = ((n * channels + c) * height + h) * width + w;\n top_data[index] = bottom_slice[h * width + w];\n h = hend;\n w = wend;\n }\n }\n }\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_test,Dtype)(\n const int_tp nthreads, __global const Dtype* const bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w,\n __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n const int_tp hstart = ph * stride_h;\n const int_tp hend = min(hstart + kernel_h, height);\n const int_tp wstart = pw * stride_w;\n const int_tp wend = min(wstart + kernel_w, width);\n // We set cumsum to be 0 to avoid divide-by-zero problems\n Dtype cumsum = FLT_MIN;\n Dtype cumvalues = 0.;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n cumsum += bottom_slice[h * width + w];\n cumvalues += bottom_slice[h * width + w] * bottom_slice[h * width + w];\n }\n }\n top_data[index] = cumvalues / cumsum;\n }\n}\n\n__kernel void TEMPLATE(max_pool_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int use_mask,\n __global const int_tp* mask,\n __global const Dtype* top_mask,\n const int_tp num,\n const int_tp channels,\n const int_tp height,\n const int_tp width,\n const int_tp pooled_height,\n const int_tp pooled_width,\n const int_tp kernel_h,\n const int_tp kernel_w,\n const int_tp stride_h,\n const int_tp stride_w,\n const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local index\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp c = (index / width / height) % channels;\n const int_tp n = index / width / height / channels;\n const int_tp phstart =\n (h + pad_h < kernel_h) ? 0 : (h + pad_h - kernel_h) / stride_h + 1;\n const int_tp phend = min((h + pad_h) / stride_h + 1, pooled_height);\n const int_tp pwstart =\n (w + pad_w < kernel_w) ? 0 : (w + pad_w - kernel_w) / stride_w + 1;\n const int_tp pwend = min((w + pad_w) / stride_w + 1, pooled_width);\n Dtype gradient = 0;\n const int_tp offset = (n * channels + c) * pooled_height * pooled_width;\n __global const Dtype* top_diff_slice = top_diff + offset;\n if (use_mask == 1) {\n __global const int_tp* mask_slice = mask + offset;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n if (mask_slice[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_slice[ph * pooled_width + pw];\n }\n }\n }\n } else {\n __global const Dtype* top_mask_slice = top_mask + offset;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n if (top_mask_slice[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_slice[ph * pooled_width + pw];\n }\n }\n }\n }\n bottom_diff[index] = gradient;\n }\n}\n\n__kernel void TEMPLATE(ave_pool_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int_tp num,\n const int_tp channels,\n const int_tp height,\n const int_tp width,\n const int_tp pooled_height,\n const int_tp pooled_width,\n const int_tp kernel_h,\n const int_tp kernel_w,\n const int_tp stride_h,\n const int_tp stride_w,\n const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local index\n // find out the local offset\n const int_tp w = index % width + pad_w;\n const int_tp h = (index / width) % height + pad_h;\n const int_tp c = (index / width / height) % channels;\n const int_tp n = index / width / height / channels;\n const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1;\n const int_tp phend = min(h / stride_h + 1, pooled_height);\n const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1;\n const int_tp pwend = min(w / stride_w + 1, pooled_width);\n Dtype gradient = 0.0;\n __global const Dtype* const top_diff_slice = top_diff\n + (n * channels + c) * pooled_height * pooled_width;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n // figure out the pooling size\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + kernel_h, height + pad_h);\n int_tp wend = min(wstart + kernel_w, width + pad_w);\n int_tp pool_size = (hend - hstart) * (wend - wstart);\n gradient += top_diff_slice[ph * pooled_width + pw] / pool_size;\n }\n }\n bottom_diff[index] = gradient;\n }\n}\n\n__kernel void TEMPLATE(sto_pool_backward,Dtype)(\n const int_tp nthreads, __global const Dtype* rand_idx,\n __global const Dtype* const top_diff, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp stride_h,\n const int_tp stride_w, __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n // find out the local index\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp c = (index / width / height) % channels;\n const int_tp n = index / width / height / channels;\n const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1;\n const int_tp phend = min(h / stride_h + 1, pooled_height);\n const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1;\n const int_tp pwend = min(w / stride_w + 1, pooled_width);\n Dtype gradient = 0.0;\n __global const Dtype* rand_idx_slice = rand_idx\n + (n * channels + c) * pooled_height * pooled_width;\n __global const Dtype* top_diff_slice = top_diff\n + (n * channels + c) * pooled_height * pooled_width;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n gradient += top_diff_slice[ph * pooled_width + pw]\n * (index == (int_tp) (rand_idx_slice[ph * pooled_width + pw])?1.0:0.0);\n }\n }\n bottom_diff[index] = gradient;\n }\n}"; // NOLINT +static std::string pooling_nd_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(max_pool_forward_nd, Dtype)(const int_tp n,\n const int_tp num_axes,\n __global const Dtype* bottom_data,\n const int_tp channels,\n __global const int_tp* size,\n __global const int_tp* pooled_size,\n __global const int_tp* kernel_size,\n __global const int_tp* ext_kernel_size,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global const int_tp* pad,\n __global Dtype* top_data,\n const int use_mask,\n __global int_tp* mask, __global Dtype* top_mask) {\n int_tp d_idx[6];\n int_tp d_start[6];\n int_tp d_end[6];\n int_tp d_iter[6];\n int_tp i;\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n int_tp offset = 1;\n int_tp num = index;\n\n bool do_continue = false;\n\n for (i = num_axes - 1; i >= 0; --i) {\n d_idx[i] = num % pooled_size[i];\n d_start[i] = d_idx[i] * stride[i] - pad[i];\n d_end[i] = min(d_start[i] + ext_kernel_size[i], size[i]);\n d_start[i] = max(d_start[i], (int_tp)0);\n num /= pooled_size[i];\n offset *= size[i];\n d_iter[i] = d_start[i];\n\n if (d_start[i] >= d_end[i]) {\n top_data[index] = -FLT_MAX;\n if (use_mask) {\n mask[index] = -1;\n } else {\n top_mask[index] = -1;\n }\n do_continue = true;\n }\n }\n\n if(do_continue) {\n continue;\n }\n\n int_tp chan = num % channels;\n num /= channels;\n offset *= (num * channels + chan);\n\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n int_tp final_offset = 0;\n\n bool incremented;\n do {\n final_offset = offset;\n int_tp size_prod = 1;\n for (i = num_axes - 1; i >= 0; --i) {\n final_offset += d_iter[i] * size_prod;\n size_prod *= size[i];\n }\n\n if (bottom_data[final_offset] > maxval) {\n maxidx = final_offset;\n maxval = bottom_data[maxidx];\n }\n\n incremented = false;\n for (i = num_axes - 1; i >= 0; --i) {\n if (d_iter[i] >= d_end[i] - dilation[i]) {\n d_iter[i] = d_start[i];\n } else {\n d_iter[i] += dilation[i];\n incremented = true;\n break;\n }\n }\n } while (incremented);\n\n top_data[index] = maxval;\n if (use_mask == 1) {\n mask[index] = maxidx;\n } else {\n top_mask[index] = maxidx;\n }\n }\n}\n\n\n__kernel void TEMPLATE(max_pool_backward_nd, Dtype)(const int_tp n,\n const int_tp num_axes,\n __global const Dtype* top_diff,\n const int use_mask,\n __global const int_tp* mask,\n __global const Dtype* top_mask,\n const int_tp channels,\n __global const int_tp* size,\n __global const int_tp* pooled_size,\n __global const int_tp* kernel_size,\n __global const int_tp* ext_kernel_size,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global const int_tp* pad,\n __global Dtype* bottom_diff) {\n int_tp d_idx[6];\n int_tp d_start[6];\n int_tp d_end[6];\n int_tp d_iter[6];\n int_tp i;\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n // find out the local index\n // find out the local offset\n int_tp offset = 1;\n int_tp num = index;\n for (i = num_axes - 1; i >= 0; --i) {\n d_idx[i] = num % size[i];\n if (dilation[i] > 1) {\n d_start[i] =\n (d_idx[i] < ext_kernel_size[i]) ?\n d_idx[i] % dilation[i] : (d_idx[i] - ext_kernel_size[i]) + 1;\n d_end[i] =\n (d_idx[i] >= pooled_size[i]) ?\n (pooled_size[i] - 1)\n - (pooled_size[i] - 1 - d_start[i]) % dilation[i] :\n d_idx[i];\n } else {\n d_start[i] =\n (d_idx[i] + pad[i] < kernel_size[i]) ?\n 0 : (d_idx[i] + pad[i] - kernel_size[i]) / stride[i] + 1;\n d_end[i] = min((int_tp) ((d_idx[i] + pad[i]) / stride[i] + 1),\n (int_tp) (pooled_size[i]));\n }\n num /= size[i];\n offset *= pooled_size[i];\n d_iter[i] = d_start[i];\n\n if (d_start[i] > d_end[i]) {\n bottom_diff[index] = 0;\n return;\n }\n }\n int_tp chan = num % channels;\n num /= channels;\n offset *= (num * channels + chan);\n\n Dtype gradient = 0;\n int_tp final_offset = 0;\n int_tp im_offset = 0;\n\n bool incremented;\n do {\n final_offset = offset;\n im_offset = 0;\n int_tp size_prod = 1;\n int_tp pooled_size_prod = 1;\n for (i = num_axes - 1; i >= 0; --i) {\n final_offset += d_iter[i] * pooled_size_prod;\n im_offset += d_idx[i] * size_prod;\n size_prod *= size[i];\n pooled_size_prod *= pooled_size[i];\n }\n\n if (use_mask) {\n if (mask[final_offset] == im_offset) {\n gradient += top_diff[final_offset];\n }\n } else {\n if (top_mask[final_offset] == im_offset) {\n gradient += top_diff[final_offset];\n }\n }\n\n incremented = false;\n for (i = num_axes - 1; i >= 0; --i) {\n if (d_iter[i] > d_end[i] - dilation[i]) {\n d_iter[i] = d_start[i];\n } else {\n d_iter[i] += dilation[i];\n incremented = true;\n break;\n }\n }\n } while (incremented);\n bottom_diff[index] = gradient;\n }\n}"; // NOLINT +static std::string pooling_sk_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(max_pool_forward_sk,Dtype)(const int_tp nthreads,\n__global Dtype* bottom_data,\n const int_tp num,\n const int_tp channels,\n const int_tp height,\n const int_tp width,\n const int_tp pooled_height,\n const int_tp pooled_width,\n const int_tp kernel_h,\n const int_tp kernel_w,\n const int_tp ext_kernel_h,\n const int_tp ext_kernel_w,\n const int_tp stride_h,\n const int_tp stride_w,\n const int_tp dilation_h,\n const int_tp dilation_w,\n const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* top_data,\n const int use_mask,\n __global int_tp* mask,\n __global Dtype* top_mask) {\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + ext_kernel_h, height);\n int_tp wend = min(wstart + ext_kernel_w, width);\n hstart = max(hstart, (int_tp) 0);\n wstart = max(wstart, (int_tp) 0);\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n __global Dtype* bottom_data_ptr = bottom_data\n + (n * channels + c) * height * width;\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n if (bottom_data_ptr[h * width + w] > maxval) {\n maxidx = h * width + w;\n maxval = bottom_data_ptr[maxidx];\n }\n }\n }\n top_data[index] = maxval;\n if (use_mask == 1) {\n mask[index] = maxidx;\n } else {\n top_mask[index] = maxidx;\n }\n }\n}\n\n__kernel void TEMPLATE(max_pool_backward_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* top_diff, const int use_mask,\n __global const int_tp* mask, __global const Dtype* top_mask,\n const int_tp num, const int_tp channels, const int_tp height,\n const int_tp width, const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w, const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* bottom_diff) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n\n __global const int_tp* mask_ptr = mask;\n __global const Dtype* top_diff_ptr = top_diff;\n\n// find out the local index\n// find out the local offset\n int_tp w = index % width;\n int_tp h = (index / width) % height;\n int_tp c = (index / width / height) % channels;\n int_tp n = index / width / height / channels;\n\n int_tp pooled_height_1 = pooled_height - 1;\n int_tp pooled_width_1 = pooled_width - 1;\n int_tp phstart =\n (h < ext_kernel_h) ? h % dilation_h : (h - ext_kernel_h) + 1;\n int_tp phend =\n (h >= pooled_height) ?\n pooled_height_1 - (pooled_height_1 - phstart) % dilation_h : h;\n int_tp pwstart =\n (w < ext_kernel_w) ? w % dilation_w : (w - ext_kernel_w) + 1;\n int_tp pwend =\n (w >= pooled_width) ?\n pooled_width_1 - (pooled_width_1 - pwstart) % dilation_w : w;\n\n Dtype gradient = 0;\n int_tp offset = (n * channels + c) * pooled_height * pooled_width;\n top_diff_ptr += offset;\n if (use_mask == 1) {\n mask_ptr += offset;\n for (int_tp ph = phstart; ph <= phend; ph += dilation_h) {\n for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) {\n if (mask_ptr[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_ptr[ph * pooled_width + pw];\n }\n }\n }\n } else {\n for (int_tp ph = phstart; ph <= phend; ph += dilation_h) {\n for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) {\n if (top_mask[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_ptr[ph * pooled_width + pw];\n }\n }\n }\n }\n bottom_diff[index] = gradient;\n }\n}\n\n__kernel void TEMPLATE(ave_pool_forward_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w, const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* top_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + ext_kernel_h, height + pad_h);\n int_tp wend = min(wstart + ext_kernel_w, width + pad_w);\n hstart = max(hstart, (int_tp)0);\n wstart = max(wstart, (int_tp)0);\n hend = min(hend, height);\n wend = min(wend, width);\n Dtype aveval = 0;\n __global const Dtype* bottom_data_ptr = bottom_data;\n bottom_data_ptr += (n * channels + c) * height * width;\n int_tp pool_size = 0;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n aveval += bottom_data_ptr[h * width + w];\n ++pool_size;\n }\n }\n top_data[index] = aveval / pool_size;\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_train_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w, __global Dtype* rand_idx,\n __global Dtype* top_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h;\n int_tp hend = min(hstart + ext_kernel_h, height);\n int_tp wstart = pw * stride_w;\n int_tp wend = min(wstart + ext_kernel_w, width);\n Dtype cumsum = 0.;\n __global const Dtype* bottom_data_ptr = bottom_data;\n bottom_data_ptr += (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n cumsum += bottom_data_ptr[h * width + w];\n }\n }\n float thres = rand_idx[index] * cumsum;\n // Second pass: get value, and set index.\n cumsum = 0;\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n cumsum += bottom_data_ptr[h * width + w];\n if (cumsum >= thres) {\n rand_idx[index] = ((n * channels + c) * height + h) * width + w;\n top_data[index] = bottom_data_ptr[h * width + w];\n h = hend;\n w = wend;\n }\n }\n }\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_test_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w,\n __global Dtype* top_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h;\n int_tp hend = min(hstart + ext_kernel_h, height);\n int_tp wstart = pw * stride_w;\n int_tp wend = min(wstart + ext_kernel_w, width);\n // We set cumsum to be 0 to avoid divide-by-zero problems\n Dtype cumsum = FLT_MIN;\n Dtype cumvalues = 0.;\n __global const Dtype* bottom_data_ptr = bottom_data;\n bottom_data_ptr += (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n cumsum += bottom_data_ptr[h * width + w];\n cumvalues += bottom_data_ptr[h * width + w]\n * bottom_data_ptr[h * width + w];\n }\n }\n top_data[index] = cumvalues / cumsum;\n }\n\n}"; // NOLINT +static std::string slice_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(slice,Dtype)(const int_tp nthreads,\n __global const Dtype* in_data,\n const int forward, const int_tp num_slices,\n const int_tp slice_size,\n const int_tp bottom_slice_axis,\n const int_tp top_slice_axis,\n const int_tp offset_slice_axis,\n __global Dtype* out_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp total_slice_size = slice_size * top_slice_axis;\n const int_tp slice_num = index / total_slice_size;\n const int_tp slice_index = index % total_slice_size;\n const int_tp bottom_index = slice_index\n + (slice_num * bottom_slice_axis + offset_slice_axis) * slice_size;\n if (forward == 1) {\n out_data[index] = in_data[bottom_index];\n } else {\n out_data[bottom_index] = in_data[index];\n }\n }\n}"; // NOLINT +static std::string softmax_loss_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(softmax_loss_forward,Dtype)(\n int_tp n, __global const Dtype* prob_data, __global const Dtype* label,\n __global Dtype* loss,\n const int_tp num, const int_tp dim, const int_tp spatial_dim,\n const int has_ignore_label_, const int_tp ignore_label_,\n __global Dtype* counts) {\n\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp n = index / spatial_dim;\n const int_tp s = index % spatial_dim;\n const int_tp label_value = (int_tp) (label[n * spatial_dim + s]);\n if (has_ignore_label_ == 1 && label_value == ignore_label_) {\n loss[index] = 0;\n counts[index] = 0;\n } else {\n loss[index] = -log((Dtype)(\n max((Dtype) (prob_data[n * dim + label_value * spatial_dim + s]),\n (Dtype) FLT_MIN)));\n counts[index] = 1;\n }\n }\n}\n\n__kernel void TEMPLATE(softmax_loss_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top,\n __global const Dtype* label,\n __global Dtype* bottom_diff,\n const int_tp num,\n const int_tp dim,\n const int_tp spatial_dim,\n const int has_ignore_label_,\n const int_tp ignore_label_,\n __global Dtype* counts) {\n\n const int_tp channels = dim / spatial_dim;\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n\n const int_tp n = index / spatial_dim;\n const int_tp s = index % spatial_dim;\n const int_tp label_value = (int_tp) (label[n * spatial_dim + s]);\n\n if (has_ignore_label_ == 1 && label_value == ignore_label_) {\n for (int_tp c = 0; c < channels; ++c) {\n bottom_diff[n * dim + c * spatial_dim + s] = 0;\n }\n counts[index] = 0;\n } else {\n bottom_diff[n * dim + label_value * spatial_dim + s] -= 1;\n counts[index] = 1;\n }\n }\n}"; // NOLINT +static std::string solvers_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(ada_delta_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n __global Dtype* h2,\n Dtype momentum,\n Dtype delta,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype hi = h[i] = momentum * h[i] + (1.0 - momentum) * gi * gi;\n gi = gi * sqrt((h2[i] + delta) / (hi + delta));\n h2[i] = momentum * h2[i] + (1.0 - momentum) * gi * gi;\n g[i] = local_rate * gi;\n }\n}\n\n__kernel void TEMPLATE(ada_grad_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype delta,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype hi = h[i] = h[i] + gi * gi;\n g[i] = local_rate * gi / (sqrt(hi) + delta);\n }\n}\n\n__kernel void TEMPLATE(adam_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* m,\n __global Dtype* v,\n Dtype beta1,\n Dtype beta2,\n Dtype eps_hat,\n Dtype corrected_local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype mi = m[i] = m[i] * beta1 + gi * (1 - beta1);\n Dtype vi = v[i] = v[i] * beta2 + gi * gi * (1 - beta2);\n g[i] = corrected_local_rate * mi / (sqrt(vi) + eps_hat);\n }\n}\n\n\n__kernel void TEMPLATE(nesterov_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype momentum,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype hi = h[i];\n Dtype hi_new = h[i] = momentum * hi + local_rate * g[i];\n g[i] = (1 + momentum) * hi_new - momentum * hi;\n }\n}\n\n__kernel void TEMPLATE(rms_prop_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype rms_decay,\n Dtype delta,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype hi = h[i] = rms_decay * h[i] + (1 - rms_decay) * gi * gi;\n g[i] = local_rate * g[i] / (sqrt(hi) + delta);\n }\n}\n\n__kernel void TEMPLATE(sgd_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype momentum,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n g[i] = h[i] = momentum * h[i] + local_rate * g[i];\n }\n}"; // NOLINT +static std::string tile_float = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n\n__kernel void TEMPLATE(tile,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data,\n const int_tp tile_size, const int_tp num_tiles,\n const int_tp bottom_tile_axis,\n __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp d = index % tile_size;\n const int_tp b = (index / tile_size / num_tiles) % bottom_tile_axis;\n const int_tp n = index / tile_size / num_tiles / bottom_tile_axis;\n const int_tp bottom_index = (n * bottom_tile_axis + b) * tile_size + d;\n top_data[index] = bottom_data[bottom_index];\n }\n}\n\n\n__kernel void TEMPLATE(tile_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int_tp tile_size,\n const int_tp num_tiles,\n const int_tp bottom_tile_axis,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp d = index % tile_size;\n const int_tp b = (index / tile_size) % bottom_tile_axis;\n const int_tp n = index / tile_size / bottom_tile_axis;\n bottom_diff[index] = 0;\n int_tp top_index = (n * num_tiles * bottom_tile_axis + b) * tile_size + d;\n for (int_tp t = 0; t < num_tiles; ++t) {\n bottom_diff[index] += top_diff[top_index];\n top_index += bottom_tile_axis * tile_size;\n }\n }\n}"; // NOLINT +static std::string activation_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(relu_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out,\n Dtype negative_slope) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] > 0 ? in[index] : in[index] * negative_slope;\n }\n}\n\n__kernel void TEMPLATE(relu_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff,\n Dtype negative_slope) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] = in_diff[index]\n * ((in_data[index] > 0?1.0:0.0) + (in_data[index] <= 0?1.0:0.0) * negative_slope);\n }\n}\n\n__kernel void TEMPLATE(tanh_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = tanh(in[index]);\n }\n}\n\n__kernel void TEMPLATE(tanh_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* out_data,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n Dtype tanhx = out_data[index];\n out_diff[index] = in_diff[index] * (1 - tanhx * tanhx);\n }\n}\n\n__kernel void TEMPLATE(sigmoid_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = 1.0 / (1.0 + exp(-in[index]));\n }\n}\n\n__kernel void TEMPLATE(sigmoid_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* out_data,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n const Dtype sigmoid_x = out_data[index];\n out_diff[index] = in_diff[index] * sigmoid_x * (1 - sigmoid_x);\n }\n}\n\n__kernel void TEMPLATE(threshold,Dtype)(const int_tp n, const Dtype threshold,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] > threshold ? 1.0 : 0.0;\n }\n}\n\n__kernel void TEMPLATE(prelu_forward,Dtype)(const int_tp n, const int_tp channels,\n const int_tp dim,\n __global const Dtype* in,\n __global Dtype* out,\n __global const Dtype* slope_data,\n const int_tp div_factor) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n int_tp c = (index / dim) % channels / div_factor;\n out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[c];\n }\n}\n\n__kernel void TEMPLATE(prelu_backward,Dtype)(const int_tp n, const int_tp channels,\n const int_tp dim,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff,\n __global const Dtype* slope_data,\n const int_tp div_factor) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n int_tp c = (index / dim) % channels / div_factor;\n out_diff[index] = in_diff[index]\n * ((in_data[index] > 0?1.0:0.0) + (in_data[index] <= 0?1.0:0.0) * slope_data[c]);\n }\n}\n\n__kernel void TEMPLATE(prelu_param_backward,Dtype)(const int_tp n, const int_tp rows,\n const int_tp rowPitch,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] = in_diff[index] * in_data[index] * (in_data[index] <= 0?1.0:0.0);\n for (int k = 1; k < rows; k++) {\n out_diff[index] += in_diff[index + k * rowPitch]\n * in_data[index + k * rowPitch]\n * (in_data[index + k * rowPitch] <= 0?1.0:0.0);\n }\n }\n}"; // NOLINT +static std::string auxiliary_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(gpu_set,Dtype)(const int_tp n, const Dtype alpha, __global Dtype* y) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index] = alpha;\n }\n}"; // NOLINT +static std::string batch_reindex_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(br_forward,Dtype)(const int_tp count, const int_tp inner_dim,\n __global const Dtype* in,\n __global const Dtype* permut,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / (inner_dim);\n int_tp in_n = (int_tp) (permut[n]);\n out[index] = in[in_n * (inner_dim) + index % (inner_dim)];\n }\n}\n\n__kernel void TEMPLATE(br_backward,Dtype)(const int_tp count, const int_tp inner_dim,\n __global const Dtype* in,\n __global const Dtype* top_indexes,\n __global const Dtype* begins,\n __global const Dtype* counts,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / (inner_dim);\n out[index] = 0;\n int_tp lower = (int_tp) (begins[n]);\n int_tp upper = lower + (int_tp) (counts[n]);\n for (int_tp i = lower; i < upper; ++i) {\n int_tp in_n = (int_tp) (top_indexes[i]);\n out[index] += in[in_n * (inner_dim) + index % (inner_dim)];\n }\n }\n}"; // NOLINT +static std::string bias_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(bias_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const Dtype* bias,\n const int_tp bias_dim,\n const int_tp inner_dim,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp bias_index = (index / inner_dim) % bias_dim;\n out[index] = in[index] + bias[bias_index];\n }\n}\n\n__kernel void TEMPLATE(scale_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const Dtype* scale,\n const int_tp scale_dim,\n const int_tp inner_dim,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp scale_index = (index / inner_dim) % scale_dim;\n out[index] = in[index] * scale[scale_index];\n }\n}\n\n__kernel void TEMPLATE(scale_bias_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const Dtype* scale,\n __global const Dtype* bias,\n const int_tp scale_dim,\n const int_tp inner_dim,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp scale_index = (index / inner_dim) % scale_dim;\n out[index] = in[index] * scale[scale_index] + bias[scale_index];\n }\n}"; // NOLINT +static std::string bnll_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(bnll_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n if (in[index] > 0.0f) {\n out[index] = in[index] + log((Dtype) (1.0 + exp(-in[index])));\n } else {\n out[index] = log((Dtype) (1.0 + exp(in[index])));\n }\n }\n}\n\n__kernel void TEMPLATE(bnll_backward,Dtype)(const int_tp n,\n __global const Dtype* in_diff,\n __global const Dtype* in_data,\n __global Dtype* out_diff) {\n Dtype kBNLL_THRESHOLD = 50.;\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n Dtype expval = exp(min(in_data[index], kBNLL_THRESHOLD));\n out_diff[index] = in_diff[index] * expval / (expval + 1.);\n }\n}"; // NOLINT +static std::string channel_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(kernel_channel_max,Dtype)(const int_tp num, const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* data,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < num * spatial_dim; index +=\n get_global_size(0)) {\n int_tp n = index / spatial_dim;\n int_tp s = index % spatial_dim;\n float maxval = -FLT_MAX;\n for (int_tp c = 0; c < channels; ++c) {\n maxval = max((Dtype)(data[(n * channels + c) * spatial_dim + s]), (Dtype)maxval);\n }\n out[index] = maxval;\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_subtract,Dtype)(const int_tp count, const int_tp num,\n const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* channel_max,\n __global Dtype* data) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / channels / spatial_dim;\n int_tp s = index % spatial_dim;\n data[index] -= channel_max[n * spatial_dim + s];\n }\n}\n\n__kernel void TEMPLATE(kernel_exp,Dtype)(const int_tp count, __global const Dtype* data,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n out[index] = exp(data[index]);\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_sum,Dtype)(const int_tp num, const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* data,\n __global Dtype* channel_sum) {\n for (int_tp index = get_global_id(0); index < num * spatial_dim; index +=\n get_global_size(0)) {\n int_tp n = index / spatial_dim;\n int_tp s = index % spatial_dim;\n Dtype sum = 0;\n for (int_tp c = 0; c < channels; ++c) {\n sum += data[(n * channels + c) * spatial_dim + s];\n }\n channel_sum[index] = sum;\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_div,Dtype)(const int_tp count, const int_tp num,\n const int_tp channels, const int_tp spatial_dim,\n __global const Dtype* channel_sum,\n __global Dtype* data) {\n for (int_tp index = get_global_id(0); index < count;\n index += get_global_size(0)) {\n int_tp n = index / channels / spatial_dim;\n int_tp s = index % spatial_dim;\n data[index] /= channel_sum[n * spatial_dim + s];\n }\n}\n\n__kernel void TEMPLATE(kernel_channel_dot,Dtype)(const int_tp num, const int_tp channels,\n const int_tp spatial_dim,\n __global const Dtype* data_1,\n __global const Dtype* data_2,\n __global Dtype* channel_dot) {\n for (int_tp index = get_global_id(0); index < num * spatial_dim; index +=\n get_global_size(0)) {\n int_tp n = index / spatial_dim;\n int_tp s = index % spatial_dim;\n Dtype dot = 0;\n for (int_tp c = 0; c < channels; ++c) {\n dot += (data_1[(n * channels + c) * spatial_dim + s]\n * data_2[(n * channels + c) * spatial_dim + s]);\n }\n channel_dot[index] = dot;\n }\n}"; // NOLINT +static std::string concat_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(concat,Dtype)(const int_tp nthreads, __global const Dtype* in_data,\n const int forward, const int_tp num_concats,\n const int_tp concat_size,\n const int_tp top_concat_axis,\n const int_tp bottom_concat_axis,\n const int_tp offset_concat_axis,\n __global Dtype* out_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp total_concat_size = concat_size * bottom_concat_axis;\n const int_tp concat_num = index / total_concat_size;\n const int_tp concat_index = index % total_concat_size;\n const int_tp top_index = concat_index\n + (concat_num * top_concat_axis + offset_concat_axis) * concat_size;\n if (forward == 1) {\n out_data[top_index] = in_data[index];\n } else {\n out_data[index] = in_data[top_index];\n }\n }\n}"; // NOLINT +static std::string contrastive_loss_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(cll_backward,Dtype)(const int_tp count, const int_tp channels,\n const Dtype margin, const int legacy_version,\n const Dtype alpha, __global const Dtype* y,\n __global const Dtype* diff, __global const Dtype* dist_sq,\n __global Dtype *bottom_diff) {\n for (int_tp i = get_global_id(0); i < count;\n i += get_global_size(0)) {\n int_tp n = i / channels; // the num index, to access y and dist_sq\n if ((int_tp)(y[n])) { // similar pairs\n bottom_diff[i] = alpha * diff[i];\n } else { // dissimilar pairs\n Dtype mdist = 0.0;\n Dtype beta = 0.0;\n if (legacy_version == 1) {\n mdist = (margin - dist_sq[n]);\n beta = -alpha;\n } else {\n Dtype dist = sqrt(dist_sq[n]);\n mdist = (margin - dist);\n beta = -alpha * mdist / (dist + 1e-4) * diff[i];\n }\n if (mdist > 0.0) {\n bottom_diff[i] = beta;\n } else {\n bottom_diff[i] = 0;\n }\n }\n }\n}"; // NOLINT +static std::string dropout_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(dropout_forward,Dtype)(const int_tp n,\n __global const Dtype* in,\n __global const uint_tp* mask,\n const uint_tp threshold,\n const Dtype scale,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] * ((mask[index] > threshold)?1.0:0.0) * scale;\n }\n}\n\n__kernel void TEMPLATE(dropout_backward,Dtype)(\n const int_tp n, __global const Dtype* in_diff,\n __global const uint_tp* mask, const uint_tp threshold,\n const Dtype scale,\n __global Dtype* out_diff) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] = in_diff[index] * ((mask[index] > threshold)?1.0:0.0) * scale;\n }\n}"; // NOLINT +static std::string eltwise_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(eltwise_max_forward,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data_a,\n __global const Dtype* bottom_data_b, const int_tp blob_idx,\n __global Dtype* top_data,\n __global int_tp* mask) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n if (bottom_data_a[index] > bottom_data_b[index]) {\n // only update for very first bottom_data blob (blob_idx == 0)\n if (blob_idx == 0) {\n maxval = bottom_data_a[index];\n top_data[index] = maxval;\n maxidx = blob_idx;\n mask[index] = maxidx;\n }\n } else {\n maxval = bottom_data_b[index];\n top_data[index] = maxval;\n maxidx = blob_idx + 1;\n mask[index] = maxidx;\n }\n }\n}\n\n__kernel void TEMPLATE(eltwise_max_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int_tp blob_idx,\n __global const int_tp* mask,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n Dtype gradient = 0;\n if (mask[index] == blob_idx) {\n gradient += top_diff[index];\n }\n bottom_diff[index] = gradient;\n }\n}"; // NOLINT +static std::string elu_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(elu_forward,Dtype)(const int n, __global const Dtype* in,\n __global Dtype* out,\n Dtype alpha) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out[index] = in[index] > 0 ? in[index] : alpha * (exp(in[index]) - 1.0);\n }\n}\n\n__kernel void TEMPLATE(elu_backward,Dtype)(const int n, __global const Dtype* in_diff,\n __global const Dtype* out_data,\n __global const Dtype* in_data,\n __global Dtype* out_diff,\n Dtype alpha) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n out_diff[index] =\n in_data[index] > 0 ?\n in_diff[index] : in_diff[index] * (out_data[index] + alpha);\n }\n}"; // NOLINT +static std::string embed_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(embed_forward,Dtype)(const int_tp nthreads,\n __global const Dtype* bottom_data,\n __global const Dtype* weight,\n const int_tp M, const int_tp N,\n const int_tp K,\n __global Dtype* top_data) {\n for (int_tp top_index = get_global_id(0); top_index < nthreads;\n top_index += get_global_size(0)) {\n const int_tp n = top_index / N;\n const int_tp d = top_index % N;\n const int_tp index = (int_tp)(bottom_data[n]);\n const int_tp weight_index = index * N + d;\n top_data[top_index] = weight[weight_index];\n }\n }\n\n// atomic_add from: http://suhorukov.blogspot.com/2011/12/opencl-11-atomic-operations-on-floating.html\n#if (TYPE == TYPE_FLOAT)\ninline void TEMPLATE(atomic_add,Dtype)(volatile __global Dtype *source, const Dtype operand) {\n union {\n uint_tp intVal;\n Dtype floatVal;\n } newVal;\n union {\n uint_tp intVal;\n Dtype floatVal;\n } prevVal;\n do {\n prevVal.floatVal = *source;\n newVal.floatVal = prevVal.floatVal + operand;\n } while (atomic_cmpxchg((volatile __global unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);\n}\n\n__kernel void TEMPLATE(embed_backward,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data,\n __global const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K,\n __global Dtype* weight_diff) {\n for (int_tp top_index = get_global_id(0); top_index < nthreads;\n top_index += get_global_size(0)) {\n const int_tp n = top_index / N;\n const int_tp d = top_index % N;\n const int_tp index = (int_tp)(bottom_data[n]);\n const int_tp weight_index = index * N + d;\n\n TEMPLATE(atomic_add,Dtype)((weight_diff + weight_index), *(top_diff + top_index));\n }\n}\n#endif\n\n#if (TYPE == TYPE_DOUBLE)\n#ifdef ATOMICS_64_AVAILABLE\ninline void TEMPLATE(atomic_add,Dtype)(volatile __global Dtype *source, const Dtype operand) {\n union {\n unsigned long intVal;\n Dtype floatVal;\n } newVal;\n union {\n unsigned long intVal;\n Dtype floatVal;\n } prevVal;\n do {\n prevVal.floatVal = *source;\n newVal.floatVal = prevVal.floatVal + operand;\n } while (atom_cmpxchg((volatile __global unsigned long *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);\n}\n\n__kernel void TEMPLATE(embed_backward,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data,\n __global const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K,\n __global Dtype* weight_diff) {\n for (int_tp top_index = get_global_id(0); top_index < nthreads;\n top_index += get_global_size(0)) {\n const int_tp n = top_index / N;\n const int_tp d = top_index % N;\n const int_tp index = (int_tp)(bottom_data[n]);\n const int_tp weight_index = index * N + d;\n\n TEMPLATE(atomic_add,Dtype)((weight_diff + weight_index), *(top_diff + top_index));\n }\n}\n#endif\n#endif"; // NOLINT +static std::string fillbuffer_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(fillbuffer,Dtype)(const int_tp n, const char alpha, __global char* x,\n const int_tp offx) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n x[index + offx] = alpha;\n }\n}\n\n__kernel void TEMPLATE(fill,Dtype)(const int_tp n, const Dtype alpha, __global Dtype* x,\n const int_tp offx) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n x[index + offx] = alpha;\n }\n}"; // NOLINT +static std::string im2col_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(im2col,Dtype)(const int_tp n,\n __global const Dtype* data_im,\n const int_tp data_im_off,\n const int_tp height, const int_tp width,\n const int_tp kernel_h,\n const int_tp kernel_w, const int_tp pad_h,\n const int_tp pad_w, const int_tp stride_h,\n const int_tp stride_w,\n const int_tp dilation_h,\n const int_tp dilation_w,\n const int_tp height_col,\n const int_tp width_col,\n __global Dtype* data_col,\n const int_tp data_col_off) {\n\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp h_index = index / width_col;\n const int_tp h_col = h_index % height_col;\n const int_tp w_col = index % width_col;\n const int_tp c_im = h_index / height_col;\n const int_tp c_col = c_im * kernel_h * kernel_w;\n const int_tp h_offset = h_col * stride_h - pad_h;\n const int_tp w_offset = w_col * stride_w - pad_w;\n __global Dtype* data_col_ptr = data_col + data_col_off;\n data_col_ptr += (c_col * height_col + h_col) * width_col + w_col;\n __global const Dtype* data_im_ptr = data_im + data_im_off;\n data_im_ptr += (c_im * height + h_offset) * width + w_offset;\n for (int_tp i = 0; i < kernel_h; ++i) {\n for (int_tp j = 0; j < kernel_w; ++j) {\n int_tp h_im = h_offset + i * dilation_h;\n int_tp w_im = w_offset + j * dilation_w;\n *data_col_ptr =\n (h_im >= 0 && w_im >= 0 && h_im < height && w_im < width) ?\n data_im_ptr[i * dilation_h * width + j * dilation_w] : 0;\n data_col_ptr += height_col * width_col;\n }\n }\n }\n}\n\n__kernel void TEMPLATE(col2im,Dtype)(const int_tp n,\n __global const Dtype* data_col,\n const int_tp data_col_off,\n const int_tp height, const int_tp width,\n const int_tp channels,\n const int_tp kernel_h,\n const int_tp kernel_w, const int_tp pad_h,\n const int_tp pad_w, const int_tp stride_h,\n const int_tp stride_w,\n const int_tp dilation_h,\n const int_tp dilation_w,\n const int_tp height_col,\n const int_tp width_col,\n __global Dtype* data_im,\n const int_tp data_im_off) {\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n Dtype val = 0;\n const int_tp w_im = index % width + pad_w;\n const int_tp h_im = (index / width) % height + pad_h;\n const int_tp c_im = index / (width * height);\n int_tp kernel_extent_w = (kernel_w - 1) * dilation_w + 1;\n int_tp kernel_extent_h = (kernel_h - 1) * dilation_h + 1;\n // compute the start and end of the output\n const int_tp w_col_start =\n (w_im < kernel_extent_w) ? 0 : (w_im - kernel_extent_w) / stride_w + 1;\n const int_tp w_col_end = min(w_im / stride_w + 1, width_col);\n const int_tp h_col_start =\n (h_im < kernel_extent_h) ? 0 : (h_im - kernel_extent_h) / stride_h + 1;\n const int_tp h_col_end = min(h_im / stride_h + 1, height_col);\n // TODO: use LCM of stride and dilation to avoid unnecessary loops\n for (int_tp h_col = h_col_start; h_col < h_col_end; h_col += 1) {\n for (int_tp w_col = w_col_start; w_col < w_col_end; w_col += 1) {\n int_tp h_k = (h_im - h_col * stride_h);\n int_tp w_k = (w_im - w_col * stride_w);\n if (h_k % dilation_h == 0 && w_k % dilation_w == 0) {\n h_k /= dilation_h;\n w_k /= dilation_w;\n int_tp data_col_index = (((c_im * kernel_h + h_k) * kernel_w + w_k) *\n height_col + h_col) * width_col + w_col;\n val += data_col[data_col_off + data_col_index];\n }\n }\n }\n data_im[data_im_off + index] = val;\n }\n}"; // NOLINT +static std::string im2col_nd_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(im2col_nd, Dtype)(const int_tp n, const int_tp num_axes,\n const int_tp channel_axis,\n __global const Dtype* data_im,\n const int_tp data_im_off,\n __global const int_tp* im_shape,\n __global const int_tp* col_shape,\n __global const int_tp* kernel_shape,\n __global const int_tp* pad,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global Dtype* data_col,\n const int_tp data_col_off) {\n int_tp d_temp[6];\n int_tp d_iter[6];\n int_tp i;\n\n __global const int_tp* im_shape_ptr = im_shape + channel_axis;\n __global const int_tp* col_shape_ptr = col_shape + channel_axis;\n\n __local int_tp shared_dilation[6];\n __local int_tp shared_kernel_shape[6];\n __local int_tp shared_pad[6];\n __local int_tp shared_stride[6];\n __local int_tp shared_col_shape[6 + 1];\n __local int_tp shared_im_shape[6 + 1];\n\n for (int li = get_local_id(0); li < num_axes; li += get_local_size(0)) {\n shared_dilation[li] = dilation[li];\n shared_kernel_shape[li] = kernel_shape[li];\n shared_pad[li] = pad[li];\n shared_stride[li] = stride[li];\n }\n\n for (int li = get_local_id(0); li < num_axes + 1; li += get_local_size(0)) {\n shared_col_shape[li] = col_shape_ptr[li];\n shared_im_shape[li] = im_shape_ptr[li];\n }\n\n barrier(CLK_LOCAL_MEM_FENCE);\n\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n // Initialize channel_in, computed in the loop below, with int_tpermediate\n // computations used to compute the spatial indices.\n int_tp channel_in = index;\n int_tp channel_out = 1;\n for (i = num_axes - 1; i >= 0; --i) {\n d_temp[i] = channel_in % shared_col_shape[i + 1];\n channel_in /= shared_col_shape[i + 1];\n channel_out *= shared_kernel_shape[i];\n }\n channel_out *= channel_in;\n int_tp data_col_inc = 1;\n for (i = 0; i < num_axes; ++i) {\n channel_out *= shared_col_shape[i + 1];\n channel_out += d_temp[i];\n d_temp[i] = d_temp[i] * shared_stride[i] - shared_pad[i];\n channel_in *= shared_im_shape[i + 1];\n channel_in += d_temp[i];\n data_col_inc *= shared_col_shape[i + 1];\n d_iter[i] = 0;\n }\n __global Dtype* data_col_ptr = data_col + data_col_off + channel_out;\n __global const Dtype* data_im_ptr = data_im + data_im_off + channel_in;\n bool incremented;\n do {\n bool in_range = true;\n for (i = 0; i < num_axes; ++i) {\n const int_tp d_iter_im = d_iter[i] * shared_dilation[i] + d_temp[i];\n in_range &= d_iter_im >= 0 && d_iter_im < shared_im_shape[i + 1];\n if (!in_range) {\n break;\n }\n }\n if (in_range) {\n int_tp data_im_offset = d_iter[0] * shared_dilation[0];\n for (i = 1; i < num_axes; ++i) {\n data_im_offset *= shared_im_shape[i + 1];\n data_im_offset += d_iter[i] * shared_dilation[i];\n }\n *data_col_ptr = data_im_ptr[data_im_offset];\n } else {\n *data_col_ptr = 0;\n }\n data_col_ptr += data_col_inc;\n incremented = false;\n for (i = num_axes - 1; i >= 0; --i) {\n const int_tp d_max = shared_kernel_shape[i];\n if (d_iter[i] == d_max - 1) {\n d_iter[i] = 0;\n } else { // d_iter[i] < d_max - 1\n ++d_iter[i];\n incremented = true;\n break;\n }\n } // for (int_tp i = num_axes - 1; i >= 0; --i)\n } while (incremented); // do\n }\n}\n\n__kernel void TEMPLATE(col2im_nd, Dtype)(const int_tp n, const int_tp num_axes,\n const int_tp channel_axis,\n __global const Dtype* data_col,\n const int_tp data_col_off,\n __global const int_tp* im_shape,\n __global const int_tp* col_shape,\n __global const int_tp* kernel_shape,\n __global const int_tp* pad,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global Dtype* data_im,\n const int_tp data_im_off) {\n int_tp d_im[6];\n int_tp d_col_iter[6];\n int_tp d_col_start[6];\n int_tp d_col_end[6];\n\n __global const int_tp* im_shape_ptr = im_shape + channel_axis;\n __global const int_tp* col_shape_ptr = col_shape + channel_axis;\n\n __local int_tp shared_dilation[6];\n __local int_tp shared_kernel_shape[6];\n __local int_tp shared_pad[6];\n __local int_tp shared_stride[6];\n __local int_tp shared_col_shape[6 + 1];\n __local int_tp shared_im_shape[6 + 1];\n\n for (int li = get_local_id(0); li < num_axes; li += get_local_size(0)) {\n shared_dilation[li] = dilation[li];\n shared_kernel_shape[li] = kernel_shape[li];\n shared_pad[li] = pad[li];\n shared_stride[li] = stride[li];\n }\n for (int li = get_local_id(0); li < num_axes + 1; li += get_local_size(0)) {\n shared_col_shape[li] = col_shape_ptr[li];\n shared_im_shape[li] = im_shape_ptr[li];\n }\n\n barrier(CLK_LOCAL_MEM_FENCE);\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n // Initialize channel_in, computed in the loop below, with intermediate\n // computations used to compute the spatial indices.\n int_tp c_im = index;\n // Calculate d_im (image dimensions).\n for (int_tp i = num_axes - 1; i >= 0; --i) {\n d_im[i] = c_im % shared_im_shape[i + 1] + shared_pad[i];\n c_im /= shared_im_shape[i + 1];\n }\n // Calculate col start/end indices.\n bool done = false;\n for (int_tp i = 0; i < num_axes; ++i) {\n const int_tp kernel_extent = shared_dilation[i]\n * (shared_kernel_shape[i] - 1) + 1;\n d_col_start[i] = d_col_iter[i] =\n (d_im[i] < kernel_extent) ?\n 0 : (d_im[i] - kernel_extent) / shared_stride[i] + 1;\n d_col_end[i] = min(d_im[i] / shared_stride[i] + 1,\n shared_col_shape[i + 1]);\n if (d_col_start[i] >= d_col_end[i]) {\n // Skip computation if the dimension is 0 at any spatial axis --\n // final val will be 0.\n data_im[index] = 0;\n done = true;\n break; // for (int_tp i = 0; i < num_axes; ++i)\n }\n }\n if (!done) {\n // Loop over the col to compute the output val.\n Dtype val = 0;\n bool incremented = true;\n bool skip = false;\n do {\n // Compute the final offset.\n int_tp final_offset = 0;\n int_tp kernel_shape_prod = 1;\n int_tp kernel_index;\n for (int_tp i = num_axes - 1; i >= 0; --i) {\n kernel_index = d_im[i] - d_col_iter[i] * shared_stride[i];\n if (kernel_index % shared_dilation[i]) {\n skip = true;\n break;\n } else {\n kernel_index /= shared_dilation[i];\n final_offset += kernel_index * kernel_shape_prod;\n kernel_shape_prod *= shared_kernel_shape[i];\n }\n }\n if (!skip) {\n final_offset += kernel_shape_prod * c_im;\n for (int_tp i = 0; i < num_axes; ++i) {\n final_offset *= shared_col_shape[i + 1];\n final_offset += d_col_iter[i];\n }\n val += data_col[data_col_off + final_offset];\n }\n skip = false;\n incremented = false;\n for (int_tp i = num_axes - 1; i >= 0; --i) {\n const int_tp d_max = d_col_end[i];\n if (d_col_iter[i] == d_max - 1) {\n d_col_iter[i] = d_col_start[i];\n } else { // d_col_iter[i] < d_max - 1\n ++d_col_iter[i];\n incremented = true;\n break; // for (int_tp i = num_axes - 1; i >= 0; --i)\n }\n } // for (int_tp i = num_axes - 1; i >= 0; --i)\n } while (incremented);\n data_im[data_im_off + index] = val;\n }\n }\n}"; // NOLINT +static std::string lrn_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(lrn_compute_output,Dtype)(const int_tp nthreads,\n __global const Dtype* in,\n __global const Dtype* scale,\n const Dtype negative_beta,\n __global Dtype* out) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n out[index] = in[index] * pow(scale[index], negative_beta);\n }\n}\n\n__kernel void TEMPLATE(lrn_fill_scale,Dtype)(const int_tp nthreads, __global const Dtype* in,\n const int_tp num, const int_tp channels,\n const int_tp height, const int_tp width, const int_tp size,\n const Dtype alpha_over_size, const Dtype k,\n __global Dtype* const scale) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp n = index / width / height;\n const int_tp offset = (n * channels * height + h) * width + w;\n const int_tp step = height * width;\n __global const Dtype* in_off = in + offset;\n __global Dtype* scale_off = scale + offset;\n int_tp head = 0;\n const int_tp pre_pad = (size - 1) / 2;\n const int_tp post_pad = size - pre_pad - 1;\n Dtype accum_scale = 0;\n // fill the scale at [n, :, h, w]\n // accumulate values\n while (head < post_pad && head < channels) {\n accum_scale += in_off[head * step] * in_off[head * step];\n ++head;\n }\n // both add and subtract\n while (head < channels) {\n accum_scale += in_off[head * step] * in_off[head * step];\n if (head - size >= 0) {\n accum_scale -= in_off[(head - size) * step]\n * in_off[(head - size) * step];\n }\n scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size;\n ++head;\n }\n // subtract only\n while (head < channels + post_pad) {\n if (head - size >= 0) {\n accum_scale -= in_off[(head - size) * step]\n * in_off[(head - size) * step];\n }\n scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size;\n ++head;\n }\n }\n}\n\n__kernel void TEMPLATE(lrn_compute_diff,Dtype)(const int_tp nthreads,\n __global const Dtype* bottom_data,\n __global const Dtype* top_data,\n __global const Dtype* scale,\n __global const Dtype* top_diff, const int_tp num,\n const int_tp channels, const int_tp height,\n const int_tp width, const int_tp size,\n const Dtype negative_beta,\n const Dtype cache_ratio,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp n = index / width / height;\n const int_tp offset = (n * channels * height + h) * width + w;\n const int_tp step = height * width;\n __global const Dtype* bottom_off = bottom_data + offset;\n __global const Dtype* top_off = top_data + offset;\n __global const Dtype* scale_off = scale + offset;\n __global const Dtype* top_diff_off = top_diff + offset;\n __global Dtype* bottom_diff_off = bottom_diff + offset;\n int_tp head = 0;\n const int_tp pre_pad = size - (size + 1) / 2;\n const int_tp post_pad = size - pre_pad - 1;\n Dtype accum_ratio = 0;\n // accumulate values\n while (head < post_pad && head < channels) {\n accum_ratio += top_diff_off[head * step] * top_off[head * step]\n / scale_off[head * step];\n ++head;\n }\n // both add and subtract\n while (head < channels) {\n accum_ratio += top_diff_off[head * step] * top_off[head * step]\n / scale_off[head * step];\n if (head - size >= 0) {\n accum_ratio -= top_diff_off[(head - size) * step]\n * top_off[(head - size) * step] / scale_off[(head - size) * step];\n }\n bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad)\n * step] * pow(scale_off[(head - post_pad) * step], negative_beta)\n - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio;\n ++head;\n }\n // subtract only\n while (head < channels + post_pad) {\n if (head - size >= 0) {\n accum_ratio -= top_diff_off[(head - size) * step]\n * top_off[(head - size) * step] / scale_off[(head - size) * step];\n }\n bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad)\n * step] * pow(scale_off[(head - post_pad) * step], negative_beta)\n - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio;\n ++head;\n }\n }\n}"; // NOLINT +static std::string math_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(mul,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa,\n __global Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = a[index + offa] * b[index + offb];\n }\n}\n\n__kernel void TEMPLATE(div,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa,\n __global Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = a[index + offa] / b[index + offb];\n }\n}\n\n__kernel void TEMPLATE(add_scalar,Dtype)(const int_tp N, const Dtype alpha,\n__global Dtype* Y,\n const int_tp offY) {\n for (int_tp index = get_global_id(0); index < N; index += get_global_size(0)) {\n Y[offY + index] += alpha;\n }\n}\n\n__kernel void TEMPLATE(add,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global const Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = a[offa + index] + b[offb + index];\n }\n}\n\n__kernel void TEMPLATE(sub,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global const Dtype* b,\n const int_tp offb, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = a[offa + index] - b[offb + index];\n }\n}\n\n__kernel void TEMPLATE(abs,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = fabs((Dtype)(a[offa + index]));\n }\n}\n\n__kernel void TEMPLATE(exp,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = exp(a[offa + index]);\n }\n}\n\n__kernel void TEMPLATE(log,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[offy + index] = log((Dtype)(a[offa + index]));\n }\n}\n\n__kernel void TEMPLATE(powx,Dtype)(const int_tp n, __global const Dtype* a,\n const int_tp offa, Dtype alpha,\n __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n if(alpha == 2.0) {\n y[offy + index] = pow((Dtype)fabs(a[offa + index]), (Dtype)alpha);\n } else {\n y[offy + index] = pow((Dtype)a[offa + index], (Dtype)alpha);\n }\n }\n}\n\n__kernel void TEMPLATE(sign,Dtype)(const int_tp n, __global const Dtype* x,\n const int_tp offx, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = (0.0 < x[index + offx])\n - (x[index + offx] < 0.0);\n }\n}\n\n__kernel void TEMPLATE(sgnbit,Dtype)(const int_tp n, __global const Dtype* x,\n const int_tp offx, __global Dtype* y,\n const int_tp offy) {\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n y[index + offy] = signbit(x[index + offx]);\n }\n}"; // NOLINT +static std::string mergecrop_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(merge_copy_forward, Dtype)(const int_tp nthreads,\n const int_tp dims,\n __global const Dtype* bottom_a,\n const int_tp forward_a,\n __global const Dtype* bottom_b,\n const int_tp forward_b,\n __global Dtype* top,\n const int_tp num,\n const int_tp channels_a,\n const int_tp channels_b,\n __global const int_tp* shape_a,\n __global const int_tp* shape_b) {\n int_tp pad[6];\n int_tp tmp_idx[6];\n int_tp size_a = 1;\n int_tp size_b = 1;\n\n for (int_tp i = 0; i < dims; ++i) {\n pad[i] = (shape_b[i] - shape_a[i]) / 2;\n size_a *= shape_a[i];\n size_b *= shape_b[i];\n }\n\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n int_tp batch_id = index / ((channels_a + channels_b) * size_a);\n int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a)\n / (channels_a * size_a)) % 2;\n int_tp counter = index;\n for (int_tp i = dims - 1; i >= 0; --i) {\n tmp_idx[i] = counter % shape_a[i];\n counter /= shape_a[i];\n }\n\n if (bottom_id == 0) {\n int_tp channel_id = (index / size_a) % channels_a;\n int_tp aidx = batch_id * channels_a + channel_id;\n for (int_tp i = 0; i < dims; ++i) {\n aidx *= shape_a[i];\n aidx += tmp_idx[i];\n }\n top[index] = (forward_a == 1) ? bottom_a[aidx] : 0;\n } else {\n int_tp channel_id = (index / size_a) % channels_b;\n int_tp bidx = (batch_id * channels_b + channel_id) * size_b;\n int_tp btemp = 1;\n for (int_tp i = dims - 1; i >= 0; --i) {\n bidx += btemp * (tmp_idx[i] + pad[i]);\n btemp *= shape_b[i];\n }\n top[index] = (forward_b == 1) ? bottom_b[bidx] : 0;\n }\n }\n}\n\n__kernel void TEMPLATE(merge_copy_backward,Dtype)(const int_tp nthreads,\n const int_tp dims,\n __global Dtype* bottom_a,\n const int_tp backward_a,\n __global Dtype* bottom_b,\n const int_tp backward_b,\n __global const Dtype* top,\n const int_tp num,\n const int_tp channels_a,\n const int_tp channels_b,\n __global const int_tp* shape_a,\n __global const int_tp* shape_b) {\n int_tp pad[6];\n int_tp tmp_idx[6];\n int_tp size_a = 1;\n int_tp size_b = 1;\n\n for (int_tp i = 0; i < dims; ++i) {\n pad[i] = (shape_b[i] - shape_a[i]) / 2;\n size_a *= shape_a[i];\n size_b *= shape_b[i];\n }\n\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n int_tp batch_id = index / ((channels_a + channels_b) * size_a);\n int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a)\n / (channels_a * size_a)) % 2;\n int_tp counter = index;\n for (int_tp i = dims - 1; i >= 0; --i) {\n tmp_idx[i] = counter % shape_a[i];\n counter /= shape_a[i];\n }\n\n if (bottom_id == 0) {\n int_tp channel_id = (index / size_a) % channels_a;\n int_tp aidx = batch_id * channels_a + channel_id;\n for (int_tp i = 0; i < dims; ++i) {\n aidx *= shape_a[i];\n aidx += tmp_idx[i];\n }\n bottom_a[aidx] = (backward_a == 1) ? top[index] : 0;\n } else {\n int_tp channel_id = (index / size_a) % channels_b;\n int_tp bidx = (batch_id * channels_b + channel_id) * size_b;\n int_tp btemp = 1;\n for (int_tp i = dims - 1; i >= 0; --i) {\n bidx += btemp * (tmp_idx[i] + pad[i]);\n btemp *= shape_b[i];\n }\n bottom_b[bidx] = (backward_b == 1) ? top[index] : 0;\n }\n }\n}"; // NOLINT +static std::string pooling_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(max_pool_forward,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* top_data,\n const int use_mask, __global int_tp* mask, __global Dtype* top_mask) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n const int_tp hend = min(hstart + kernel_h, height);\n const int_tp wend = min(wstart + kernel_w, width);\n hstart = max(hstart, (int_tp)0);\n wstart = max(wstart, (int_tp)0);\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n if (bottom_slice[h * width + w] > maxval) {\n maxidx = h * width + w;\n maxval = bottom_slice[maxidx];\n }\n }\n }\n top_data[index] = maxval;\n if (use_mask == 1) {\n mask[index] = maxidx;\n } else {\n top_mask[index] = maxidx;\n }\n }\n}\n\n__kernel void TEMPLATE(ave_pool_forward,Dtype)(\n const int_tp nthreads, __global const Dtype* const bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, const int_tp pad_h,\n const int_tp pad_w, __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + kernel_h, height + pad_h);\n int_tp wend = min(wstart + kernel_w, width + pad_w);\n const int_tp pool_size = (hend - hstart) * (wend - wstart);\n hstart = max(hstart, (int_tp)0);\n wstart = max(wstart, (int_tp)0);\n hend = min(hend, height);\n wend = min(wend, width);\n Dtype aveval = 0;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n aveval += bottom_slice[h * width + w];\n }\n }\n top_data[index] = aveval / pool_size;\n }\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_train,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w,\n __global Dtype* rand_idx,\n __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n const int_tp hstart = ph * stride_h;\n const int_tp hend = min(hstart + kernel_h, height);\n const int_tp wstart = pw * stride_w;\n const int_tp wend = min(wstart + kernel_w, width);\n Dtype cumsum = 0.;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n cumsum += bottom_slice[h * width + w];\n }\n }\n const float thres = rand_idx[index] * cumsum;\n // Second pass: get value, and set index.\n cumsum = 0;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n cumsum += bottom_slice[h * width + w];\n if (cumsum >= thres) {\n rand_idx[index] = ((n * channels + c) * height + h) * width + w;\n top_data[index] = bottom_slice[h * width + w];\n h = hend;\n w = wend;\n }\n }\n }\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_test,Dtype)(\n const int_tp nthreads, __global const Dtype* const bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h,\n const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w,\n __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp pw = index % pooled_width;\n const int_tp ph = (index / pooled_width) % pooled_height;\n const int_tp c = (index / pooled_width / pooled_height) % channels;\n const int_tp n = index / pooled_width / pooled_height / channels;\n const int_tp hstart = ph * stride_h;\n const int_tp hend = min(hstart + kernel_h, height);\n const int_tp wstart = pw * stride_w;\n const int_tp wend = min(wstart + kernel_w, width);\n // We set cumsum to be 0 to avoid divide-by-zero problems\n Dtype cumsum = FLT_MIN;\n Dtype cumvalues = 0.;\n __global const Dtype* bottom_slice = bottom_data\n + (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n cumsum += bottom_slice[h * width + w];\n cumvalues += bottom_slice[h * width + w] * bottom_slice[h * width + w];\n }\n }\n top_data[index] = cumvalues / cumsum;\n }\n}\n\n__kernel void TEMPLATE(max_pool_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int use_mask,\n __global const int_tp* mask,\n __global const Dtype* top_mask,\n const int_tp num,\n const int_tp channels,\n const int_tp height,\n const int_tp width,\n const int_tp pooled_height,\n const int_tp pooled_width,\n const int_tp kernel_h,\n const int_tp kernel_w,\n const int_tp stride_h,\n const int_tp stride_w,\n const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local index\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp c = (index / width / height) % channels;\n const int_tp n = index / width / height / channels;\n const int_tp phstart =\n (h + pad_h < kernel_h) ? 0 : (h + pad_h - kernel_h) / stride_h + 1;\n const int_tp phend = min((h + pad_h) / stride_h + 1, pooled_height);\n const int_tp pwstart =\n (w + pad_w < kernel_w) ? 0 : (w + pad_w - kernel_w) / stride_w + 1;\n const int_tp pwend = min((w + pad_w) / stride_w + 1, pooled_width);\n Dtype gradient = 0;\n const int_tp offset = (n * channels + c) * pooled_height * pooled_width;\n __global const Dtype* top_diff_slice = top_diff + offset;\n if (use_mask == 1) {\n __global const int_tp* mask_slice = mask + offset;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n if (mask_slice[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_slice[ph * pooled_width + pw];\n }\n }\n }\n } else {\n __global const Dtype* top_mask_slice = top_mask + offset;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n if (top_mask_slice[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_slice[ph * pooled_width + pw];\n }\n }\n }\n }\n bottom_diff[index] = gradient;\n }\n}\n\n__kernel void TEMPLATE(ave_pool_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int_tp num,\n const int_tp channels,\n const int_tp height,\n const int_tp width,\n const int_tp pooled_height,\n const int_tp pooled_width,\n const int_tp kernel_h,\n const int_tp kernel_w,\n const int_tp stride_h,\n const int_tp stride_w,\n const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n // find out the local index\n // find out the local offset\n const int_tp w = index % width + pad_w;\n const int_tp h = (index / width) % height + pad_h;\n const int_tp c = (index / width / height) % channels;\n const int_tp n = index / width / height / channels;\n const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1;\n const int_tp phend = min(h / stride_h + 1, pooled_height);\n const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1;\n const int_tp pwend = min(w / stride_w + 1, pooled_width);\n Dtype gradient = 0.0;\n __global const Dtype* const top_diff_slice = top_diff\n + (n * channels + c) * pooled_height * pooled_width;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n // figure out the pooling size\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + kernel_h, height + pad_h);\n int_tp wend = min(wstart + kernel_w, width + pad_w);\n int_tp pool_size = (hend - hstart) * (wend - wstart);\n gradient += top_diff_slice[ph * pooled_width + pw] / pool_size;\n }\n }\n bottom_diff[index] = gradient;\n }\n}\n\n__kernel void TEMPLATE(sto_pool_backward,Dtype)(\n const int_tp nthreads, __global const Dtype* rand_idx,\n __global const Dtype* const top_diff, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp stride_h,\n const int_tp stride_w, __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n // find out the local index\n // find out the local offset\n const int_tp w = index % width;\n const int_tp h = (index / width) % height;\n const int_tp c = (index / width / height) % channels;\n const int_tp n = index / width / height / channels;\n const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1;\n const int_tp phend = min(h / stride_h + 1, pooled_height);\n const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1;\n const int_tp pwend = min(w / stride_w + 1, pooled_width);\n Dtype gradient = 0.0;\n __global const Dtype* rand_idx_slice = rand_idx\n + (n * channels + c) * pooled_height * pooled_width;\n __global const Dtype* top_diff_slice = top_diff\n + (n * channels + c) * pooled_height * pooled_width;\n for (int_tp ph = phstart; ph < phend; ++ph) {\n for (int_tp pw = pwstart; pw < pwend; ++pw) {\n gradient += top_diff_slice[ph * pooled_width + pw]\n * (index == (int_tp) (rand_idx_slice[ph * pooled_width + pw])?1.0:0.0);\n }\n }\n bottom_diff[index] = gradient;\n }\n}"; // NOLINT +static std::string pooling_nd_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(max_pool_forward_nd, Dtype)(const int_tp n,\n const int_tp num_axes,\n __global const Dtype* bottom_data,\n const int_tp channels,\n __global const int_tp* size,\n __global const int_tp* pooled_size,\n __global const int_tp* kernel_size,\n __global const int_tp* ext_kernel_size,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global const int_tp* pad,\n __global Dtype* top_data,\n const int use_mask,\n __global int_tp* mask, __global Dtype* top_mask) {\n int_tp d_idx[6];\n int_tp d_start[6];\n int_tp d_end[6];\n int_tp d_iter[6];\n int_tp i;\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n int_tp offset = 1;\n int_tp num = index;\n\n bool do_continue = false;\n\n for (i = num_axes - 1; i >= 0; --i) {\n d_idx[i] = num % pooled_size[i];\n d_start[i] = d_idx[i] * stride[i] - pad[i];\n d_end[i] = min(d_start[i] + ext_kernel_size[i], size[i]);\n d_start[i] = max(d_start[i], (int_tp)0);\n num /= pooled_size[i];\n offset *= size[i];\n d_iter[i] = d_start[i];\n\n if (d_start[i] >= d_end[i]) {\n top_data[index] = -FLT_MAX;\n if (use_mask) {\n mask[index] = -1;\n } else {\n top_mask[index] = -1;\n }\n do_continue = true;\n }\n }\n\n if(do_continue) {\n continue;\n }\n\n int_tp chan = num % channels;\n num /= channels;\n offset *= (num * channels + chan);\n\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n int_tp final_offset = 0;\n\n bool incremented;\n do {\n final_offset = offset;\n int_tp size_prod = 1;\n for (i = num_axes - 1; i >= 0; --i) {\n final_offset += d_iter[i] * size_prod;\n size_prod *= size[i];\n }\n\n if (bottom_data[final_offset] > maxval) {\n maxidx = final_offset;\n maxval = bottom_data[maxidx];\n }\n\n incremented = false;\n for (i = num_axes - 1; i >= 0; --i) {\n if (d_iter[i] >= d_end[i] - dilation[i]) {\n d_iter[i] = d_start[i];\n } else {\n d_iter[i] += dilation[i];\n incremented = true;\n break;\n }\n }\n } while (incremented);\n\n top_data[index] = maxval;\n if (use_mask == 1) {\n mask[index] = maxidx;\n } else {\n top_mask[index] = maxidx;\n }\n }\n}\n\n\n__kernel void TEMPLATE(max_pool_backward_nd, Dtype)(const int_tp n,\n const int_tp num_axes,\n __global const Dtype* top_diff,\n const int use_mask,\n __global const int_tp* mask,\n __global const Dtype* top_mask,\n const int_tp channels,\n __global const int_tp* size,\n __global const int_tp* pooled_size,\n __global const int_tp* kernel_size,\n __global const int_tp* ext_kernel_size,\n __global const int_tp* stride,\n __global const int_tp* dilation,\n __global const int_tp* pad,\n __global Dtype* bottom_diff) {\n int_tp d_idx[6];\n int_tp d_start[6];\n int_tp d_end[6];\n int_tp d_iter[6];\n int_tp i;\n\n for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) {\n // find out the local index\n // find out the local offset\n int_tp offset = 1;\n int_tp num = index;\n for (i = num_axes - 1; i >= 0; --i) {\n d_idx[i] = num % size[i];\n if (dilation[i] > 1) {\n d_start[i] =\n (d_idx[i] < ext_kernel_size[i]) ?\n d_idx[i] % dilation[i] : (d_idx[i] - ext_kernel_size[i]) + 1;\n d_end[i] =\n (d_idx[i] >= pooled_size[i]) ?\n (pooled_size[i] - 1)\n - (pooled_size[i] - 1 - d_start[i]) % dilation[i] :\n d_idx[i];\n } else {\n d_start[i] =\n (d_idx[i] + pad[i] < kernel_size[i]) ?\n 0 : (d_idx[i] + pad[i] - kernel_size[i]) / stride[i] + 1;\n d_end[i] = min((int_tp) ((d_idx[i] + pad[i]) / stride[i] + 1),\n (int_tp) (pooled_size[i]));\n }\n num /= size[i];\n offset *= pooled_size[i];\n d_iter[i] = d_start[i];\n\n if (d_start[i] > d_end[i]) {\n bottom_diff[index] = 0;\n return;\n }\n }\n int_tp chan = num % channels;\n num /= channels;\n offset *= (num * channels + chan);\n\n Dtype gradient = 0;\n int_tp final_offset = 0;\n int_tp im_offset = 0;\n\n bool incremented;\n do {\n final_offset = offset;\n im_offset = 0;\n int_tp size_prod = 1;\n int_tp pooled_size_prod = 1;\n for (i = num_axes - 1; i >= 0; --i) {\n final_offset += d_iter[i] * pooled_size_prod;\n im_offset += d_idx[i] * size_prod;\n size_prod *= size[i];\n pooled_size_prod *= pooled_size[i];\n }\n\n if (use_mask) {\n if (mask[final_offset] == im_offset) {\n gradient += top_diff[final_offset];\n }\n } else {\n if (top_mask[final_offset] == im_offset) {\n gradient += top_diff[final_offset];\n }\n }\n\n incremented = false;\n for (i = num_axes - 1; i >= 0; --i) {\n if (d_iter[i] > d_end[i] - dilation[i]) {\n d_iter[i] = d_start[i];\n } else {\n d_iter[i] += dilation[i];\n incremented = true;\n break;\n }\n }\n } while (incremented);\n bottom_diff[index] = gradient;\n }\n}"; // NOLINT +static std::string pooling_sk_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(max_pool_forward_sk,Dtype)(const int_tp nthreads,\n__global Dtype* bottom_data,\n const int_tp num,\n const int_tp channels,\n const int_tp height,\n const int_tp width,\n const int_tp pooled_height,\n const int_tp pooled_width,\n const int_tp kernel_h,\n const int_tp kernel_w,\n const int_tp ext_kernel_h,\n const int_tp ext_kernel_w,\n const int_tp stride_h,\n const int_tp stride_w,\n const int_tp dilation_h,\n const int_tp dilation_w,\n const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* top_data,\n const int use_mask,\n __global int_tp* mask,\n __global Dtype* top_mask) {\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + ext_kernel_h, height);\n int_tp wend = min(wstart + ext_kernel_w, width);\n hstart = max(hstart, (int_tp) 0);\n wstart = max(wstart, (int_tp) 0);\n Dtype maxval = -FLT_MAX;\n int_tp maxidx = -1;\n __global Dtype* bottom_data_ptr = bottom_data\n + (n * channels + c) * height * width;\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n if (bottom_data_ptr[h * width + w] > maxval) {\n maxidx = h * width + w;\n maxval = bottom_data_ptr[maxidx];\n }\n }\n }\n top_data[index] = maxval;\n if (use_mask == 1) {\n mask[index] = maxidx;\n } else {\n top_mask[index] = maxidx;\n }\n }\n}\n\n__kernel void TEMPLATE(max_pool_backward_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* top_diff, const int use_mask,\n __global const int_tp* mask, __global const Dtype* top_mask,\n const int_tp num, const int_tp channels, const int_tp height,\n const int_tp width, const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w, const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* bottom_diff) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n\n __global const int_tp* mask_ptr = mask;\n __global const Dtype* top_diff_ptr = top_diff;\n\n// find out the local index\n// find out the local offset\n int_tp w = index % width;\n int_tp h = (index / width) % height;\n int_tp c = (index / width / height) % channels;\n int_tp n = index / width / height / channels;\n\n int_tp pooled_height_1 = pooled_height - 1;\n int_tp pooled_width_1 = pooled_width - 1;\n int_tp phstart =\n (h < ext_kernel_h) ? h % dilation_h : (h - ext_kernel_h) + 1;\n int_tp phend =\n (h >= pooled_height) ?\n pooled_height_1 - (pooled_height_1 - phstart) % dilation_h : h;\n int_tp pwstart =\n (w < ext_kernel_w) ? w % dilation_w : (w - ext_kernel_w) + 1;\n int_tp pwend =\n (w >= pooled_width) ?\n pooled_width_1 - (pooled_width_1 - pwstart) % dilation_w : w;\n\n Dtype gradient = 0;\n int_tp offset = (n * channels + c) * pooled_height * pooled_width;\n top_diff_ptr += offset;\n if (use_mask == 1) {\n mask_ptr += offset;\n for (int_tp ph = phstart; ph <= phend; ph += dilation_h) {\n for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) {\n if (mask_ptr[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_ptr[ph * pooled_width + pw];\n }\n }\n }\n } else {\n for (int_tp ph = phstart; ph <= phend; ph += dilation_h) {\n for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) {\n if (top_mask[ph * pooled_width + pw] == h * width + w) {\n gradient += top_diff_ptr[ph * pooled_width + pw];\n }\n }\n }\n }\n bottom_diff[index] = gradient;\n }\n}\n\n__kernel void TEMPLATE(ave_pool_forward_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w, const int_tp pad_h,\n const int_tp pad_w,\n __global Dtype* top_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h - pad_h;\n int_tp wstart = pw * stride_w - pad_w;\n int_tp hend = min(hstart + ext_kernel_h, height + pad_h);\n int_tp wend = min(wstart + ext_kernel_w, width + pad_w);\n hstart = max(hstart, (int_tp)0);\n wstart = max(wstart, (int_tp)0);\n hend = min(hend, height);\n wend = min(wend, width);\n Dtype aveval = 0;\n __global const Dtype* bottom_data_ptr = bottom_data;\n bottom_data_ptr += (n * channels + c) * height * width;\n int_tp pool_size = 0;\n for (int_tp h = hstart; h < hend; ++h) {\n for (int_tp w = wstart; w < wend; ++w) {\n aveval += bottom_data_ptr[h * width + w];\n ++pool_size;\n }\n }\n top_data[index] = aveval / pool_size;\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_train_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w, __global Dtype* rand_idx,\n __global Dtype* top_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h;\n int_tp hend = min(hstart + ext_kernel_h, height);\n int_tp wstart = pw * stride_w;\n int_tp wend = min(wstart + ext_kernel_w, width);\n Dtype cumsum = 0.;\n __global const Dtype* bottom_data_ptr = bottom_data;\n bottom_data_ptr += (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n cumsum += bottom_data_ptr[h * width + w];\n }\n }\n float thres = rand_idx[index] * cumsum;\n // Second pass: get value, and set index.\n cumsum = 0;\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n cumsum += bottom_data_ptr[h * width + w];\n if (cumsum >= thres) {\n rand_idx[index] = ((n * channels + c) * height + h) * width + w;\n top_data[index] = bottom_data_ptr[h * width + w];\n h = hend;\n w = wend;\n }\n }\n }\n }\n}\n\n__kernel void TEMPLATE(sto_pool_forward_test_sk,Dtype)(\n const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num,\n const int_tp channels, const int_tp height, const int_tp width,\n const int_tp pooled_height, const int_tp pooled_width,\n const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h,\n const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w,\n const int_tp dilation_h, const int_tp dilation_w,\n __global Dtype* top_data) {\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n int_tp pw = index % pooled_width;\n int_tp ph = (index / pooled_width) % pooled_height;\n int_tp c = (index / pooled_width / pooled_height) % channels;\n int_tp n = index / pooled_width / pooled_height / channels;\n int_tp hstart = ph * stride_h;\n int_tp hend = min(hstart + ext_kernel_h, height);\n int_tp wstart = pw * stride_w;\n int_tp wend = min(wstart + ext_kernel_w, width);\n // We set cumsum to be 0 to avoid divide-by-zero problems\n Dtype cumsum = FLT_MIN;\n Dtype cumvalues = 0.;\n __global const Dtype* bottom_data_ptr = bottom_data;\n bottom_data_ptr += (n * channels + c) * height * width;\n // First pass: get sum\n for (int_tp h = hstart; h < hend; h += dilation_h) {\n for (int_tp w = wstart; w < wend; w += dilation_w) {\n cumsum += bottom_data_ptr[h * width + w];\n cumvalues += bottom_data_ptr[h * width + w]\n * bottom_data_ptr[h * width + w];\n }\n }\n top_data[index] = cumvalues / cumsum;\n }\n\n}"; // NOLINT +static std::string slice_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(slice,Dtype)(const int_tp nthreads,\n __global const Dtype* in_data,\n const int forward, const int_tp num_slices,\n const int_tp slice_size,\n const int_tp bottom_slice_axis,\n const int_tp top_slice_axis,\n const int_tp offset_slice_axis,\n __global Dtype* out_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp total_slice_size = slice_size * top_slice_axis;\n const int_tp slice_num = index / total_slice_size;\n const int_tp slice_index = index % total_slice_size;\n const int_tp bottom_index = slice_index\n + (slice_num * bottom_slice_axis + offset_slice_axis) * slice_size;\n if (forward == 1) {\n out_data[index] = in_data[bottom_index];\n } else {\n out_data[bottom_index] = in_data[index];\n }\n }\n}"; // NOLINT +static std::string softmax_loss_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(softmax_loss_forward,Dtype)(\n int_tp n, __global const Dtype* prob_data, __global const Dtype* label,\n __global Dtype* loss,\n const int_tp num, const int_tp dim, const int_tp spatial_dim,\n const int has_ignore_label_, const int_tp ignore_label_,\n __global Dtype* counts) {\n\n for (int_tp index = get_global_id(0); index < n;\n index += get_global_size(0)) {\n const int_tp n = index / spatial_dim;\n const int_tp s = index % spatial_dim;\n const int_tp label_value = (int_tp) (label[n * spatial_dim + s]);\n if (has_ignore_label_ == 1 && label_value == ignore_label_) {\n loss[index] = 0;\n counts[index] = 0;\n } else {\n loss[index] = -log((Dtype)(\n max((Dtype) (prob_data[n * dim + label_value * spatial_dim + s]),\n (Dtype) FLT_MIN)));\n counts[index] = 1;\n }\n }\n}\n\n__kernel void TEMPLATE(softmax_loss_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top,\n __global const Dtype* label,\n __global Dtype* bottom_diff,\n const int_tp num,\n const int_tp dim,\n const int_tp spatial_dim,\n const int has_ignore_label_,\n const int_tp ignore_label_,\n __global Dtype* counts) {\n\n const int_tp channels = dim / spatial_dim;\n\n for (int_tp index = get_global_id(0); index < nthreads; index +=\n get_global_size(0)) {\n\n const int_tp n = index / spatial_dim;\n const int_tp s = index % spatial_dim;\n const int_tp label_value = (int_tp) (label[n * spatial_dim + s]);\n\n if (has_ignore_label_ == 1 && label_value == ignore_label_) {\n for (int_tp c = 0; c < channels; ++c) {\n bottom_diff[n * dim + c * spatial_dim + s] = 0;\n }\n counts[index] = 0;\n } else {\n bottom_diff[n * dim + label_value * spatial_dim + s] -= 1;\n counts[index] = 1;\n }\n }\n}"; // NOLINT +static std::string solvers_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n__kernel void TEMPLATE(ada_delta_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n __global Dtype* h2,\n Dtype momentum,\n Dtype delta,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype hi = h[i] = momentum * h[i] + (1.0 - momentum) * gi * gi;\n gi = gi * sqrt((h2[i] + delta) / (hi + delta));\n h2[i] = momentum * h2[i] + (1.0 - momentum) * gi * gi;\n g[i] = local_rate * gi;\n }\n}\n\n__kernel void TEMPLATE(ada_grad_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype delta,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype hi = h[i] = h[i] + gi * gi;\n g[i] = local_rate * gi / (sqrt(hi) + delta);\n }\n}\n\n__kernel void TEMPLATE(adam_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* m,\n __global Dtype* v,\n Dtype beta1,\n Dtype beta2,\n Dtype eps_hat,\n Dtype corrected_local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype mi = m[i] = m[i] * beta1 + gi * (1 - beta1);\n Dtype vi = v[i] = v[i] * beta2 + gi * gi * (1 - beta2);\n g[i] = corrected_local_rate * mi / (sqrt(vi) + eps_hat);\n }\n}\n\n\n__kernel void TEMPLATE(nesterov_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype momentum,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype hi = h[i];\n Dtype hi_new = h[i] = momentum * hi + local_rate * g[i];\n g[i] = (1 + momentum) * hi_new - momentum * hi;\n }\n}\n\n__kernel void TEMPLATE(rms_prop_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype rms_decay,\n Dtype delta,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n Dtype gi = g[i];\n Dtype hi = h[i] = rms_decay * h[i] + (1 - rms_decay) * gi * gi;\n g[i] = local_rate * g[i] / (sqrt(hi) + delta);\n }\n}\n\n__kernel void TEMPLATE(sgd_update,Dtype)(int_tp N, __global Dtype* g,\n __global Dtype* h,\n Dtype momentum,\n Dtype local_rate) {\n for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) {\n g[i] = h[i] = momentum * h[i] + local_rate * g[i];\n }\n}"; // NOLINT +static std::string tile_double = "#ifndef __OPENCL_VERSION__\n#include \"header.cl\"\n#endif\n\n\n__kernel void TEMPLATE(tile,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data,\n const int_tp tile_size, const int_tp num_tiles,\n const int_tp bottom_tile_axis,\n __global Dtype* top_data) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp d = index % tile_size;\n const int_tp b = (index / tile_size / num_tiles) % bottom_tile_axis;\n const int_tp n = index / tile_size / num_tiles / bottom_tile_axis;\n const int_tp bottom_index = (n * bottom_tile_axis + b) * tile_size + d;\n top_data[index] = bottom_data[bottom_index];\n }\n}\n\n\n__kernel void TEMPLATE(tile_backward,Dtype)(const int_tp nthreads,\n __global const Dtype* top_diff,\n const int_tp tile_size,\n const int_tp num_tiles,\n const int_tp bottom_tile_axis,\n __global Dtype* bottom_diff) {\n for (int_tp index = get_global_id(0); index < nthreads;\n index += get_global_size(0)) {\n const int_tp d = index % tile_size;\n const int_tp b = (index / tile_size) % bottom_tile_axis;\n const int_tp n = index / tile_size / bottom_tile_axis;\n bottom_diff[index] = 0;\n int_tp top_index = (n * num_tiles * bottom_tile_axis + b) * tile_size + d;\n for (int_tp t = 0; t < num_tiles; ++t) {\n bottom_diff[index] += top_diff[top_index];\n top_index += bottom_tile_axis * tile_size;\n }\n }\n}"; // NOLINT +viennacl::ocl::program & RegisterKernels(viennacl::ocl::context *ctx) { + std::stringstream ss; +#ifdef USE_INDEX_64 + ss << header << "\n\n"; // NOLINT + ss << definitions_64 << "\n\n"; // NOLINT +#else + ss << header << "\n\n"; // NOLINT + ss << definitions_32 << "\n\n"; // NOLINT +#endif + ss << "#define Dtype float" << "\n\n"; // NOLINT + ss << "#define TYPE TYPE_FLOAT" << "\n\n"; // NOLINT + ss << activation_float << "\n\n"; // NOLINT + ss << auxiliary_float << "\n\n"; // NOLINT + ss << batch_reindex_float << "\n\n"; // NOLINT + ss << bias_float << "\n\n"; // NOLINT + ss << bnll_float << "\n\n"; // NOLINT + ss << channel_float << "\n\n"; // NOLINT + ss << concat_float << "\n\n"; // NOLINT + ss << contrastive_loss_float << "\n\n"; // NOLINT + ss << dropout_float << "\n\n"; // NOLINT + ss << eltwise_float << "\n\n"; // NOLINT + ss << elu_float << "\n\n"; // NOLINT + ss << embed_float << "\n\n"; // NOLINT + ss << fillbuffer_float << "\n\n"; // NOLINT + ss << im2col_float << "\n\n"; // NOLINT + ss << im2col_nd_float << "\n\n"; // NOLINT + ss << lrn_float << "\n\n"; // NOLINT + ss << math_float << "\n\n"; // NOLINT + ss << mergecrop_float << "\n\n"; // NOLINT + ss << pooling_float << "\n\n"; // NOLINT + ss << pooling_nd_float << "\n\n"; // NOLINT + ss << pooling_sk_float << "\n\n"; // NOLINT + ss << slice_float << "\n\n"; // NOLINT + ss << softmax_loss_float << "\n\n"; // NOLINT + ss << solvers_float << "\n\n"; // NOLINT + ss << tile_float << "\n\n"; // NOLINT + ss << "#ifdef DOUBLE_SUPPORT_AVAILABLE" << "\n\n"; // NOLINT + ss << "#undef Dtype" << "\n\n"; // NOLINT + ss << "#define Dtype double" << "\n\n"; // NOLINT + ss << "#undef TYPE" << "\n\n"; // NOLINT + ss << "#define TYPE TYPE_DOUBLE" << "\n\n"; // NOLINT + ss << activation_double << "\n\n"; // NOLINT + ss << auxiliary_double << "\n\n"; // NOLINT + ss << batch_reindex_double << "\n\n"; // NOLINT + ss << bias_double << "\n\n"; // NOLINT + ss << bnll_double << "\n\n"; // NOLINT + ss << channel_double << "\n\n"; // NOLINT + ss << concat_double << "\n\n"; // NOLINT + ss << contrastive_loss_double << "\n\n"; // NOLINT + ss << dropout_double << "\n\n"; // NOLINT + ss << eltwise_double << "\n\n"; // NOLINT + ss << elu_double << "\n\n"; // NOLINT + ss << embed_double << "\n\n"; // NOLINT + ss << fillbuffer_double << "\n\n"; // NOLINT + ss << im2col_double << "\n\n"; // NOLINT + ss << im2col_nd_double << "\n\n"; // NOLINT + ss << lrn_double << "\n\n"; // NOLINT + ss << math_double << "\n\n"; // NOLINT + ss << mergecrop_double << "\n\n"; // NOLINT + ss << pooling_double << "\n\n"; // NOLINT + ss << pooling_nd_double << "\n\n"; // NOLINT + ss << pooling_sk_double << "\n\n"; // NOLINT + ss << slice_double << "\n\n"; // NOLINT + ss << softmax_loss_double << "\n\n"; // NOLINT + ss << solvers_double << "\n\n"; // NOLINT + ss << tile_double << "\n\n"; // NOLINT + ss << "#endif" << "\n\n"; + std::string kernel_string = ss.str(); + const char* kernel_program = kernel_string.c_str(); + // ctx->build_options("-cl-fast-relaxed-math -cl-mad-enable"); + viennacl::ocl::program &program = ctx->add_program(kernel_program, + "kernel_program"); + return program; +} +} // namespace caffe +#endif diff --git a/src/caffe/greentea/cl_kernels.sh b/src/caffe/greentea/cl_kernels.sh new file mode 100644 index 00000000000..98a86e01389 --- /dev/null +++ b/src/caffe/greentea/cl_kernels.sh @@ -0,0 +1,147 @@ +#! /bin/bash +# This script converts all OpenCL Kernels to C++ char strings and defines the helper function to +# load the kernels to ViennaCL/OpenCL contexts. +# Outputs (overwrites): cl_kernels.hpp and cl_kernels.cpp + +declare -a CL_HEADERS_32=("src/caffe/greentea/cl_headers/header.cl" "src/caffe/greentea/cl_headers/definitions_32.cl") +declare -a CL_HEADERS_64=("src/caffe/greentea/cl_headers/header.cl" "src/caffe/greentea/cl_headers/definitions_64.cl") +CL_KERNELDIR="src/caffe/greentea/cl_kernels/*.cl" +HEADER='include/caffe/greentea/cl_kernels.hpp' +INCHEADER='caffe/greentea/cl_kernels.hpp' +SOURCE='src/caffe/greentea/cl_kernels.cpp' + +echo "// AUTOMATICALLY GENERATED FILE, DO NOT EDIT" > $HEADER +echo "// AUTOMATICALLY GENERATED FILE, DO NOT EDIT" > $SOURCE +echo "#include \"caffe/common.hpp\"" >> $HEADER +echo "#ifdef USE_GREENTEA" >> $HEADER +echo "#include \"caffe/common.hpp\"" >> $SOURCE +echo "#ifdef USE_GREENTEA" >> $SOURCE + +echo "#ifndef GREENTEA_CL_KERNELS_HPP_" >> $HEADER +echo "#define GREENTEA_CL_KERNELS_HPP_" >> $HEADER +echo "#include \"caffe/greentea/greentea.hpp\"" >> $HEADER +echo "#include \"viennacl/backend/opencl.hpp\"" >> $HEADER +echo "#include \"viennacl/ocl/backend.hpp\"" >> $HEADER +echo "#include \"viennacl/ocl/context.hpp\"" >> $HEADER +echo "#include \"viennacl/ocl/device.hpp\"" >> $HEADER +echo "#include \"viennacl/ocl/platform.hpp\"" >> $HEADER +echo "namespace caffe {" >> $HEADER +echo "#include \"$INCHEADER\"" >> $SOURCE +echo "#include " >> $SOURCE +echo "#include " >> $SOURCE +echo "namespace caffe {" >> $SOURCE + +echo "viennacl::ocl::program & RegisterKernels(viennacl::ocl::context *ctx);" >> $HEADER +echo "}" >> $HEADER +echo "#endif" >> $HEADER + +echo "#ifdef USE_INDEX_64" >> $SOURCE +shopt -s nullglob +for CL_KERNEL in "${CL_HEADERS_64[@]}" +do + CL_KERNEL_STR=`cat $CL_KERNEL` + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo -n "static std::string $CL_KERNEL_NAME = \"" >> $SOURCE + echo -n "$CL_KERNEL_STR" | sed -e ':a;N;$!ba;s/\n/\\n/g' | sed -e 's/\"/\\"/g' >> $SOURCE + echo "\"; // NOLINT" >> $SOURCE +done +echo "#else" >> $SOURCE +shopt -s nullglob +for CL_KERNEL in "${CL_HEADERS_32[@]}" +do + CL_KERNEL_STR=`cat $CL_KERNEL` + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo -n "static std::string $CL_KERNEL_NAME = \"" >> $SOURCE + echo -n "$CL_KERNEL_STR" | sed -e ':a;N;$!ba;s/\n/\\n/g' | sed -e 's/\"/\\"/g' >> $SOURCE + echo "\"; // NOLINT" >> $SOURCE +done +echo "#endif" >> $SOURCE + +shopt -s nullglob +for CL_KERNEL in $CL_KERNELDIR +do + CL_KERNEL_STR=`cat $CL_KERNEL` + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo -n "static std::string ${CL_KERNEL_NAME}_float = \"" >> $SOURCE + echo -n "$CL_KERNEL_STR" | sed -e ':a;N;$!ba;s/\n/\\n/g' | sed -e 's/\"/\\"/g' >> $SOURCE + echo "\"; // NOLINT" >> $SOURCE +done + +shopt -s nullglob +for CL_KERNEL in $CL_KERNELDIR +do + CL_KERNEL_STR=`cat $CL_KERNEL` + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo -n "static std::string ${CL_KERNEL_NAME}_double = \"" >> $SOURCE + echo -n "$CL_KERNEL_STR" | sed -e ':a;N;$!ba;s/\n/\\n/g' | sed -e 's/\"/\\"/g' >> $SOURCE + echo "\"; // NOLINT" >> $SOURCE +done + +echo "viennacl::ocl::program & RegisterKernels(viennacl::ocl::context *ctx) {" >> $SOURCE +echo " std::stringstream ss;" >> $SOURCE + +echo "#ifdef USE_INDEX_64" >> $SOURCE +shopt -s nullglob +for CL_KERNEL in "${CL_HEADERS_64[@]}" +do + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo " ss << $CL_KERNEL_NAME << \"\\n\\n\"; // NOLINT" >> $SOURCE +done +echo "#else" >> $SOURCE +shopt -s nullglob +for CL_KERNEL in "${CL_HEADERS_32[@]}" +do + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo " ss << $CL_KERNEL_NAME << \"\\n\\n\"; // NOLINT" >> $SOURCE +done +echo "#endif" >> $SOURCE + +shopt -s nullglob +echo " ss << \"#define Dtype float\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +echo " ss << \"#define TYPE TYPE_FLOAT\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +for CL_KERNEL in $CL_KERNELDIR +do + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo " ss << ${CL_KERNEL_NAME}_float << \"\\n\\n\"; // NOLINT" >> $SOURCE +done + +shopt -s nullglob +echo " ss << \"#ifdef DOUBLE_SUPPORT_AVAILABLE\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +echo " ss << \"#undef Dtype\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +echo " ss << \"#define Dtype double\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +echo " ss << \"#undef TYPE\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +echo " ss << \"#define TYPE TYPE_DOUBLE\" << \"\\n\\n\"; // NOLINT" >> $SOURCE +for CL_KERNEL in $CL_KERNELDIR +do + CL_KERNEL_NAME=`echo $CL_KERNEL` + CL_KERNEL_NAME="${CL_KERNEL_NAME##*/}" + CL_KERNEL_NAME="${CL_KERNEL_NAME%.cl}" + echo " ss << ${CL_KERNEL_NAME}_double << \"\\n\\n\"; // NOLINT" >> $SOURCE +done +echo " ss << \"#endif\" << \"\\n\\n\";" >> $SOURCE + +echo " std::string kernel_string = ss.str();" >> $SOURCE +echo " const char* kernel_program = kernel_string.c_str();" >> $SOURCE +echo " // ctx->build_options(\"-cl-fast-relaxed-math -cl-mad-enable\");" >> $SOURCE +echo " viennacl::ocl::program &program = ctx->add_program(kernel_program," >> $SOURCE +echo " \"kernel_program\");" >> $SOURCE +echo " return program;" >> $SOURCE +echo "}" >> $SOURCE +echo "} // namespace caffe" >> $SOURCE + +echo "#endif" >> $HEADER +echo "#endif" >> $SOURCE diff --git a/src/caffe/greentea/cl_kernels/activation.cl b/src/caffe/greentea/cl_kernels/activation.cl new file mode 100644 index 00000000000..d0bfc625245 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/activation.cl @@ -0,0 +1,108 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(relu_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global Dtype* out, + Dtype negative_slope) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out[index] = in[index] > 0 ? in[index] : in[index] * negative_slope; + } +} + +__kernel void TEMPLATE(relu_backward,Dtype)(const int_tp n, + __global const Dtype* in_diff, + __global const Dtype* in_data, + __global Dtype* out_diff, + Dtype negative_slope) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out_diff[index] = in_diff[index] + * ((in_data[index] > 0?1.0:0.0) + (in_data[index] <= 0?1.0:0.0) * negative_slope); + } +} + +__kernel void TEMPLATE(tanh_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out[index] = tanh(in[index]); + } +} + +__kernel void TEMPLATE(tanh_backward,Dtype)(const int_tp n, + __global const Dtype* in_diff, + __global const Dtype* out_data, + __global Dtype* out_diff) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + Dtype tanhx = out_data[index]; + out_diff[index] = in_diff[index] * (1 - tanhx * tanhx); + } +} + +__kernel void TEMPLATE(sigmoid_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out[index] = 1.0 / (1.0 + exp(-in[index])); + } +} + +__kernel void TEMPLATE(sigmoid_backward,Dtype)(const int_tp n, + __global const Dtype* in_diff, + __global const Dtype* out_data, + __global Dtype* out_diff) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + const Dtype sigmoid_x = out_data[index]; + out_diff[index] = in_diff[index] * sigmoid_x * (1 - sigmoid_x); + } +} + +__kernel void TEMPLATE(threshold,Dtype)(const int_tp n, const Dtype threshold, + __global const Dtype* in, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out[index] = in[index] > threshold ? 1.0 : 0.0; + } +} + +__kernel void TEMPLATE(prelu_forward,Dtype)(const int_tp n, const int_tp channels, + const int_tp dim, + __global const Dtype* in, + __global Dtype* out, + __global const Dtype* slope_data, + const int_tp div_factor) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + int_tp c = (index / dim) % channels / div_factor; + out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[c]; + } +} + +__kernel void TEMPLATE(prelu_backward,Dtype)(const int_tp n, const int_tp channels, + const int_tp dim, + __global const Dtype* in_diff, + __global const Dtype* in_data, + __global Dtype* out_diff, + __global const Dtype* slope_data, + const int_tp div_factor) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + int_tp c = (index / dim) % channels / div_factor; + out_diff[index] = in_diff[index] + * ((in_data[index] > 0?1.0:0.0) + (in_data[index] <= 0?1.0:0.0) * slope_data[c]); + } +} + +__kernel void TEMPLATE(prelu_param_backward,Dtype)(const int_tp n, const int_tp rows, + const int_tp rowPitch, + __global const Dtype* in_diff, + __global const Dtype* in_data, + __global Dtype* out_diff) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out_diff[index] = in_diff[index] * in_data[index] * (in_data[index] <= 0?1.0:0.0); + for (int k = 1; k < rows; k++) { + out_diff[index] += in_diff[index + k * rowPitch] + * in_data[index + k * rowPitch] + * (in_data[index + k * rowPitch] <= 0?1.0:0.0); + } + } +} diff --git a/src/caffe/greentea/cl_kernels/auxiliary.cl b/src/caffe/greentea/cl_kernels/auxiliary.cl new file mode 100644 index 00000000000..940cecb7c5f --- /dev/null +++ b/src/caffe/greentea/cl_kernels/auxiliary.cl @@ -0,0 +1,10 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(gpu_set,Dtype)(const int_tp n, const Dtype alpha, __global Dtype* y) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[index] = alpha; + } +} + diff --git a/src/caffe/greentea/cl_kernels/batch_reindex.cl b/src/caffe/greentea/cl_kernels/batch_reindex.cl new file mode 100644 index 00000000000..9cc8dc2a299 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/batch_reindex.cl @@ -0,0 +1,34 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(br_forward,Dtype)(const int_tp count, const int_tp inner_dim, + __global const Dtype* in, + __global const Dtype* permut, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < count; + index += get_global_size(0)) { + int_tp n = index / (inner_dim); + int_tp in_n = (int_tp) (permut[n]); + out[index] = in[in_n * (inner_dim) + index % (inner_dim)]; + } +} + +__kernel void TEMPLATE(br_backward,Dtype)(const int_tp count, const int_tp inner_dim, + __global const Dtype* in, + __global const Dtype* top_indexes, + __global const Dtype* begins, + __global const Dtype* counts, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < count; + index += get_global_size(0)) { + int_tp n = index / (inner_dim); + out[index] = 0; + int_tp lower = (int_tp) (begins[n]); + int_tp upper = lower + (int_tp) (counts[n]); + for (int_tp i = lower; i < upper; ++i) { + int_tp in_n = (int_tp) (top_indexes[i]); + out[index] += in[in_n * (inner_dim) + index % (inner_dim)]; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/bias.cl b/src/caffe/greentea/cl_kernels/bias.cl new file mode 100644 index 00000000000..048f17928d5 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/bias.cl @@ -0,0 +1,43 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(bias_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global const Dtype* bias, + const int_tp bias_dim, + const int_tp inner_dim, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; + index += get_global_size(0)) { + const int_tp bias_index = (index / inner_dim) % bias_dim; + out[index] = in[index] + bias[bias_index]; + } +} + +__kernel void TEMPLATE(scale_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global const Dtype* scale, + const int_tp scale_dim, + const int_tp inner_dim, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; + index += get_global_size(0)) { + const int_tp scale_index = (index / inner_dim) % scale_dim; + out[index] = in[index] * scale[scale_index]; + } +} + +__kernel void TEMPLATE(scale_bias_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global const Dtype* scale, + __global const Dtype* bias, + const int_tp scale_dim, + const int_tp inner_dim, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; + index += get_global_size(0)) { + const int_tp scale_index = (index / inner_dim) % scale_dim; + out[index] = in[index] * scale[scale_index] + bias[scale_index]; + } +} diff --git a/src/caffe/greentea/cl_kernels/bnll.cl b/src/caffe/greentea/cl_kernels/bnll.cl new file mode 100644 index 00000000000..a385484e857 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/bnll.cl @@ -0,0 +1,26 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(bnll_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + if (in[index] > 0.0f) { + out[index] = in[index] + log((Dtype) (1.0 + exp(-in[index]))); + } else { + out[index] = log((Dtype) (1.0 + exp(in[index]))); + } + } +} + +__kernel void TEMPLATE(bnll_backward,Dtype)(const int_tp n, + __global const Dtype* in_diff, + __global const Dtype* in_data, + __global Dtype* out_diff) { + Dtype kBNLL_THRESHOLD = 50.; + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + Dtype expval = exp(min(in_data[index], kBNLL_THRESHOLD)); + out_diff[index] = in_diff[index] * expval / (expval + 1.); + } +} diff --git a/src/caffe/greentea/cl_kernels/channel.cl b/src/caffe/greentea/cl_kernels/channel.cl new file mode 100644 index 00000000000..bf65f536fb1 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/channel.cl @@ -0,0 +1,86 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(kernel_channel_max,Dtype)(const int_tp num, const int_tp channels, + const int_tp spatial_dim, + __global const Dtype* data, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < num * spatial_dim; index += + get_global_size(0)) { + int_tp n = index / spatial_dim; + int_tp s = index % spatial_dim; + float maxval = -FLT_MAX; + for (int_tp c = 0; c < channels; ++c) { + maxval = max((Dtype)(data[(n * channels + c) * spatial_dim + s]), (Dtype)maxval); + } + out[index] = maxval; + } +} + +__kernel void TEMPLATE(kernel_channel_subtract,Dtype)(const int_tp count, const int_tp num, + const int_tp channels, + const int_tp spatial_dim, + __global const Dtype* channel_max, + __global Dtype* data) { + for (int_tp index = get_global_id(0); index < count; + index += get_global_size(0)) { + int_tp n = index / channels / spatial_dim; + int_tp s = index % spatial_dim; + data[index] -= channel_max[n * spatial_dim + s]; + } +} + +__kernel void TEMPLATE(kernel_exp,Dtype)(const int_tp count, __global const Dtype* data, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < count; + index += get_global_size(0)) { + out[index] = exp(data[index]); + } +} + +__kernel void TEMPLATE(kernel_channel_sum,Dtype)(const int_tp num, const int_tp channels, + const int_tp spatial_dim, + __global const Dtype* data, + __global Dtype* channel_sum) { + for (int_tp index = get_global_id(0); index < num * spatial_dim; index += + get_global_size(0)) { + int_tp n = index / spatial_dim; + int_tp s = index % spatial_dim; + Dtype sum = 0; + for (int_tp c = 0; c < channels; ++c) { + sum += data[(n * channels + c) * spatial_dim + s]; + } + channel_sum[index] = sum; + } +} + +__kernel void TEMPLATE(kernel_channel_div,Dtype)(const int_tp count, const int_tp num, + const int_tp channels, const int_tp spatial_dim, + __global const Dtype* channel_sum, + __global Dtype* data) { + for (int_tp index = get_global_id(0); index < count; + index += get_global_size(0)) { + int_tp n = index / channels / spatial_dim; + int_tp s = index % spatial_dim; + data[index] /= channel_sum[n * spatial_dim + s]; + } +} + +__kernel void TEMPLATE(kernel_channel_dot,Dtype)(const int_tp num, const int_tp channels, + const int_tp spatial_dim, + __global const Dtype* data_1, + __global const Dtype* data_2, + __global Dtype* channel_dot) { + for (int_tp index = get_global_id(0); index < num * spatial_dim; index += + get_global_size(0)) { + int_tp n = index / spatial_dim; + int_tp s = index % spatial_dim; + Dtype dot = 0; + for (int_tp c = 0; c < channels; ++c) { + dot += (data_1[(n * channels + c) * spatial_dim + s] + * data_2[(n * channels + c) * spatial_dim + s]); + } + channel_dot[index] = dot; + } +} diff --git a/src/caffe/greentea/cl_kernels/concat.cl b/src/caffe/greentea/cl_kernels/concat.cl new file mode 100644 index 00000000000..4406f97b217 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/concat.cl @@ -0,0 +1,26 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(concat,Dtype)(const int_tp nthreads, __global const Dtype* in_data, + const int forward, const int_tp num_concats, + const int_tp concat_size, + const int_tp top_concat_axis, + const int_tp bottom_concat_axis, + const int_tp offset_concat_axis, + __global Dtype* out_data) { + + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp total_concat_size = concat_size * bottom_concat_axis; + const int_tp concat_num = index / total_concat_size; + const int_tp concat_index = index % total_concat_size; + const int_tp top_index = concat_index + + (concat_num * top_concat_axis + offset_concat_axis) * concat_size; + if (forward == 1) { + out_data[top_index] = in_data[index]; + } else { + out_data[index] = in_data[top_index]; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/contrastive_loss.cl b/src/caffe/greentea/cl_kernels/contrastive_loss.cl new file mode 100644 index 00000000000..867082501f2 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/contrastive_loss.cl @@ -0,0 +1,33 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(cll_backward,Dtype)(const int_tp count, const int_tp channels, + const Dtype margin, const int legacy_version, + const Dtype alpha, __global const Dtype* y, + __global const Dtype* diff, __global const Dtype* dist_sq, + __global Dtype *bottom_diff) { + for (int_tp i = get_global_id(0); i < count; + i += get_global_size(0)) { + int_tp n = i / channels; // the num index, to access y and dist_sq + if ((int_tp)(y[n])) { // similar pairs + bottom_diff[i] = alpha * diff[i]; + } else { // dissimilar pairs + Dtype mdist = 0.0; + Dtype beta = 0.0; + if (legacy_version == 1) { + mdist = (margin - dist_sq[n]); + beta = -alpha; + } else { + Dtype dist = sqrt(dist_sq[n]); + mdist = (margin - dist); + beta = -alpha * mdist / (dist + 1e-4) * diff[i]; + } + if (mdist > 0.0) { + bottom_diff[i] = beta; + } else { + bottom_diff[i] = 0; + } + } + } +} diff --git a/src/caffe/greentea/cl_kernels/dropout.cl b/src/caffe/greentea/cl_kernels/dropout.cl new file mode 100644 index 00000000000..a3debfa6d52 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/dropout.cl @@ -0,0 +1,24 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(dropout_forward,Dtype)(const int_tp n, + __global const Dtype* in, + __global const uint_tp* mask, + const uint_tp threshold, + const Dtype scale, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out[index] = in[index] * ((mask[index] > threshold)?1.0:0.0) * scale; + } +} + +__kernel void TEMPLATE(dropout_backward,Dtype)( + const int_tp n, __global const Dtype* in_diff, + __global const uint_tp* mask, const uint_tp threshold, + const Dtype scale, + __global Dtype* out_diff) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out_diff[index] = in_diff[index] * ((mask[index] > threshold)?1.0:0.0) * scale; + } +} diff --git a/src/caffe/greentea/cl_kernels/eltwise.cl b/src/caffe/greentea/cl_kernels/eltwise.cl new file mode 100644 index 00000000000..7a075cb5e75 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/eltwise.cl @@ -0,0 +1,45 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(eltwise_max_forward,Dtype)( + const int_tp nthreads, __global const Dtype* bottom_data_a, + __global const Dtype* bottom_data_b, const int_tp blob_idx, + __global Dtype* top_data, + __global int_tp* mask) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + Dtype maxval = -FLT_MAX; + int_tp maxidx = -1; + if (bottom_data_a[index] > bottom_data_b[index]) { + // only update for very first bottom_data blob (blob_idx == 0) + if (blob_idx == 0) { + maxval = bottom_data_a[index]; + top_data[index] = maxval; + maxidx = blob_idx; + mask[index] = maxidx; + } + } else { + maxval = bottom_data_b[index]; + top_data[index] = maxval; + maxidx = blob_idx + 1; + mask[index] = maxidx; + } + } +} + +__kernel void TEMPLATE(eltwise_max_backward,Dtype)(const int_tp nthreads, + __global const Dtype* top_diff, + const int_tp blob_idx, + __global const int_tp* mask, + __global Dtype* bottom_diff) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + Dtype gradient = 0; + if (mask[index] == blob_idx) { + gradient += top_diff[index]; + } + bottom_diff[index] = gradient; + } +} + diff --git a/src/caffe/greentea/cl_kernels/elu.cl b/src/caffe/greentea/cl_kernels/elu.cl new file mode 100644 index 00000000000..08cd0e38bd5 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/elu.cl @@ -0,0 +1,23 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(elu_forward,Dtype)(const int n, __global const Dtype* in, + __global Dtype* out, + Dtype alpha) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out[index] = in[index] > 0 ? in[index] : alpha * (exp(in[index]) - 1.0); + } +} + +__kernel void TEMPLATE(elu_backward,Dtype)(const int n, __global const Dtype* in_diff, + __global const Dtype* out_data, + __global const Dtype* in_data, + __global Dtype* out_diff, + Dtype alpha) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + out_diff[index] = + in_data[index] > 0 ? + in_diff[index] : in_diff[index] * (out_data[index] + alpha); + } +} diff --git a/src/caffe/greentea/cl_kernels/embed.cl b/src/caffe/greentea/cl_kernels/embed.cl new file mode 100644 index 00000000000..60029dcf179 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/embed.cl @@ -0,0 +1,84 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(embed_forward,Dtype)(const int_tp nthreads, + __global const Dtype* bottom_data, + __global const Dtype* weight, + const int_tp M, const int_tp N, + const int_tp K, + __global Dtype* top_data) { + for (int_tp top_index = get_global_id(0); top_index < nthreads; + top_index += get_global_size(0)) { + const int_tp n = top_index / N; + const int_tp d = top_index % N; + const int_tp index = (int_tp)(bottom_data[n]); + const int_tp weight_index = index * N + d; + top_data[top_index] = weight[weight_index]; + } + } + +// atomic_add from: http://suhorukov.blogspot.com/2011/12/opencl-11-atomic-operations-on-floating.html +#if (TYPE == TYPE_FLOAT) +inline void TEMPLATE(atomic_add,Dtype)(volatile __global Dtype *source, const Dtype operand) { + union { + uint_tp intVal; + Dtype floatVal; + } newVal; + union { + uint_tp intVal; + Dtype floatVal; + } prevVal; + do { + prevVal.floatVal = *source; + newVal.floatVal = prevVal.floatVal + operand; + } while (atomic_cmpxchg((volatile __global unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal); +} + +__kernel void TEMPLATE(embed_backward,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data, + __global const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K, + __global Dtype* weight_diff) { + for (int_tp top_index = get_global_id(0); top_index < nthreads; + top_index += get_global_size(0)) { + const int_tp n = top_index / N; + const int_tp d = top_index % N; + const int_tp index = (int_tp)(bottom_data[n]); + const int_tp weight_index = index * N + d; + + TEMPLATE(atomic_add,Dtype)((weight_diff + weight_index), *(top_diff + top_index)); + } +} +#endif + +#if (TYPE == TYPE_DOUBLE) +#ifdef ATOMICS_64_AVAILABLE +inline void TEMPLATE(atomic_add,Dtype)(volatile __global Dtype *source, const Dtype operand) { + union { + unsigned long intVal; + Dtype floatVal; + } newVal; + union { + unsigned long intVal; + Dtype floatVal; + } prevVal; + do { + prevVal.floatVal = *source; + newVal.floatVal = prevVal.floatVal + operand; + } while (atom_cmpxchg((volatile __global unsigned long *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal); +} + +__kernel void TEMPLATE(embed_backward,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data, + __global const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K, + __global Dtype* weight_diff) { + for (int_tp top_index = get_global_id(0); top_index < nthreads; + top_index += get_global_size(0)) { + const int_tp n = top_index / N; + const int_tp d = top_index % N; + const int_tp index = (int_tp)(bottom_data[n]); + const int_tp weight_index = index * N + d; + + TEMPLATE(atomic_add,Dtype)((weight_diff + weight_index), *(top_diff + top_index)); + } +} +#endif +#endif diff --git a/src/caffe/greentea/cl_kernels/fillbuffer.cl b/src/caffe/greentea/cl_kernels/fillbuffer.cl new file mode 100644 index 00000000000..52d55a04a1a --- /dev/null +++ b/src/caffe/greentea/cl_kernels/fillbuffer.cl @@ -0,0 +1,17 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(fillbuffer,Dtype)(const int_tp n, const char alpha, __global char* x, + const int_tp offx) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + x[index + offx] = alpha; + } +} + +__kernel void TEMPLATE(fill,Dtype)(const int_tp n, const Dtype alpha, __global Dtype* x, + const int_tp offx) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + x[index + offx] = alpha; + } +} diff --git a/src/caffe/greentea/cl_kernels/im2col.cl b/src/caffe/greentea/cl_kernels/im2col.cl new file mode 100644 index 00000000000..34082b05247 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/im2col.cl @@ -0,0 +1,92 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(im2col,Dtype)(const int_tp n, + __global const Dtype* data_im, + const int_tp data_im_off, + const int_tp height, const int_tp width, + const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, + const int_tp pad_w, const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + const int_tp height_col, + const int_tp width_col, + __global Dtype* data_col, + const int_tp data_col_off) { + + for (int_tp index = get_global_id(0); index < n; + index += get_global_size(0)) { + const int_tp h_index = index / width_col; + const int_tp h_col = h_index % height_col; + const int_tp w_col = index % width_col; + const int_tp c_im = h_index / height_col; + const int_tp c_col = c_im * kernel_h * kernel_w; + const int_tp h_offset = h_col * stride_h - pad_h; + const int_tp w_offset = w_col * stride_w - pad_w; + __global Dtype* data_col_ptr = data_col + data_col_off; + data_col_ptr += (c_col * height_col + h_col) * width_col + w_col; + __global const Dtype* data_im_ptr = data_im + data_im_off; + data_im_ptr += (c_im * height + h_offset) * width + w_offset; + for (int_tp i = 0; i < kernel_h; ++i) { + for (int_tp j = 0; j < kernel_w; ++j) { + int_tp h_im = h_offset + i * dilation_h; + int_tp w_im = w_offset + j * dilation_w; + *data_col_ptr = + (h_im >= 0 && w_im >= 0 && h_im < height && w_im < width) ? + data_im_ptr[i * dilation_h * width + j * dilation_w] : 0; + data_col_ptr += height_col * width_col; + } + } + } +} + +__kernel void TEMPLATE(col2im,Dtype)(const int_tp n, + __global const Dtype* data_col, + const int_tp data_col_off, + const int_tp height, const int_tp width, + const int_tp channels, + const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, + const int_tp pad_w, const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + const int_tp height_col, + const int_tp width_col, + __global Dtype* data_im, + const int_tp data_im_off) { + + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + Dtype val = 0; + const int_tp w_im = index % width + pad_w; + const int_tp h_im = (index / width) % height + pad_h; + const int_tp c_im = index / (width * height); + int_tp kernel_extent_w = (kernel_w - 1) * dilation_w + 1; + int_tp kernel_extent_h = (kernel_h - 1) * dilation_h + 1; + // compute the start and end of the output + const int_tp w_col_start = + (w_im < kernel_extent_w) ? 0 : (w_im - kernel_extent_w) / stride_w + 1; + const int_tp w_col_end = min(w_im / stride_w + 1, width_col); + const int_tp h_col_start = + (h_im < kernel_extent_h) ? 0 : (h_im - kernel_extent_h) / stride_h + 1; + const int_tp h_col_end = min(h_im / stride_h + 1, height_col); + // TODO: use LCM of stride and dilation to avoid unnecessary loops + for (int_tp h_col = h_col_start; h_col < h_col_end; h_col += 1) { + for (int_tp w_col = w_col_start; w_col < w_col_end; w_col += 1) { + int_tp h_k = (h_im - h_col * stride_h); + int_tp w_k = (w_im - w_col * stride_w); + if (h_k % dilation_h == 0 && w_k % dilation_w == 0) { + h_k /= dilation_h; + w_k /= dilation_w; + int_tp data_col_index = (((c_im * kernel_h + h_k) * kernel_w + w_k) * + height_col + h_col) * width_col + w_col; + val += data_col[data_col_off + data_col_index]; + } + } + } + data_im[data_im_off + index] = val; + } +} diff --git a/src/caffe/greentea/cl_kernels/im2col_nd.cl b/src/caffe/greentea/cl_kernels/im2col_nd.cl new file mode 100644 index 00000000000..f372ee3c452 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/im2col_nd.cl @@ -0,0 +1,217 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(im2col_nd, Dtype)(const int_tp n, const int_tp num_axes, + const int_tp channel_axis, + __global const Dtype* data_im, + const int_tp data_im_off, + __global const int_tp* im_shape, + __global const int_tp* col_shape, + __global const int_tp* kernel_shape, + __global const int_tp* pad, + __global const int_tp* stride, + __global const int_tp* dilation, + __global Dtype* data_col, + const int_tp data_col_off) { + int_tp d_temp[6]; + int_tp d_iter[6]; + int_tp i; + + __global const int_tp* im_shape_ptr = im_shape + channel_axis; + __global const int_tp* col_shape_ptr = col_shape + channel_axis; + + __local int_tp shared_dilation[6]; + __local int_tp shared_kernel_shape[6]; + __local int_tp shared_pad[6]; + __local int_tp shared_stride[6]; + __local int_tp shared_col_shape[6 + 1]; + __local int_tp shared_im_shape[6 + 1]; + + for (int li = get_local_id(0); li < num_axes; li += get_local_size(0)) { + shared_dilation[li] = dilation[li]; + shared_kernel_shape[li] = kernel_shape[li]; + shared_pad[li] = pad[li]; + shared_stride[li] = stride[li]; + } + + for (int li = get_local_id(0); li < num_axes + 1; li += get_local_size(0)) { + shared_col_shape[li] = col_shape_ptr[li]; + shared_im_shape[li] = im_shape_ptr[li]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for (int_tp index = get_global_id(0); index < n; + index += get_global_size(0)) { + // Initialize channel_in, computed in the loop below, with int_tpermediate + // computations used to compute the spatial indices. + int_tp channel_in = index; + int_tp channel_out = 1; + for (i = num_axes - 1; i >= 0; --i) { + d_temp[i] = channel_in % shared_col_shape[i + 1]; + channel_in /= shared_col_shape[i + 1]; + channel_out *= shared_kernel_shape[i]; + } + channel_out *= channel_in; + int_tp data_col_inc = 1; + for (i = 0; i < num_axes; ++i) { + channel_out *= shared_col_shape[i + 1]; + channel_out += d_temp[i]; + d_temp[i] = d_temp[i] * shared_stride[i] - shared_pad[i]; + channel_in *= shared_im_shape[i + 1]; + channel_in += d_temp[i]; + data_col_inc *= shared_col_shape[i + 1]; + d_iter[i] = 0; + } + __global Dtype* data_col_ptr = data_col + data_col_off + channel_out; + __global const Dtype* data_im_ptr = data_im + data_im_off + channel_in; + bool incremented; + do { + bool in_range = true; + for (i = 0; i < num_axes; ++i) { + const int_tp d_iter_im = d_iter[i] * shared_dilation[i] + d_temp[i]; + in_range &= d_iter_im >= 0 && d_iter_im < shared_im_shape[i + 1]; + if (!in_range) { + break; + } + } + if (in_range) { + int_tp data_im_offset = d_iter[0] * shared_dilation[0]; + for (i = 1; i < num_axes; ++i) { + data_im_offset *= shared_im_shape[i + 1]; + data_im_offset += d_iter[i] * shared_dilation[i]; + } + *data_col_ptr = data_im_ptr[data_im_offset]; + } else { + *data_col_ptr = 0; + } + data_col_ptr += data_col_inc; + incremented = false; + for (i = num_axes - 1; i >= 0; --i) { + const int_tp d_max = shared_kernel_shape[i]; + if (d_iter[i] == d_max - 1) { + d_iter[i] = 0; + } else { // d_iter[i] < d_max - 1 + ++d_iter[i]; + incremented = true; + break; + } + } // for (int_tp i = num_axes - 1; i >= 0; --i) + } while (incremented); // do + } +} + +__kernel void TEMPLATE(col2im_nd, Dtype)(const int_tp n, const int_tp num_axes, + const int_tp channel_axis, + __global const Dtype* data_col, + const int_tp data_col_off, + __global const int_tp* im_shape, + __global const int_tp* col_shape, + __global const int_tp* kernel_shape, + __global const int_tp* pad, + __global const int_tp* stride, + __global const int_tp* dilation, + __global Dtype* data_im, + const int_tp data_im_off) { + int_tp d_im[6]; + int_tp d_col_iter[6]; + int_tp d_col_start[6]; + int_tp d_col_end[6]; + + __global const int_tp* im_shape_ptr = im_shape + channel_axis; + __global const int_tp* col_shape_ptr = col_shape + channel_axis; + + __local int_tp shared_dilation[6]; + __local int_tp shared_kernel_shape[6]; + __local int_tp shared_pad[6]; + __local int_tp shared_stride[6]; + __local int_tp shared_col_shape[6 + 1]; + __local int_tp shared_im_shape[6 + 1]; + + for (int li = get_local_id(0); li < num_axes; li += get_local_size(0)) { + shared_dilation[li] = dilation[li]; + shared_kernel_shape[li] = kernel_shape[li]; + shared_pad[li] = pad[li]; + shared_stride[li] = stride[li]; + } + for (int li = get_local_id(0); li < num_axes + 1; li += get_local_size(0)) { + shared_col_shape[li] = col_shape_ptr[li]; + shared_im_shape[li] = im_shape_ptr[li]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + // Initialize channel_in, computed in the loop below, with intermediate + // computations used to compute the spatial indices. + int_tp c_im = index; + // Calculate d_im (image dimensions). + for (int_tp i = num_axes - 1; i >= 0; --i) { + d_im[i] = c_im % shared_im_shape[i + 1] + shared_pad[i]; + c_im /= shared_im_shape[i + 1]; + } + // Calculate col start/end indices. + bool done = false; + for (int_tp i = 0; i < num_axes; ++i) { + const int_tp kernel_extent = shared_dilation[i] + * (shared_kernel_shape[i] - 1) + 1; + d_col_start[i] = d_col_iter[i] = + (d_im[i] < kernel_extent) ? + 0 : (d_im[i] - kernel_extent) / shared_stride[i] + 1; + d_col_end[i] = min(d_im[i] / shared_stride[i] + 1, + shared_col_shape[i + 1]); + if (d_col_start[i] >= d_col_end[i]) { + // Skip computation if the dimension is 0 at any spatial axis -- + // final val will be 0. + data_im[index] = 0; + done = true; + break; // for (int_tp i = 0; i < num_axes; ++i) + } + } + if (!done) { + // Loop over the col to compute the output val. + Dtype val = 0; + bool incremented = true; + bool skip = false; + do { + // Compute the final offset. + int_tp final_offset = 0; + int_tp kernel_shape_prod = 1; + int_tp kernel_index; + for (int_tp i = num_axes - 1; i >= 0; --i) { + kernel_index = d_im[i] - d_col_iter[i] * shared_stride[i]; + if (kernel_index % shared_dilation[i]) { + skip = true; + break; + } else { + kernel_index /= shared_dilation[i]; + final_offset += kernel_index * kernel_shape_prod; + kernel_shape_prod *= shared_kernel_shape[i]; + } + } + if (!skip) { + final_offset += kernel_shape_prod * c_im; + for (int_tp i = 0; i < num_axes; ++i) { + final_offset *= shared_col_shape[i + 1]; + final_offset += d_col_iter[i]; + } + val += data_col[data_col_off + final_offset]; + } + skip = false; + incremented = false; + for (int_tp i = num_axes - 1; i >= 0; --i) { + const int_tp d_max = d_col_end[i]; + if (d_col_iter[i] == d_max - 1) { + d_col_iter[i] = d_col_start[i]; + } else { // d_col_iter[i] < d_max - 1 + ++d_col_iter[i]; + incremented = true; + break; // for (int_tp i = num_axes - 1; i >= 0; --i) + } + } // for (int_tp i = num_axes - 1; i >= 0; --i) + } while (incremented); + data_im[data_im_off + index] = val; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/lrn.cl b/src/caffe/greentea/cl_kernels/lrn.cl new file mode 100644 index 00000000000..6bcbd75081f --- /dev/null +++ b/src/caffe/greentea/cl_kernels/lrn.cl @@ -0,0 +1,121 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(lrn_compute_output,Dtype)(const int_tp nthreads, + __global const Dtype* in, + __global const Dtype* scale, + const Dtype negative_beta, + __global Dtype* out) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + out[index] = in[index] * pow(scale[index], negative_beta); + } +} + +__kernel void TEMPLATE(lrn_fill_scale,Dtype)(const int_tp nthreads, __global const Dtype* in, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, const int_tp size, + const Dtype alpha_over_size, const Dtype k, + __global Dtype* const scale) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + // find out the local offset + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp n = index / width / height; + const int_tp offset = (n * channels * height + h) * width + w; + const int_tp step = height * width; + __global const Dtype* in_off = in + offset; + __global Dtype* scale_off = scale + offset; + int_tp head = 0; + const int_tp pre_pad = (size - 1) / 2; + const int_tp post_pad = size - pre_pad - 1; + Dtype accum_scale = 0; + // fill the scale at [n, :, h, w] + // accumulate values + while (head < post_pad && head < channels) { + accum_scale += in_off[head * step] * in_off[head * step]; + ++head; + } + // both add and subtract + while (head < channels) { + accum_scale += in_off[head * step] * in_off[head * step]; + if (head - size >= 0) { + accum_scale -= in_off[(head - size) * step] + * in_off[(head - size) * step]; + } + scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size; + ++head; + } + // subtract only + while (head < channels + post_pad) { + if (head - size >= 0) { + accum_scale -= in_off[(head - size) * step] + * in_off[(head - size) * step]; + } + scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size; + ++head; + } + } +} + +__kernel void TEMPLATE(lrn_compute_diff,Dtype)(const int_tp nthreads, + __global const Dtype* bottom_data, + __global const Dtype* top_data, + __global const Dtype* scale, + __global const Dtype* top_diff, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp size, + const Dtype negative_beta, + const Dtype cache_ratio, + __global Dtype* bottom_diff) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + // find out the local offset + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp n = index / width / height; + const int_tp offset = (n * channels * height + h) * width + w; + const int_tp step = height * width; + __global const Dtype* bottom_off = bottom_data + offset; + __global const Dtype* top_off = top_data + offset; + __global const Dtype* scale_off = scale + offset; + __global const Dtype* top_diff_off = top_diff + offset; + __global Dtype* bottom_diff_off = bottom_diff + offset; + int_tp head = 0; + const int_tp pre_pad = size - (size + 1) / 2; + const int_tp post_pad = size - pre_pad - 1; + Dtype accum_ratio = 0; + // accumulate values + while (head < post_pad && head < channels) { + accum_ratio += top_diff_off[head * step] * top_off[head * step] + / scale_off[head * step]; + ++head; + } + // both add and subtract + while (head < channels) { + accum_ratio += top_diff_off[head * step] * top_off[head * step] + / scale_off[head * step]; + if (head - size >= 0) { + accum_ratio -= top_diff_off[(head - size) * step] + * top_off[(head - size) * step] / scale_off[(head - size) * step]; + } + bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad) + * step] * pow(scale_off[(head - post_pad) * step], negative_beta) + - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio; + ++head; + } + // subtract only + while (head < channels + post_pad) { + if (head - size >= 0) { + accum_ratio -= top_diff_off[(head - size) * step] + * top_off[(head - size) * step] / scale_off[(head - size) * step]; + } + bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad) + * step] * pow(scale_off[(head - post_pad) * step], negative_beta) + - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio; + ++head; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/math.cl b/src/caffe/greentea/cl_kernels/math.cl new file mode 100644 index 00000000000..50e9d3267c6 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/math.cl @@ -0,0 +1,103 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(mul,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, + __global Dtype* b, + const int_tp offb, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[index + offy] = a[index + offa] * b[index + offb]; + } +} + +__kernel void TEMPLATE(div,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, + __global Dtype* b, + const int_tp offb, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[index + offy] = a[index + offa] / b[index + offb]; + } +} + +__kernel void TEMPLATE(add_scalar,Dtype)(const int_tp N, const Dtype alpha, +__global Dtype* Y, + const int_tp offY) { + for (int_tp index = get_global_id(0); index < N; index += get_global_size(0)) { + Y[offY + index] += alpha; + } +} + +__kernel void TEMPLATE(add,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, __global const Dtype* b, + const int_tp offb, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[offy + index] = a[offa + index] + b[offb + index]; + } +} + +__kernel void TEMPLATE(sub,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, __global const Dtype* b, + const int_tp offb, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[offy + index] = a[offa + index] - b[offb + index]; + } +} + +__kernel void TEMPLATE(abs,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[offy + index] = fabs((Dtype)(a[offa + index])); + } +} + +__kernel void TEMPLATE(exp,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[offy + index] = exp(a[offa + index]); + } +} + +__kernel void TEMPLATE(log,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[offy + index] = log((Dtype)(a[offa + index])); + } +} + +__kernel void TEMPLATE(powx,Dtype)(const int_tp n, __global const Dtype* a, + const int_tp offa, Dtype alpha, + __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + if(alpha == 2.0) { + y[offy + index] = pow((Dtype)fabs(a[offa + index]), (Dtype)alpha); + } else { + y[offy + index] = pow((Dtype)a[offa + index], (Dtype)alpha); + } + } +} + +__kernel void TEMPLATE(sign,Dtype)(const int_tp n, __global const Dtype* x, + const int_tp offx, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[index + offy] = (0.0 < x[index + offx]) + - (x[index + offx] < 0.0); + } +} + +__kernel void TEMPLATE(sgnbit,Dtype)(const int_tp n, __global const Dtype* x, + const int_tp offx, __global Dtype* y, + const int_tp offy) { + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + y[index + offy] = signbit(x[index + offx]); + } +} diff --git a/src/caffe/greentea/cl_kernels/mergecrop.cl b/src/caffe/greentea/cl_kernels/mergecrop.cl new file mode 100644 index 00000000000..d8d7289a8fd --- /dev/null +++ b/src/caffe/greentea/cl_kernels/mergecrop.cl @@ -0,0 +1,113 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(merge_copy_forward, Dtype)(const int_tp nthreads, + const int_tp dims, + __global const Dtype* bottom_a, + const int_tp forward_a, + __global const Dtype* bottom_b, + const int_tp forward_b, + __global Dtype* top, + const int_tp num, + const int_tp channels_a, + const int_tp channels_b, + __global const int_tp* shape_a, + __global const int_tp* shape_b) { + int_tp pad[6]; + int_tp tmp_idx[6]; + int_tp size_a = 1; + int_tp size_b = 1; + + for (int_tp i = 0; i < dims; ++i) { + pad[i] = (shape_b[i] - shape_a[i]) / 2; + size_a *= shape_a[i]; + size_b *= shape_b[i]; + } + + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + int_tp batch_id = index / ((channels_a + channels_b) * size_a); + int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a) + / (channels_a * size_a)) % 2; + int_tp counter = index; + for (int_tp i = dims - 1; i >= 0; --i) { + tmp_idx[i] = counter % shape_a[i]; + counter /= shape_a[i]; + } + + if (bottom_id == 0) { + int_tp channel_id = (index / size_a) % channels_a; + int_tp aidx = batch_id * channels_a + channel_id; + for (int_tp i = 0; i < dims; ++i) { + aidx *= shape_a[i]; + aidx += tmp_idx[i]; + } + top[index] = (forward_a == 1) ? bottom_a[aidx] : 0; + } else { + int_tp channel_id = (index / size_a) % channels_b; + int_tp bidx = (batch_id * channels_b + channel_id) * size_b; + int_tp btemp = 1; + for (int_tp i = dims - 1; i >= 0; --i) { + bidx += btemp * (tmp_idx[i] + pad[i]); + btemp *= shape_b[i]; + } + top[index] = (forward_b == 1) ? bottom_b[bidx] : 0; + } + } +} + +__kernel void TEMPLATE(merge_copy_backward,Dtype)(const int_tp nthreads, + const int_tp dims, + __global Dtype* bottom_a, + const int_tp backward_a, + __global Dtype* bottom_b, + const int_tp backward_b, + __global const Dtype* top, + const int_tp num, + const int_tp channels_a, + const int_tp channels_b, + __global const int_tp* shape_a, + __global const int_tp* shape_b) { + int_tp pad[6]; + int_tp tmp_idx[6]; + int_tp size_a = 1; + int_tp size_b = 1; + + for (int_tp i = 0; i < dims; ++i) { + pad[i] = (shape_b[i] - shape_a[i]) / 2; + size_a *= shape_a[i]; + size_b *= shape_b[i]; + } + + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + int_tp batch_id = index / ((channels_a + channels_b) * size_a); + int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a) + / (channels_a * size_a)) % 2; + int_tp counter = index; + for (int_tp i = dims - 1; i >= 0; --i) { + tmp_idx[i] = counter % shape_a[i]; + counter /= shape_a[i]; + } + + if (bottom_id == 0) { + int_tp channel_id = (index / size_a) % channels_a; + int_tp aidx = batch_id * channels_a + channel_id; + for (int_tp i = 0; i < dims; ++i) { + aidx *= shape_a[i]; + aidx += tmp_idx[i]; + } + bottom_a[aidx] = (backward_a == 1) ? top[index] : 0; + } else { + int_tp channel_id = (index / size_a) % channels_b; + int_tp bidx = (batch_id * channels_b + channel_id) * size_b; + int_tp btemp = 1; + for (int_tp i = dims - 1; i >= 0; --i) { + bidx += btemp * (tmp_idx[i] + pad[i]); + btemp *= shape_b[i]; + } + bottom_b[bidx] = (backward_b == 1) ? top[index] : 0; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/pooling.cl b/src/caffe/greentea/cl_kernels/pooling.cl new file mode 100644 index 00000000000..cc56bab12d9 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/pooling.cl @@ -0,0 +1,292 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(max_pool_forward,Dtype)( + const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, const int_tp pad_h, + const int_tp pad_w, + __global Dtype* top_data, + const int use_mask, __global int_tp* mask, __global Dtype* top_mask) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + const int_tp hend = min(hstart + kernel_h, height); + const int_tp wend = min(wstart + kernel_w, width); + hstart = max(hstart, (int_tp)0); + wstart = max(wstart, (int_tp)0); + Dtype maxval = -FLT_MAX; + int_tp maxidx = -1; + __global const Dtype* bottom_slice = bottom_data + + (n * channels + c) * height * width; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + if (bottom_slice[h * width + w] > maxval) { + maxidx = h * width + w; + maxval = bottom_slice[maxidx]; + } + } + } + top_data[index] = maxval; + if (use_mask == 1) { + mask[index] = maxidx; + } else { + top_mask[index] = maxidx; + } + } +} + +__kernel void TEMPLATE(ave_pool_forward,Dtype)( + const int_tp nthreads, __global const Dtype* const bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, const int_tp pad_h, + const int_tp pad_w, __global Dtype* top_data) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + { + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min(hstart + kernel_h, height + pad_h); + int_tp wend = min(wstart + kernel_w, width + pad_w); + const int_tp pool_size = (hend - hstart) * (wend - wstart); + hstart = max(hstart, (int_tp)0); + wstart = max(wstart, (int_tp)0); + hend = min(hend, height); + wend = min(wend, width); + Dtype aveval = 0; + __global const Dtype* bottom_slice = bottom_data + + (n * channels + c) * height * width; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + aveval += bottom_slice[h * width + w]; + } + } + top_data[index] = aveval / pool_size; + } + } +} + +__kernel void TEMPLATE(sto_pool_forward_train,Dtype)( + const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, + __global Dtype* rand_idx, + __global Dtype* top_data) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + const int_tp hstart = ph * stride_h; + const int_tp hend = min(hstart + kernel_h, height); + const int_tp wstart = pw * stride_w; + const int_tp wend = min(wstart + kernel_w, width); + Dtype cumsum = 0.; + __global const Dtype* bottom_slice = bottom_data + + (n * channels + c) * height * width; + // First pass: get sum + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + cumsum += bottom_slice[h * width + w]; + } + } + const float thres = rand_idx[index] * cumsum; + // Second pass: get value, and set index. + cumsum = 0; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + cumsum += bottom_slice[h * width + w]; + if (cumsum >= thres) { + rand_idx[index] = ((n * channels + c) * height + h) * width + w; + top_data[index] = bottom_slice[h * width + w]; + h = hend; + w = wend; + } + } + } + } +} + +__kernel void TEMPLATE(sto_pool_forward_test,Dtype)( + const int_tp nthreads, __global const Dtype* const bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp stride_h, const int_tp stride_w, + __global Dtype* top_data) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + const int_tp hstart = ph * stride_h; + const int_tp hend = min(hstart + kernel_h, height); + const int_tp wstart = pw * stride_w; + const int_tp wend = min(wstart + kernel_w, width); + // We set cumsum to be 0 to avoid divide-by-zero problems + Dtype cumsum = FLT_MIN; + Dtype cumvalues = 0.; + __global const Dtype* bottom_slice = bottom_data + + (n * channels + c) * height * width; + // First pass: get sum + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + cumsum += bottom_slice[h * width + w]; + cumvalues += bottom_slice[h * width + w] * bottom_slice[h * width + w]; + } + } + top_data[index] = cumvalues / cumsum; + } +} + +__kernel void TEMPLATE(max_pool_backward,Dtype)(const int_tp nthreads, + __global const Dtype* top_diff, + const int use_mask, + __global const int_tp* mask, + __global const Dtype* top_mask, + const int_tp num, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp pad_h, + const int_tp pad_w, + __global Dtype* bottom_diff) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + // find out the local index + // find out the local offset + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp c = (index / width / height) % channels; + const int_tp n = index / width / height / channels; + const int_tp phstart = + (h + pad_h < kernel_h) ? 0 : (h + pad_h - kernel_h) / stride_h + 1; + const int_tp phend = min((h + pad_h) / stride_h + 1, pooled_height); + const int_tp pwstart = + (w + pad_w < kernel_w) ? 0 : (w + pad_w - kernel_w) / stride_w + 1; + const int_tp pwend = min((w + pad_w) / stride_w + 1, pooled_width); + Dtype gradient = 0; + const int_tp offset = (n * channels + c) * pooled_height * pooled_width; + __global const Dtype* top_diff_slice = top_diff + offset; + if (use_mask == 1) { + __global const int_tp* mask_slice = mask + offset; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { + if (mask_slice[ph * pooled_width + pw] == h * width + w) { + gradient += top_diff_slice[ph * pooled_width + pw]; + } + } + } + } else { + __global const Dtype* top_mask_slice = top_mask + offset; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { + if (top_mask_slice[ph * pooled_width + pw] == h * width + w) { + gradient += top_diff_slice[ph * pooled_width + pw]; + } + } + } + } + bottom_diff[index] = gradient; + } +} + +__kernel void TEMPLATE(ave_pool_backward,Dtype)(const int_tp nthreads, + __global const Dtype* top_diff, + const int_tp num, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp pad_h, + const int_tp pad_w, + __global Dtype* bottom_diff) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + // find out the local index + // find out the local offset + const int_tp w = index % width + pad_w; + const int_tp h = (index / width) % height + pad_h; + const int_tp c = (index / width / height) % channels; + const int_tp n = index / width / height / channels; + const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1; + const int_tp phend = min(h / stride_h + 1, pooled_height); + const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1; + const int_tp pwend = min(w / stride_w + 1, pooled_width); + Dtype gradient = 0.0; + __global const Dtype* const top_diff_slice = top_diff + + (n * channels + c) * pooled_height * pooled_width; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { + // figure out the pooling size + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min(hstart + kernel_h, height + pad_h); + int_tp wend = min(wstart + kernel_w, width + pad_w); + int_tp pool_size = (hend - hstart) * (wend - wstart); + gradient += top_diff_slice[ph * pooled_width + pw] / pool_size; + } + } + bottom_diff[index] = gradient; + } +} + +__kernel void TEMPLATE(sto_pool_backward,Dtype)( + const int_tp nthreads, __global const Dtype* rand_idx, + __global const Dtype* const top_diff, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, const int_tp stride_h, + const int_tp stride_w, __global Dtype* bottom_diff) { + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + // find out the local index + // find out the local offset + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp c = (index / width / height) % channels; + const int_tp n = index / width / height / channels; + const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1; + const int_tp phend = min(h / stride_h + 1, pooled_height); + const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1; + const int_tp pwend = min(w / stride_w + 1, pooled_width); + Dtype gradient = 0.0; + __global const Dtype* rand_idx_slice = rand_idx + + (n * channels + c) * pooled_height * pooled_width; + __global const Dtype* top_diff_slice = top_diff + + (n * channels + c) * pooled_height * pooled_width; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { + gradient += top_diff_slice[ph * pooled_width + pw] + * (index == (int_tp) (rand_idx_slice[ph * pooled_width + pw])?1.0:0.0); + } + } + bottom_diff[index] = gradient; + } +} + diff --git a/src/caffe/greentea/cl_kernels/pooling_nd.cl b/src/caffe/greentea/cl_kernels/pooling_nd.cl new file mode 100644 index 00000000000..73a2dc147e2 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/pooling_nd.cl @@ -0,0 +1,196 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(max_pool_forward_nd, Dtype)(const int_tp n, + const int_tp num_axes, + __global const Dtype* bottom_data, + const int_tp channels, + __global const int_tp* size, + __global const int_tp* pooled_size, + __global const int_tp* kernel_size, + __global const int_tp* ext_kernel_size, + __global const int_tp* stride, + __global const int_tp* dilation, + __global const int_tp* pad, + __global Dtype* top_data, + const int use_mask, + __global int_tp* mask, __global Dtype* top_mask) { + int_tp d_idx[6]; + int_tp d_start[6]; + int_tp d_end[6]; + int_tp d_iter[6]; + int_tp i; + + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + int_tp offset = 1; + int_tp num = index; + + bool do_continue = false; + + for (i = num_axes - 1; i >= 0; --i) { + d_idx[i] = num % pooled_size[i]; + d_start[i] = d_idx[i] * stride[i] - pad[i]; + d_end[i] = min(d_start[i] + ext_kernel_size[i], size[i]); + d_start[i] = max(d_start[i], (int_tp)0); + num /= pooled_size[i]; + offset *= size[i]; + d_iter[i] = d_start[i]; + + if (d_start[i] >= d_end[i]) { + top_data[index] = -FLT_MAX; + if (use_mask) { + mask[index] = -1; + } else { + top_mask[index] = -1; + } + do_continue = true; + } + } + + if(do_continue) { + continue; + } + + int_tp chan = num % channels; + num /= channels; + offset *= (num * channels + chan); + + Dtype maxval = -FLT_MAX; + int_tp maxidx = -1; + int_tp final_offset = 0; + + bool incremented; + do { + final_offset = offset; + int_tp size_prod = 1; + for (i = num_axes - 1; i >= 0; --i) { + final_offset += d_iter[i] * size_prod; + size_prod *= size[i]; + } + + if (bottom_data[final_offset] > maxval) { + maxidx = final_offset; + maxval = bottom_data[maxidx]; + } + + incremented = false; + for (i = num_axes - 1; i >= 0; --i) { + if (d_iter[i] >= d_end[i] - dilation[i]) { + d_iter[i] = d_start[i]; + } else { + d_iter[i] += dilation[i]; + incremented = true; + break; + } + } + } while (incremented); + + top_data[index] = maxval; + if (use_mask == 1) { + mask[index] = maxidx; + } else { + top_mask[index] = maxidx; + } + } +} + + +__kernel void TEMPLATE(max_pool_backward_nd, Dtype)(const int_tp n, + const int_tp num_axes, + __global const Dtype* top_diff, + const int use_mask, + __global const int_tp* mask, + __global const Dtype* top_mask, + const int_tp channels, + __global const int_tp* size, + __global const int_tp* pooled_size, + __global const int_tp* kernel_size, + __global const int_tp* ext_kernel_size, + __global const int_tp* stride, + __global const int_tp* dilation, + __global const int_tp* pad, + __global Dtype* bottom_diff) { + int_tp d_idx[6]; + int_tp d_start[6]; + int_tp d_end[6]; + int_tp d_iter[6]; + int_tp i; + + for (int_tp index = get_global_id(0); index < n; index += get_global_size(0)) { + // find out the local index + // find out the local offset + int_tp offset = 1; + int_tp num = index; + for (i = num_axes - 1; i >= 0; --i) { + d_idx[i] = num % size[i]; + if (dilation[i] > 1) { + d_start[i] = + (d_idx[i] < ext_kernel_size[i]) ? + d_idx[i] % dilation[i] : (d_idx[i] - ext_kernel_size[i]) + 1; + d_end[i] = + (d_idx[i] >= pooled_size[i]) ? + (pooled_size[i] - 1) + - (pooled_size[i] - 1 - d_start[i]) % dilation[i] : + d_idx[i]; + } else { + d_start[i] = + (d_idx[i] + pad[i] < kernel_size[i]) ? + 0 : (d_idx[i] + pad[i] - kernel_size[i]) / stride[i] + 1; + d_end[i] = min((int_tp) ((d_idx[i] + pad[i]) / stride[i] + 1), + (int_tp) (pooled_size[i])); + } + num /= size[i]; + offset *= pooled_size[i]; + d_iter[i] = d_start[i]; + + if (d_start[i] > d_end[i]) { + bottom_diff[index] = 0; + return; + } + } + int_tp chan = num % channels; + num /= channels; + offset *= (num * channels + chan); + + Dtype gradient = 0; + int_tp final_offset = 0; + int_tp im_offset = 0; + + bool incremented; + do { + final_offset = offset; + im_offset = 0; + int_tp size_prod = 1; + int_tp pooled_size_prod = 1; + for (i = num_axes - 1; i >= 0; --i) { + final_offset += d_iter[i] * pooled_size_prod; + im_offset += d_idx[i] * size_prod; + size_prod *= size[i]; + pooled_size_prod *= pooled_size[i]; + } + + if (use_mask) { + if (mask[final_offset] == im_offset) { + gradient += top_diff[final_offset]; + } + } else { + if (top_mask[final_offset] == im_offset) { + gradient += top_diff[final_offset]; + } + } + + incremented = false; + for (i = num_axes - 1; i >= 0; --i) { + if (d_iter[i] > d_end[i] - dilation[i]) { + d_iter[i] = d_start[i]; + } else { + d_iter[i] += dilation[i]; + incremented = true; + break; + } + } + } while (incremented); + bottom_diff[index] = gradient; + } +} diff --git a/src/caffe/greentea/cl_kernels/pooling_sk.cl b/src/caffe/greentea/cl_kernels/pooling_sk.cl new file mode 100644 index 00000000000..1184ba64590 --- /dev/null +++ b/src/caffe/greentea/cl_kernels/pooling_sk.cl @@ -0,0 +1,241 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(max_pool_forward_sk,Dtype)(const int_tp nthreads, +__global Dtype* bottom_data, + const int_tp num, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp ext_kernel_h, + const int_tp ext_kernel_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + const int_tp pad_h, + const int_tp pad_w, + __global Dtype* top_data, + const int use_mask, + __global int_tp* mask, + __global Dtype* top_mask) { + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min(hstart + ext_kernel_h, height); + int_tp wend = min(wstart + ext_kernel_w, width); + hstart = max(hstart, (int_tp) 0); + wstart = max(wstart, (int_tp) 0); + Dtype maxval = -FLT_MAX; + int_tp maxidx = -1; + __global Dtype* bottom_data_ptr = bottom_data + + (n * channels + c) * height * width; + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + if (bottom_data_ptr[h * width + w] > maxval) { + maxidx = h * width + w; + maxval = bottom_data_ptr[maxidx]; + } + } + } + top_data[index] = maxval; + if (use_mask == 1) { + mask[index] = maxidx; + } else { + top_mask[index] = maxidx; + } + } +} + +__kernel void TEMPLATE(max_pool_backward_sk,Dtype)( + const int_tp nthreads, __global const Dtype* top_diff, const int use_mask, + __global const int_tp* mask, __global const Dtype* top_mask, + const int_tp num, const int_tp channels, const int_tp height, + const int_tp width, const int_tp pooled_height, const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h, + const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, const int_tp pad_h, + const int_tp pad_w, + __global Dtype* bottom_diff) { + + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + + __global const int_tp* mask_ptr = mask; + __global const Dtype* top_diff_ptr = top_diff; + +// find out the local index +// find out the local offset + int_tp w = index % width; + int_tp h = (index / width) % height; + int_tp c = (index / width / height) % channels; + int_tp n = index / width / height / channels; + + int_tp pooled_height_1 = pooled_height - 1; + int_tp pooled_width_1 = pooled_width - 1; + int_tp phstart = + (h < ext_kernel_h) ? h % dilation_h : (h - ext_kernel_h) + 1; + int_tp phend = + (h >= pooled_height) ? + pooled_height_1 - (pooled_height_1 - phstart) % dilation_h : h; + int_tp pwstart = + (w < ext_kernel_w) ? w % dilation_w : (w - ext_kernel_w) + 1; + int_tp pwend = + (w >= pooled_width) ? + pooled_width_1 - (pooled_width_1 - pwstart) % dilation_w : w; + + Dtype gradient = 0; + int_tp offset = (n * channels + c) * pooled_height * pooled_width; + top_diff_ptr += offset; + if (use_mask == 1) { + mask_ptr += offset; + for (int_tp ph = phstart; ph <= phend; ph += dilation_h) { + for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) { + if (mask_ptr[ph * pooled_width + pw] == h * width + w) { + gradient += top_diff_ptr[ph * pooled_width + pw]; + } + } + } + } else { + for (int_tp ph = phstart; ph <= phend; ph += dilation_h) { + for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) { + if (top_mask[ph * pooled_width + pw] == h * width + w) { + gradient += top_diff_ptr[ph * pooled_width + pw]; + } + } + } + } + bottom_diff[index] = gradient; + } +} + +__kernel void TEMPLATE(ave_pool_forward_sk,Dtype)( + const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h, + const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, const int_tp pad_h, + const int_tp pad_w, + __global Dtype* top_data) { + + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min(hstart + ext_kernel_h, height + pad_h); + int_tp wend = min(wstart + ext_kernel_w, width + pad_w); + hstart = max(hstart, (int_tp)0); + wstart = max(wstart, (int_tp)0); + hend = min(hend, height); + wend = min(wend, width); + Dtype aveval = 0; + __global const Dtype* bottom_data_ptr = bottom_data; + bottom_data_ptr += (n * channels + c) * height * width; + int_tp pool_size = 0; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + aveval += bottom_data_ptr[h * width + w]; + ++pool_size; + } + } + top_data[index] = aveval / pool_size; + } +} + +__kernel void TEMPLATE(sto_pool_forward_train_sk,Dtype)( + const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h, + const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, __global Dtype* rand_idx, + __global Dtype* top_data) { + + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h; + int_tp hend = min(hstart + ext_kernel_h, height); + int_tp wstart = pw * stride_w; + int_tp wend = min(wstart + ext_kernel_w, width); + Dtype cumsum = 0.; + __global const Dtype* bottom_data_ptr = bottom_data; + bottom_data_ptr += (n * channels + c) * height * width; + // First pass: get sum + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + cumsum += bottom_data_ptr[h * width + w]; + } + } + float thres = rand_idx[index] * cumsum; + // Second pass: get value, and set index. + cumsum = 0; + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + cumsum += bottom_data_ptr[h * width + w]; + if (cumsum >= thres) { + rand_idx[index] = ((n * channels + c) * height + h) * width + w; + top_data[index] = bottom_data_ptr[h * width + w]; + h = hend; + w = wend; + } + } + } + } +} + +__kernel void TEMPLATE(sto_pool_forward_test_sk,Dtype)( + const int_tp nthreads, __global const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, const int_tp width, + const int_tp pooled_height, const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, const int_tp ext_kernel_h, + const int_tp ext_kernel_w, const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + __global Dtype* top_data) { + + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h; + int_tp hend = min(hstart + ext_kernel_h, height); + int_tp wstart = pw * stride_w; + int_tp wend = min(wstart + ext_kernel_w, width); + // We set cumsum to be 0 to avoid divide-by-zero problems + Dtype cumsum = FLT_MIN; + Dtype cumvalues = 0.; + __global const Dtype* bottom_data_ptr = bottom_data; + bottom_data_ptr += (n * channels + c) * height * width; + // First pass: get sum + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + cumsum += bottom_data_ptr[h * width + w]; + cumvalues += bottom_data_ptr[h * width + w] + * bottom_data_ptr[h * width + w]; + } + } + top_data[index] = cumvalues / cumsum; + } + +} diff --git a/src/caffe/greentea/cl_kernels/slice.cl b/src/caffe/greentea/cl_kernels/slice.cl new file mode 100644 index 00000000000..2203ffac4cb --- /dev/null +++ b/src/caffe/greentea/cl_kernels/slice.cl @@ -0,0 +1,26 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(slice,Dtype)(const int_tp nthreads, + __global const Dtype* in_data, + const int forward, const int_tp num_slices, + const int_tp slice_size, + const int_tp bottom_slice_axis, + const int_tp top_slice_axis, + const int_tp offset_slice_axis, + __global Dtype* out_data) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp total_slice_size = slice_size * top_slice_axis; + const int_tp slice_num = index / total_slice_size; + const int_tp slice_index = index % total_slice_size; + const int_tp bottom_index = slice_index + + (slice_num * bottom_slice_axis + offset_slice_axis) * slice_size; + if (forward == 1) { + out_data[index] = in_data[bottom_index]; + } else { + out_data[bottom_index] = in_data[index]; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/softmax_loss.cl b/src/caffe/greentea/cl_kernels/softmax_loss.cl new file mode 100644 index 00000000000..8974bfb70ac --- /dev/null +++ b/src/caffe/greentea/cl_kernels/softmax_loss.cl @@ -0,0 +1,59 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(softmax_loss_forward,Dtype)( + int_tp n, __global const Dtype* prob_data, __global const Dtype* label, + __global Dtype* loss, + const int_tp num, const int_tp dim, const int_tp spatial_dim, + const int has_ignore_label_, const int_tp ignore_label_, + __global Dtype* counts) { + + for (int_tp index = get_global_id(0); index < n; + index += get_global_size(0)) { + const int_tp n = index / spatial_dim; + const int_tp s = index % spatial_dim; + const int_tp label_value = (int_tp) (label[n * spatial_dim + s]); + if (has_ignore_label_ == 1 && label_value == ignore_label_) { + loss[index] = 0; + counts[index] = 0; + } else { + loss[index] = -log((Dtype)( + max((Dtype) (prob_data[n * dim + label_value * spatial_dim + s]), + (Dtype) FLT_MIN))); + counts[index] = 1; + } + } +} + +__kernel void TEMPLATE(softmax_loss_backward,Dtype)(const int_tp nthreads, + __global const Dtype* top, + __global const Dtype* label, + __global Dtype* bottom_diff, + const int_tp num, + const int_tp dim, + const int_tp spatial_dim, + const int has_ignore_label_, + const int_tp ignore_label_, + __global Dtype* counts) { + + const int_tp channels = dim / spatial_dim; + + for (int_tp index = get_global_id(0); index < nthreads; index += + get_global_size(0)) { + + const int_tp n = index / spatial_dim; + const int_tp s = index % spatial_dim; + const int_tp label_value = (int_tp) (label[n * spatial_dim + s]); + + if (has_ignore_label_ == 1 && label_value == ignore_label_) { + for (int_tp c = 0; c < channels; ++c) { + bottom_diff[n * dim + c * spatial_dim + s] = 0; + } + counts[index] = 0; + } else { + bottom_diff[n * dim + label_value * spatial_dim + s] -= 1; + counts[index] = 1; + } + } +} diff --git a/src/caffe/greentea/cl_kernels/solvers.cl b/src/caffe/greentea/cl_kernels/solvers.cl new file mode 100644 index 00000000000..5e5ca0cc57a --- /dev/null +++ b/src/caffe/greentea/cl_kernels/solvers.cl @@ -0,0 +1,77 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + +__kernel void TEMPLATE(ada_delta_update,Dtype)(int_tp N, __global Dtype* g, + __global Dtype* h, + __global Dtype* h2, + Dtype momentum, + Dtype delta, + Dtype local_rate) { + for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) { + Dtype gi = g[i]; + Dtype hi = h[i] = momentum * h[i] + (1.0 - momentum) * gi * gi; + gi = gi * sqrt((h2[i] + delta) / (hi + delta)); + h2[i] = momentum * h2[i] + (1.0 - momentum) * gi * gi; + g[i] = local_rate * gi; + } +} + +__kernel void TEMPLATE(ada_grad_update,Dtype)(int_tp N, __global Dtype* g, + __global Dtype* h, + Dtype delta, + Dtype local_rate) { + for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) { + Dtype gi = g[i]; + Dtype hi = h[i] = h[i] + gi * gi; + g[i] = local_rate * gi / (sqrt(hi) + delta); + } +} + +__kernel void TEMPLATE(adam_update,Dtype)(int_tp N, __global Dtype* g, + __global Dtype* m, + __global Dtype* v, + Dtype beta1, + Dtype beta2, + Dtype eps_hat, + Dtype corrected_local_rate) { + for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) { + Dtype gi = g[i]; + Dtype mi = m[i] = m[i] * beta1 + gi * (1 - beta1); + Dtype vi = v[i] = v[i] * beta2 + gi * gi * (1 - beta2); + g[i] = corrected_local_rate * mi / (sqrt(vi) + eps_hat); + } +} + + +__kernel void TEMPLATE(nesterov_update,Dtype)(int_tp N, __global Dtype* g, + __global Dtype* h, + Dtype momentum, + Dtype local_rate) { + for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) { + Dtype hi = h[i]; + Dtype hi_new = h[i] = momentum * hi + local_rate * g[i]; + g[i] = (1 + momentum) * hi_new - momentum * hi; + } +} + +__kernel void TEMPLATE(rms_prop_update,Dtype)(int_tp N, __global Dtype* g, + __global Dtype* h, + Dtype rms_decay, + Dtype delta, + Dtype local_rate) { + for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) { + Dtype gi = g[i]; + Dtype hi = h[i] = rms_decay * h[i] + (1 - rms_decay) * gi * gi; + g[i] = local_rate * g[i] / (sqrt(hi) + delta); + } +} + +__kernel void TEMPLATE(sgd_update,Dtype)(int_tp N, __global Dtype* g, + __global Dtype* h, + Dtype momentum, + Dtype local_rate) { + for (int_tp i = get_global_id(0); i < N; i += get_global_size(0)) { + g[i] = h[i] = momentum * h[i] + local_rate * g[i]; + } +} diff --git a/src/caffe/greentea/cl_kernels/tile.cl b/src/caffe/greentea/cl_kernels/tile.cl new file mode 100644 index 00000000000..a484efbd51f --- /dev/null +++ b/src/caffe/greentea/cl_kernels/tile.cl @@ -0,0 +1,39 @@ +#ifndef __OPENCL_VERSION__ +#include "header.cl" +#endif + + +__kernel void TEMPLATE(tile,Dtype)(const int_tp nthreads, __global const Dtype* bottom_data, + const int_tp tile_size, const int_tp num_tiles, + const int_tp bottom_tile_axis, + __global Dtype* top_data) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp d = index % tile_size; + const int_tp b = (index / tile_size / num_tiles) % bottom_tile_axis; + const int_tp n = index / tile_size / num_tiles / bottom_tile_axis; + const int_tp bottom_index = (n * bottom_tile_axis + b) * tile_size + d; + top_data[index] = bottom_data[bottom_index]; + } +} + + +__kernel void TEMPLATE(tile_backward,Dtype)(const int_tp nthreads, + __global const Dtype* top_diff, + const int_tp tile_size, + const int_tp num_tiles, + const int_tp bottom_tile_axis, + __global Dtype* bottom_diff) { + for (int_tp index = get_global_id(0); index < nthreads; + index += get_global_size(0)) { + const int_tp d = index % tile_size; + const int_tp b = (index / tile_size) % bottom_tile_axis; + const int_tp n = index / tile_size / bottom_tile_axis; + bottom_diff[index] = 0; + int_tp top_index = (n * num_tiles * bottom_tile_axis + b) * tile_size + d; + for (int_tp t = 0; t < num_tiles; ++t) { + bottom_diff[index] += top_diff[top_index]; + top_index += bottom_tile_axis * tile_size; + } + } +} diff --git a/src/caffe/greentea/greentea.cpp b/src/caffe/greentea/greentea.cpp new file mode 100644 index 00000000000..713d13c8b40 --- /dev/null +++ b/src/caffe/greentea/greentea.cpp @@ -0,0 +1,35 @@ +/* + * greentea.cpp + * + * Created on: Apr 6, 2015 + * Author: Fabian Tschopp + */ + +#include "caffe/common.hpp" +#include "caffe/greentea/greentea.hpp" +#include "caffe/util/device_alternate.hpp" + +namespace caffe { + +#ifdef USE_GREENTEA + +viennacl::ocl::handle WrapHandle(cl_mem in, + viennacl::ocl::context *ctx) { + if (in != NULL) { + viennacl::ocl::handle memhandle(in, *ctx); + memhandle.inc(); + return memhandle; + } else { + cl_int err; + cl_mem dummy = clCreateBuffer(ctx->handle().get(), CL_MEM_READ_WRITE, 0, + NULL, + &err); + viennacl::ocl::handle memhandle(dummy, *ctx); + return memhandle; + } +} + +#endif + + +} // namespace caffe diff --git a/src/caffe/greentea/greentea_im2col.cpp b/src/caffe/greentea/greentea_im2col.cpp new file mode 100644 index 00000000000..11a0e59ee3f --- /dev/null +++ b/src/caffe/greentea/greentea_im2col.cpp @@ -0,0 +1,235 @@ +/* + * greentea_im2col.cpp + * + * Created on: Apr 8, 2015 + * Author: Fabian Tschopp + */ +#include "caffe/common.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea_im2col.hpp" + +namespace caffe { + +template +void greentea_im2col_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, const cl_mem data_im, + const int_tp data_offset, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + cl_mem data_col, const int_tp data_col_off) { + int_tp height_col = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) + / stride_h + 1; + int_tp width_col = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) + / stride_w + 1; + int_tp num_kernels = channels * height_col * width_col; + + viennacl::ocl::kernel &kernel = prog->get_kernel(CL_KERNEL_SELECT("im2col")); + + viennacl::ocl::enqueue( + kernel(num_kernels, WrapHandle(data_im, ctx), data_offset, height, width, + kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w, dilation_h, + dilation_w, height_col, width_col, WrapHandle(data_col, ctx), + data_col_off), + ctx->get_queue()); +} + +// Explicit instantiation +template void greentea_im2col_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + const cl_mem data_im, + const int_tp data_offset, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + cl_mem data_col, + const int_tp data_col_off); + +template void greentea_im2col_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + const cl_mem data_im, + const int_tp data_offset, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp pad_h, + const int_tp pad_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + cl_mem data_col, + const int_tp data_col_off); + +template +void greentea_col2im_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, const cl_mem data_col, + const int_tp data_col_off, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + cl_mem data_im, const int_tp data_offset) { + int_tp height_col = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) + / stride_h + 1; + int_tp width_col = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) + / stride_w + 1; + int_tp num_kernels = channels * height * width; + viennacl::ocl::kernel &kernel = prog->get_kernel(CL_KERNEL_SELECT("col2im")); + + viennacl::ocl::enqueue( + kernel(num_kernels, WrapHandle(data_col, ctx), data_col_off, height, + width, channels, kernel_h, kernel_w, pad_h, pad_w, stride_h, + stride_w, dilation_h, dilation_w, height_col, width_col, + WrapHandle(data_im, ctx), data_offset), + ctx->get_queue()); +} + +template void greentea_col2im_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + const cl_mem data_col, + const int_tp data_col_off, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp patch_h, + const int_tp patch_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + cl_mem data_im, + const int_tp data_offset); + +template void greentea_col2im_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + const cl_mem data_col, + const int_tp data_col_off, + const int_tp channels, + const int_tp height, + const int_tp width, + const int_tp patch_h, + const int_tp patch_w, + const int_tp pad_h, + const int_tp pad_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + cl_mem data_im, + const int_tp data_offset); + +template +void greentea_im2col_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, cl_mem data_im, + const int_tp data_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, const int_tp num_kernels, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, cl_mem stride, + cl_mem dilation, cl_mem data_col, + const int_tp data_col_off) { + viennacl::ocl::kernel &kernel = prog->get_kernel( + CL_KERNEL_SELECT("im2col_nd")); + + viennacl::ocl::enqueue( + kernel(num_kernels, num_spatial_axes, channel_axis, + WrapHandle(data_im, ctx), data_off, WrapHandle(im_shape, ctx), + WrapHandle(col_shape, ctx), WrapHandle(kernel_shape, ctx), + WrapHandle(pad, ctx), WrapHandle(stride, ctx), + WrapHandle(dilation, ctx), WrapHandle(data_col, ctx), + data_col_off), + ctx->get_queue()); +} + +// Explicit instantiation +template void greentea_im2col_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + cl_mem data_im, + const int_tp data_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, + const int_tp num_kernels, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, + cl_mem stride, cl_mem dilation, + cl_mem data_col, + const int_tp data_col_off); + +template void greentea_im2col_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + cl_mem data_im, + const int_tp data_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, + const int_tp num_kernels, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, + cl_mem stride, cl_mem dilation, + cl_mem data_col, + const int_tp data_col_off); + +template +void greentea_col2im_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, cl_mem data_col, + const int_tp data_col_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, const int_tp im_size, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, cl_mem stride, + cl_mem dilation, cl_mem data_im, + const int_tp data_im_off) { + viennacl::ocl::kernel &kernel = prog->get_kernel( + CL_KERNEL_SELECT("col2im_nd")); + + viennacl::ocl::enqueue( + kernel(im_size, num_spatial_axes, channel_axis, + WrapHandle(data_col, ctx), data_col_off, + WrapHandle(im_shape, ctx), + WrapHandle(col_shape, ctx), + WrapHandle(kernel_shape, ctx), WrapHandle(pad, ctx), + WrapHandle(stride, ctx), WrapHandle(dilation, ctx), + WrapHandle(data_im, ctx), data_im_off), + ctx->get_queue()); +} + +// Explicit instantiation +template void greentea_col2im_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + cl_mem data_col, + const int_tp data_col_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, + const int_tp im_size, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, + cl_mem stride, cl_mem dilation, + cl_mem data_im, int_tp data_off); + +template void greentea_col2im_nd_gpu(viennacl::ocl::program *prog, + viennacl::ocl::context *ctx, + cl_mem data_col, + const int_tp data_col_off, + const int_tp num_spatial_axes, + const int_tp channel_axis, + const int_tp im_size, + cl_mem im_shape, cl_mem col_shape, + cl_mem kernel_shape, cl_mem pad, + cl_mem stride, cl_mem dilation, + cl_mem data_im, int_tp data_off); + +} // namespace caffe +#endif diff --git a/src/caffe/greentea/greentea_math_functions.cpp b/src/caffe/greentea/greentea_math_functions.cpp new file mode 100644 index 00000000000..62b24ddc026 --- /dev/null +++ b/src/caffe/greentea/greentea_math_functions.cpp @@ -0,0 +1,1055 @@ +/* + * greentea_math_functions.cpp + * + * Created on: Apr 6, 2015 + * Author: Fabian Tschopp + */ + +#include "caffe/common.hpp" +#include "caffe/device.hpp" + +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "viennacl/backend/opencl.hpp" +#include "viennacl/ocl/backend.hpp" +#include "viennacl/ocl/context.hpp" +#include "viennacl/ocl/device.hpp" +#include "viennacl/ocl/platform.hpp" + +#include "caffe/util/math_functions.hpp" + +#ifdef USE_CLBLAS +#include +#else +#include "viennacl/linalg/inner_prod.hpp" +#include "viennacl/linalg/norm_1.hpp" +#include "viennacl/linalg/norm_2.hpp" +#include "viennacl/linalg/norm_inf.hpp" +#include "viennacl/linalg/prod.hpp" +#include "viennacl/matrix.hpp" +#include "viennacl/scalar.hpp" +#include "viennacl/vector.hpp" +#endif + +// ViennaCL 1.5.1 compability fix +#ifndef VIENNACL_MINOR_VERSION +#define VIENNACL_MINOR_VERSION 5 +#endif + +#if VIENNACL_MINOR_VERSION > 5 +#define VCL_ROW_MAJOR , true +#define VCL_COL_MAJOR , false +#else +#define VCL_ROW_MAJOR +#define VCL_COL_MAJOR +#endif + +namespace caffe { + +void greentea_memset(const int_tp ctx_id, const uint_tp N, const int_tp alpha, + cl_mem X, const int_tp offX) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + // OpenCL Version >= 1.2 approach + // clEnqueueFillBuffer(ctx.get_queue().handle().get(), + // X, &alpha, sizeof(int_tp), + // offX, N, 0, NULL, NULL); + // OpenCL Version < 1.2 fallback + typedef float Dtype; + viennacl::ocl::kernel &oclk_fill = program.get_kernel( + CL_KERNEL_SELECT("fillbuffer")); + viennacl::ocl::enqueue( + oclk_fill(static_cast(N), static_cast(alpha), + WrapHandle(X, &ctx), offX), + ctx.get_queue()); +} + +// Copy from OpenCL buffer to main memory +void greentea_gpu_memcpy(const uint_tp N, const cl_mem X, const int_tp offX, + void *Y, viennacl::ocl::context *ctx) { + if (Y != NULL) { + clEnqueueReadBuffer(ctx->get_queue().handle().get(), X, CL_TRUE, offX, N, Y, + 0, + NULL, + NULL); + } +} + +// Copy from main memory to OpenCL buffer +void greentea_gpu_memcpy(const uint_tp N, const void* X, cl_mem Y, + const int_tp offY, viennacl::ocl::context *ctx) { + if (X != NULL) { + clEnqueueWriteBuffer(ctx->get_queue().handle().get(), Y, + CL_TRUE, + offY, N, X, 0, NULL, NULL); + } +} + +// Copy from OpenCL to OpenCL buffer +void greentea_gpu_memcpy(const uint_tp N, const cl_mem X, const int_tp offX, + cl_mem Y, const int_tp offY, + viennacl::ocl::context *ctx) { + clEnqueueCopyBuffer(ctx->get_queue().handle().get(), X, Y, offX, offY, N, 0, + NULL, + NULL); +} + +template +void greentea_copy(const int_tp N, const cl_mem X, const int_tp offX, Dtype* Y, + viennacl::ocl::context *ctx) { + greentea_gpu_memcpy(sizeof(Dtype) * N, X, offX * sizeof(Dtype), Y, ctx); +} + +template +void greentea_copy(const int_tp N, const Dtype* X, cl_mem Y, const int_tp offY, + viennacl::ocl::context *ctx) { + greentea_gpu_memcpy(sizeof(Dtype) * N, X, Y, offY * sizeof(Dtype), ctx); +} + +// Copy from OpenCL buffer to OpenCL buffer +template +void greentea_copy(const int_tp N, const cl_mem X, const int_tp offX, cl_mem Y, + const int_tp offY, viennacl::ocl::context *ctx) { + greentea_gpu_memcpy(sizeof(Dtype) * N, X, offX * sizeof(Dtype), Y, + offY * sizeof(Dtype), ctx); +} + +// Explicit instantiations +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, + int_tp* Y, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, uint_tp* Y, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, float* Y, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, double* Y, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const int_tp* X, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const uint_tp* X, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const float* X, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const double* X, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); +template void greentea_copy(const int_tp N, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY, + viennacl::ocl::context *ctx); + +template +void greentea_gpu_gemm(const int_tp ctx_id, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const int_tp M, + const int_tp N, const int_tp K, const Dtype alpha, + const cl_mem A, const int_tp offA, const cl_mem B, + const int_tp offB, const Dtype beta, cl_mem C, + const int_tp offC) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* Aptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), A, true, CL_MAP_READ, + sizeof(Dtype) * offA, sizeof(Dtype) * M * K, 0, NULL, NULL, NULL)); + Dtype* Bptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), B, true, CL_MAP_READ, + sizeof(Dtype) * offB, sizeof(Dtype) * N * K, 0, NULL, NULL, NULL)); + Dtype* Cptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), C, true, CL_MAP_READ | CL_MAP_WRITE, + sizeof(Dtype) * offC, sizeof(Dtype) * M * N, 0, NULL, NULL, NULL)); + + caffe_cpu_gemm(TransA, TransB, M, N, K, alpha, Aptr, Bptr, beta, + Cptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), A, Aptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), B, Bptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), C, Cptr, 0, NULL, + NULL); + } else { + int_tp lda = (TransA == CblasNoTrans) ? K : M; + int_tp ldb = (TransB == CblasNoTrans) ? N : K; + int_tp ldc = N; + +#ifndef USE_CLBLAS + + typedef typename viennacl::matrix_base::size_type size_type; + typedef typename viennacl::matrix_base::size_type difference_type; + + size_type A_size1 = static_cast((TransA == CblasTrans) ? K : M); + size_type A_size2 = static_cast((TransA == CblasTrans) ? M : K); + + size_type B_size1 = static_cast((TransB == CblasTrans) ? N : K); + size_type B_size2 = static_cast((TransB == CblasTrans) ? K : N); + + viennacl::matrix_base matA(A, ctx, A_size1, + size_type(0), + difference_type(1), + size_type(M), A_size2, + size_type(offA), + difference_type(1), + size_type(lda) + VCL_ROW_MAJOR); + + viennacl::matrix_base matB(B, ctx, B_size1, + size_type(0), + difference_type(1), + size_type(K), B_size2, + size_type(offB), + difference_type(1), + size_type(ldb) + VCL_ROW_MAJOR); + + viennacl::matrix_base matC(C, ctx, size_type(M), + size_type(0), + difference_type(1), + size_type(M), + size_type(N), + size_type(offC), + difference_type(1), + size_type(ldc) + VCL_ROW_MAJOR); + + if (TransA == CblasTrans && TransB == CblasTrans) + viennacl::linalg::prod_impl(viennacl::trans(matA), viennacl::trans(matB), + matC, alpha, beta); + else if (TransA == CblasTrans && TransB == CblasNoTrans) + viennacl::linalg::prod_impl(viennacl::trans(matA), matB, matC, alpha, + beta); + else if (TransA == CblasNoTrans && TransB == CblasTrans) + viennacl::linalg::prod_impl(matA, viennacl::trans(matB), matC, alpha, + beta); + else if (TransA == CblasNoTrans && TransB == CblasNoTrans) + viennacl::linalg::prod_impl(matA, matB, matC, alpha, beta); + +#else + clblasOrder clOrder = clblasRowMajor; + clblasTranspose clTransA = + (TransA == CblasNoTrans) ? clblasNoTrans : clblasTrans; + clblasTranspose clTransB = + (TransB == CblasNoTrans) ? clblasNoTrans : clblasTrans; + + cl_command_queue queue = ctx.get_queue().handle().get(); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK( + clblasSgemm(clOrder, clTransA, clTransB, + M, N, K, alpha, A, offA, lda, B, offB, ldb, beta, + C, offC, ldc, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK( + clblasDgemm(clOrder, clTransA, clTransB, + M, N, K, alpha, A, offA, lda, B, offB, ldb, beta, + C, offC, ldc, 1, &queue, 0, NULL, NULL)); + } +#endif + } +} + +template void greentea_gpu_gemm(const int_tp ctx_id, + const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, + const int_tp M, const int_tp N, + const int_tp K, const float alpha, + const cl_mem A, const int_tp offA, + const cl_mem B, const int_tp offB, + const float beta, cl_mem C, + const int_tp offC); +template void greentea_gpu_gemm(const int_tp ctx_id, + const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, + const int_tp M, const int_tp N, + const int_tp K, const double alpha, + const cl_mem A, const int_tp offA, + const cl_mem B, const int_tp offB, + const double beta, cl_mem C, + const int_tp offC); + +template +void greentea_gpu_gemv(const int_tp ctx_id, const CBLAS_TRANSPOSE TransA, + const int_tp M, const int_tp N, const Dtype alpha, + const cl_mem A, const int_tp offA, const cl_mem x, + const int_tp offx, const Dtype beta, cl_mem y, + const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* Aptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), A, true, CL_MAP_READ, + sizeof(Dtype) * offA, sizeof(Dtype) * M * N, 0, NULL, NULL, NULL)); + Dtype* xptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), x, true, CL_MAP_READ, + sizeof(Dtype) * offx, sizeof(Dtype) * (TransA == CblasTrans) ? M : N, 0, + NULL, + NULL, NULL)); + Dtype* yptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), y, true, CL_MAP_READ | CL_MAP_WRITE, + sizeof(Dtype) * offy, sizeof(Dtype) * (TransA == CblasTrans) ? N : M, 0, + NULL, + NULL, NULL)); + + caffe_cpu_gemv(TransA, M, N, alpha, Aptr, xptr, beta, yptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), A, Aptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), x, xptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), y, yptr, 0, NULL, + NULL); + } else { +#ifndef USE_CLBLAS + + typedef typename viennacl::vector_base::size_type size_type; + typedef typename viennacl::vector_base::size_type difference_type; + + viennacl::vector_base v1( + x, size_type((TransA == CblasTrans) ? M : N), size_type(offx), + difference_type(1), ctx); + viennacl::vector_base v2( + y, size_type((TransA == CblasTrans) ? N : M), size_type(offy), + difference_type(1), ctx); + viennacl::matrix_base mat(A, ctx, size_type(M), + size_type(0), + difference_type(1), + size_type(M), + size_type(N), + size_type(offA), + difference_type(1), + size_type(N) + VCL_ROW_MAJOR); + v2 *= beta; + if (TransA == CblasTrans) + v2 += alpha * viennacl::linalg::prod(viennacl::trans(mat), v1); + else + v2 += alpha * viennacl::linalg::prod(mat, v1); + +#else + clblasTranspose clTransA = + (TransA == CblasNoTrans) ? clblasNoTrans : clblasTrans; + + cl_command_queue queue = ctx.get_queue().handle().get(); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK( + clblasSgemv(clblasRowMajor, + clTransA, M, N, alpha, A, offA, N, x, offx, 1, + beta, y, offy, 1, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK( + clblasDgemv(clblasRowMajor, + clTransA, M, N, alpha, A, offA, N, x, offx, 1, + beta, y, offy, 1, 1, &queue, 0, NULL, NULL)); + } +#endif + } +} + +template void greentea_gpu_gemv(const int_tp ctx_id, + const CBLAS_TRANSPOSE TransA, + const int_tp M, const int_tp N, + const float alpha, const cl_mem A, + const int_tp offA, const cl_mem x, + const int_tp offx, const float beta, + cl_mem y, const int_tp offy); +template void greentea_gpu_gemv(const int_tp ctx_id, + const CBLAS_TRANSPOSE TransA, + const int_tp M, const int_tp N, + const double alpha, const cl_mem A, + const int_tp offA, const cl_mem x, + const int_tp offx, const double beta, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_axpy(const int_tp ctx_id, const int_tp N, const Dtype alpha, + const cl_mem X, const int_tp offX, cl_mem Y, + const int_tp offY) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* Xptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), X, true, CL_MAP_READ, + sizeof(Dtype) * offX, sizeof(Dtype) * N, 0, NULL, NULL, NULL)); + Dtype* Yptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), Y, true, CL_MAP_WRITE, + sizeof(Dtype) * offY, sizeof(Dtype) * N, 0, NULL, NULL, NULL)); + + caffe_axpy(N, alpha, Xptr, Yptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), X, Xptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), Y, Yptr, 0, NULL, + NULL); + } else { +#ifndef USE_CLBLAS + + typedef typename viennacl::vector_base::size_type size_type; + typedef typename viennacl::vector_base::size_type difference_type; + + viennacl::vector_base v1(X, size_type(N), + size_type(offX), + difference_type(1), ctx); + viennacl::vector_base v2(Y, size_type(N), + size_type(offY), + difference_type(1), ctx); + + v2 += alpha * v1; + +#else + cl_command_queue queue = ctx.get_queue().handle().get(); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK( + clblasSaxpy(N, alpha, X, offX, + 1, Y, offY, 1, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK( + clblasDaxpy(N, alpha, X, offX, + 1, Y, offY, 1, 1, &queue, 0, NULL, NULL)); + } +#endif + } +} + +template void greentea_gpu_axpy(const int_tp ctx_id, const int_tp N, + const float alpha, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY); +template void greentea_gpu_axpy(const int_tp ctx_id, const int_tp N, + const double alpha, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY); + +template +void greentea_gpu_mul(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_mul = program.get_kernel(CL_KERNEL_SELECT("mul")); + viennacl::ocl::enqueue( + oclk_mul(N, WrapHandle(a, &ctx), offa, WrapHandle(b, &ctx), offb, + WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_mul(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); +template void greentea_gpu_mul(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_div(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_div = program.get_kernel(CL_KERNEL_SELECT("div")); + viennacl::ocl::enqueue( + oclk_div(N, WrapHandle(a, &ctx), offa, WrapHandle(b, &ctx), offb, + WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_div(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); +template void greentea_gpu_div(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_scal(const int_tp ctx_id, const int_tp N, const Dtype alpha, + cl_mem x, int_tp offx) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* xptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), x, true, CL_MAP_READ | CL_MAP_WRITE, + sizeof(Dtype) * offx, sizeof(Dtype) * N, 0, NULL, NULL, NULL)); + + caffe_scal(N, alpha, xptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), x, xptr, 0, NULL, + NULL); + } else { +#ifndef USE_CLBLAS + + typedef typename viennacl::vector_base::size_type size_type; + typedef typename viennacl::vector_base::size_type difference_type; + + viennacl::vector_base v1(x, size_type(N), + size_type(offx), + difference_type(1), ctx); + + v1 *= alpha; + +#else + cl_command_queue queue = ctx.get_queue().handle().get(); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK(clblasSscal(N, alpha, x, offx, + 1, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK(clblasDscal(N, alpha, x, offx, + 1, 1, &queue, 0, NULL, NULL)); + } +#endif + } +} + +template void greentea_gpu_scal(const int_tp ctx_id, const int_tp N, + const float alpha, cl_mem x, + const int_tp offx); +template void greentea_gpu_scal(const int_tp ctx_id, const int_tp N, + const double alpha, cl_mem x, + const int_tp offx); + +template +void greentea_gpu_axpby(const int_tp ctx_id, const int_tp N, const Dtype alpha, + const cl_mem X, const int_tp offX, const Dtype beta, + cl_mem Y, const int_tp offY) { + greentea_gpu_scal(ctx_id, N, beta, Y, offY); + greentea_gpu_axpy(ctx_id, N, alpha, X, offX, Y, offY); +} + +template void greentea_gpu_axpby(const int_tp ctx_id, const int_tp N, + const float alpha, const cl_mem X, + const int_tp offX, const float beta, + cl_mem Y, const int_tp offY); + +template void greentea_gpu_axpby(const int_tp ctx_id, const int_tp N, + const double alpha, const cl_mem X, + const int_tp offX, const double beta, + cl_mem Y, const int_tp offY); + +template +void greentea_gpu_dot(const int_tp ctx_id, const int_tp n, const cl_mem X, + const int_tp offX, const cl_mem Y, const int_tp offY, + Dtype* out) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* Xptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), X, true, CL_MAP_READ, + sizeof(Dtype) * offX, sizeof(Dtype) * n, 0, NULL, NULL, NULL)); + Dtype* Yptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), Y, true, CL_MAP_READ, + sizeof(Dtype) * offY, sizeof(Dtype) * n, 0, NULL, NULL, NULL)); + + *out = caffe_cpu_dot(n, Xptr, Yptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), X, Xptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), Y, Yptr, 0, NULL, + NULL); + + } else { +#ifndef USE_CLBLAS + typedef typename viennacl::vector_base::size_type size_type; + typedef typename viennacl::vector_base::size_type difference_type; + + viennacl::vector_base v1(X, size_type(n), + size_type(offX), + difference_type(1), ctx); + viennacl::vector_base v2(Y, size_type(n), + size_type(offY), + difference_type(1), ctx); + + *out = viennacl::linalg::inner_prod(v1, v2); + +#else + cl_command_queue queue = ctx.get_queue().handle().get(); + + cl_int err; + cl_mem gpuout = clCreateBuffer(ctx.handle().get(), CL_MEM_READ_WRITE, + sizeof(Dtype), NULL, &err); + cl_mem scratch = clCreateBuffer(ctx.handle().get(), CL_MEM_READ_WRITE, + n * sizeof(Dtype), NULL, &err); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK( + clblasSdot(n, gpuout, 0, X, offX, 1, Y, + offY, 1, scratch, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK( + clblasDdot(n, gpuout, 0, X, offX, 1, Y, + offY, 1, scratch, 1, &queue, 0, NULL, NULL)); + } + + greentea_gpu_memcpy(sizeof(Dtype), gpuout, 0, out, &ctx); + + clReleaseMemObject(gpuout); + clReleaseMemObject(scratch); + +#endif + } +} + +template void greentea_gpu_dot(const int_tp ctx_id, const int_tp n, + const cl_mem X, const int_tp offX, + const cl_mem Y, const int_tp offY, + float* out); +template void greentea_gpu_dot(const int_tp ctx_id, const int_tp n, + const cl_mem X, const int_tp offX, + const cl_mem Y, const int_tp offY, + double* out); + +template +void greentea_gpu_asum(const int_tp ctx_id, const int_tp n, const cl_mem X, + const int_tp offX, Dtype* Y) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* Xptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), X, true, CL_MAP_READ, + sizeof(Dtype) * offX, sizeof(Dtype) * n, 0, NULL, NULL, NULL)); + + *Y = caffe_cpu_asum(n, Xptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), X, Xptr, 0, NULL, + NULL); + } else { +#ifndef USE_CLBLAS + + typedef typename viennacl::vector_base::size_type size_type; + typedef typename viennacl::vector_base::size_type difference_type; + + viennacl::vector_base v1(X, size_type(n), + size_type(offX), + difference_type(1), ctx); + + *Y = viennacl::linalg::norm_1(v1); + +#else + cl_command_queue queue = ctx.get_queue().handle().get(); + + cl_int err; + cl_mem gpuout = clCreateBuffer(ctx.handle().get(), CL_MEM_READ_WRITE, + sizeof(Dtype), NULL, &err); + cl_mem scratch = clCreateBuffer(ctx.handle().get(), CL_MEM_READ_WRITE, + n * sizeof(Dtype), NULL, &err); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK( + clblasSasum(n, gpuout, 0, X, offX, 1, + scratch, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK( + clblasDasum(n, gpuout, 0, X, offX, 1, + scratch, 1, &queue, 0, NULL, NULL)); + } + + greentea_gpu_memcpy(sizeof(Dtype), gpuout, 0, Y, &ctx); + + clReleaseMemObject(gpuout); + clReleaseMemObject(scratch); +#endif + } +} + +template void greentea_gpu_asum(const int_tp ctx_id, const int_tp n, + const cl_mem X, const int_tp offX, + float* Y); +template void greentea_gpu_asum(const int_tp ctx_id, const int_tp n, + const cl_mem X, const int_tp offX, + double* Y); + +template +void greentea_gpu_scale(const int_tp ctx_id, const int_tp n, const Dtype alpha, + const cl_mem X, const int_tp offX, cl_mem Y, + const int_tp offY) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + Dtype* Xptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), X, true, CL_MAP_READ, + sizeof(Dtype) * offX, sizeof(Dtype) * n, 0, NULL, NULL, NULL)); + Dtype* Yptr = reinterpret_cast(clEnqueueMapBuffer( + ctx.get_queue().handle().get(), Y, true, CL_MAP_WRITE, + sizeof(Dtype) * offY, sizeof(Dtype) * n, 0, NULL, NULL, NULL)); + + caffe_cpu_scale(n, alpha, Xptr, Yptr); + + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), X, Xptr, 0, NULL, + NULL); + clEnqueueUnmapMemObject(ctx.get_queue().handle().get(), Y, Yptr, 0, NULL, + NULL); + } else { +#ifndef USE_CLBLAS + + typedef typename viennacl::vector_base::size_type size_type; + typedef typename viennacl::vector_base::size_type difference_type; + + viennacl::vector_base v1(X, size_type(n), + size_type(offX), + difference_type(1), ctx); + viennacl::vector_base v2(Y, size_type(n), + size_type(offY), + difference_type(1), ctx); + + v2 = v1 * alpha; + +#else + + viennacl::ocl::context ctx = viennacl::ocl::get_context(ctx_id); + cl_command_queue queue = ctx.get_queue().handle().get(); + + if (std::is_same::value) { + GREENTEA_CL_BLAS_CHECK( + clblasScopy(n, X, offX, 1, Y, offY, 1, 1, &queue, 0, NULL, NULL)); + GREENTEA_CL_BLAS_CHECK( + clblasSscal(n, alpha, Y, offY, 1, 1, &queue, 0, NULL, NULL)); + } else { + GREENTEA_CL_BLAS_CHECK( + clblasDcopy(n, X, offX, 1, Y, offY, 1, 1, &queue, 0, NULL, NULL)); + GREENTEA_CL_BLAS_CHECK( + clblasDscal(n, alpha, Y, offY, 1, 1, &queue, 0, NULL, NULL)); + } +#endif + } +} + +template void greentea_gpu_scale(const int_tp ctx_id, const int_tp n, + const float alpha, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY); + +template void greentea_gpu_scale(const int_tp ctx_id, const int_tp n, + const double alpha, const cl_mem X, + const int_tp offX, cl_mem Y, + const int_tp offY); + +template +void greentea_gpu_set(const int_tp ctx_id, const int_tp N, const Dtype alpha, + cl_mem Y, const int_tp offY) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + // OpenCL Version >= 1.2 approach + // clEnqueueFillBuffer(ctx.get_queue().handle().get(), + // Y, &alpha, sizeof(Dtype), + // offY, N, 0, NULL, NULL); + + // OpenCL Version < 1.2 fallback + viennacl::ocl::kernel &oclk_fill = program.get_kernel( + CL_KERNEL_SELECT("fill")); + viennacl::ocl::enqueue(oclk_fill(N, alpha, WrapHandle(Y, &ctx), offY), + ctx.get_queue()); +} + +template void greentea_gpu_set(const int_tp ctx_id, const int_tp N, + const int_tp alpha, cl_mem Y, + const int_tp offY); +template void greentea_gpu_set(const int_tp ctx_id, const int_tp N, + const float alpha, cl_mem Y, + const int_tp offY); +template void greentea_gpu_set(const int_tp ctx_id, const int_tp N, + const double alpha, cl_mem Y, + const int_tp offY); + +template +void greentea_gpu_add_scalar(const int_tp ctx_id, const int_tp N, + const Dtype alpha, cl_mem Y, const int_tp offY) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_add_scalar = program.get_kernel( + CL_KERNEL_SELECT("add_scalar")); + viennacl::ocl::enqueue(oclk_add_scalar(N, alpha, WrapHandle(Y, &ctx), offY), + ctx.get_queue()); +} + +template void greentea_gpu_add_scalar(const int_tp ctx_id, + const int_tp N, const float alpha, + cl_mem Y, const int_tp offY); +template void greentea_gpu_add_scalar(const int_tp ctx_id, + const int_tp N, + const double alpha, cl_mem Y, + const int_tp offY); + +template +void greentea_gpu_add(const int_tp ctx_id, const int_tp n, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_add = program.get_kernel(CL_KERNEL_SELECT("add")); + viennacl::ocl::enqueue( + oclk_add(n, WrapHandle(a, &ctx), offa, WrapHandle(b, &ctx), offb, + WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_add(const int_tp ctx_id, const int_tp n, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); +template void greentea_gpu_add(const int_tp ctx_id, const int_tp n, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_sub(const int_tp ctx_id, const int_tp n, const cl_mem a, + const int_tp offa, const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_sub = program.get_kernel(CL_KERNEL_SELECT("sub")); + viennacl::ocl::enqueue( + oclk_sub(n, WrapHandle(a, &ctx), offa, WrapHandle(b, &ctx), offb, + WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_sub(const int_tp ctx_id, const int_tp n, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); +template void greentea_gpu_sub(const int_tp ctx_id, const int_tp n, + const cl_mem a, const int_tp offa, + const cl_mem b, const int_tp offb, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_abs(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_abs = program.get_kernel(CL_KERNEL_SELECT("abs")); + viennacl::ocl::enqueue( + oclk_abs(N, WrapHandle(a, &ctx), offa, WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_abs(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + cl_mem y, const int_tp offy); +template void greentea_gpu_abs(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_exp(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_exp = program.get_kernel(CL_KERNEL_SELECT("exp")); + viennacl::ocl::enqueue( + oclk_exp(N, WrapHandle(a, &ctx), offa, WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_exp(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + cl_mem y, const int_tp offy); +template void greentea_gpu_exp(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_powx(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, const Dtype alpha, cl_mem y, + const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_powx = program.get_kernel( + CL_KERNEL_SELECT("powx")); + viennacl::ocl::enqueue( + oclk_powx(N, WrapHandle(a, &ctx), offa, alpha, WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_powx(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + const float alpha, cl_mem y, + const int_tp offy); +template void greentea_gpu_powx(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + const double alpha, cl_mem y, + const int_tp offy); + +template +void greentea_gpu_log(const int_tp ctx_id, const int_tp N, const cl_mem a, + const int_tp offa, cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_log = program.get_kernel(CL_KERNEL_SELECT("log")); + viennacl::ocl::enqueue( + oclk_log(N, WrapHandle(a, &ctx), offa, WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_log(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + cl_mem y, const int_tp offy); +template void greentea_gpu_log(const int_tp ctx_id, const int_tp N, + const cl_mem a, const int_tp offa, + cl_mem y, const int_tp offy); + +template +void greentea_gpu_sign(const int_tp ctx_id, const int_tp n, const cl_mem x, +int_tp offx, + cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_sign = program.get_kernel( + CL_KERNEL_SELECT("sign")); + viennacl::ocl::enqueue( + oclk_sign(n, WrapHandle(x, &ctx), offx, WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_sign(const int_tp ctx_id, const int_tp n, + const cl_mem x, int_tp offx, cl_mem y, + const int_tp offy); +template void greentea_gpu_sign(const int_tp ctx_id, const int_tp n, + const cl_mem x, int_tp offx, cl_mem y, + const int_tp offy); + +template +void greentea_gpu_sgnbit(const int_tp ctx_id, const int_tp n, const cl_mem x, +int_tp offx, + cl_mem y, const int_tp offy) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + viennacl::ocl::program &program = (Caffe::Get().GetDevice(ctx_id, false)) + ->program(); + + viennacl::ocl::kernel &oclk_sgnbit = program.get_kernel( + CL_KERNEL_SELECT("sgnbit")); + viennacl::ocl::enqueue( + oclk_sgnbit(n, WrapHandle(x, &ctx), offx, WrapHandle(y, &ctx), offy), + ctx.get_queue()); +} + +template void greentea_gpu_sgnbit(const int_tp ctx_id, const int_tp n, + const cl_mem x, int_tp offx, cl_mem y, + const int_tp offy); +template void greentea_gpu_sgnbit(const int_tp ctx_id, const int_tp n, + const cl_mem x, int_tp offx, cl_mem y, + const int_tp offy); + +void greentea_gpu_rng_uniform(const int_tp ctx_id, const int_tp n, cl_mem r, +int_tp offr) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + std::vector random(n); //NOLINT + caffe_rng_uniform(n, &random[0]); + greentea_gpu_memcpy(sizeof(uint_tp) * n, &random[0], r, offr, &ctx); +} + +template +void greentea_gpu_rng_uniform(const int_tp ctx_id, const int_tp n, + const Dtype a, const Dtype b, cl_mem r, + const int_tp offr) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + std::vector random(n); // NOLINT + caffe_rng_uniform(n, a, b, &random[0]); + greentea_gpu_memcpy(sizeof(Dtype) * n, &random[0], r, offr, &ctx); +} + +template void greentea_gpu_rng_uniform(const int_tp ctx_id, + const int_tp n, const float a, + const float b, cl_mem r, + const int_tp offr); +template void greentea_gpu_rng_uniform(const int_tp ctx_id, + const int_tp n, const double a, + const double b, cl_mem r, + const int_tp offr); + +template +void greentea_gpu_rng_gaussian(const int_tp ctx_id, const int_tp n, + const Dtype mu, const Dtype sigma, cl_mem r, + const int_tp offr) { + viennacl::ocl::context &ctx = viennacl::ocl::get_context(ctx_id); + std::vector random(n); // NOLINT + caffe_rng_gaussian(n, mu, sigma, &random[0]); + greentea_gpu_memcpy(sizeof(Dtype) * n, &random[0], r, offr, &ctx); +} + +template void greentea_gpu_rng_gaussian(const int_tp ctx_id, + const int_tp n, const float mu, + const float sigma, cl_mem r, + const int_tp offr); + +template void greentea_gpu_rng_gaussian(const int_tp ctx_id, + const int_tp n, const double mu, + const double sigma, cl_mem r, + const int_tp offr); + +} // namespace caffe +#endif diff --git a/src/caffe/internal_thread.cpp b/src/caffe/internal_thread.cpp index 104884e0295..c705e5ea666 100644 --- a/src/caffe/internal_thread.cpp +++ b/src/caffe/internal_thread.cpp @@ -18,33 +18,31 @@ bool InternalThread::must_stop() { return thread_ && thread_->interruption_requested(); } -void InternalThread::StartInternalThread() { +void InternalThread::StartInternalThread(device* device_context) { CHECK(!is_started()) << "Threads should persist and not be restarted."; - int device = 0; -#ifndef CPU_ONLY - CUDA_CHECK(cudaGetDevice(&device)); -#endif + thread_device_ = device_context; + Caffe::Brew mode = Caffe::mode(); - int rand_seed = caffe_rng_rand(); - int solver_count = Caffe::solver_count(); + int_tp rand_seed = caffe_rng_rand(); + int_tp solver_count = Caffe::solver_count(); bool root_solver = Caffe::root_solver(); try { - thread_.reset(new boost::thread(&InternalThread::entry, this, device, mode, - rand_seed, solver_count, root_solver)); + thread_.reset( + new boost::thread(&InternalThread::entry, this, thread_device_, + mode, rand_seed, solver_count, root_solver)); } catch (std::exception& e) { - LOG(FATAL) << "Thread exception: " << e.what(); + LOG(FATAL)<< "Thread exception: " << e.what(); } } -void InternalThread::entry(int device, Caffe::Brew mode, int rand_seed, - int solver_count, bool root_solver) { -#ifndef CPU_ONLY - CUDA_CHECK(cudaSetDevice(device)); -#endif +void InternalThread::entry(device* device_context, Caffe::Brew mode, + int_tp rand_seed, + int_tp solver_count, bool root_solver) { + Caffe::SelectDevice(device_context); Caffe::set_mode(mode); - Caffe::set_random_seed(rand_seed); + Caffe::set_random_seed(rand_seed, thread_device_); Caffe::set_solver_count(solver_count); Caffe::set_root_solver(root_solver); diff --git a/src/caffe/layer_factory.cpp b/src/caffe/layer_factory.cpp index e967bd6181c..8d449613713 100644 --- a/src/caffe/layer_factory.cpp +++ b/src/caffe/layer_factory.cpp @@ -33,47 +33,56 @@ namespace caffe { -// Get convolution layer according to engine. -template -shared_ptr > GetConvolutionLayer( - const LayerParameter& param) { - ConvolutionParameter conv_param = param.convolution_param(); - ConvolutionParameter_Engine engine = conv_param.engine(); -#ifdef USE_CUDNN - bool use_dilation = false; - for (int i = 0; i < conv_param.dilation_size(); ++i) { - if (conv_param.dilation(i) > 1) { - use_dilation = true; +bool checkConvolutionDilated(ConvolutionParameter param) { + for (int i = 0; i < param.dilation_size(); ++i) { + if (param.dilation(i) > 1) { + return true; } } -#endif + return false; +} + +bool checkPoolingDilated(PoolingParameter param) { + for (int i = 0; i < param.dilation_size(); ++i) { + if (param.dilation(i) > 1) { + return true; + } + } + return false; +} + +// Get convolution layer according to engine. +template +shared_ptr > GetConvolutionLayer(const LayerParameter& param) { + ConvolutionParameter_Engine engine = param.convolution_param().engine(); if (engine == ConvolutionParameter_Engine_DEFAULT) { engine = ConvolutionParameter_Engine_CAFFE; #ifdef USE_CUDNN - if (!use_dilation) { - engine = ConvolutionParameter_Engine_CUDNN; - } + engine = ConvolutionParameter_Engine_CUDNN; #endif } - if (engine == ConvolutionParameter_Engine_CAFFE) { + if (engine == ConvolutionParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL + || checkConvolutionDilated(param.convolution_param())) { return shared_ptr >(new ConvolutionLayer(param)); #ifdef USE_CUDNN } else if (engine == ConvolutionParameter_Engine_CUDNN) { - if (use_dilation) { + if (checkConvolutionDilated(param.convolution_param())) { LOG(FATAL) << "CuDNN doesn't support the dilated convolution at Layer " << param.name(); } return shared_ptr >(new CuDNNConvolutionLayer(param)); #endif } else { - LOG(FATAL) << "Layer " << param.name() << " has unknown engine."; + LOG(FATAL)<< "Layer " << param.name() << " has unknown engine."; } } REGISTER_LAYER_CREATOR(Convolution, GetConvolutionLayer); + // Get pooling layer according to engine. -template +template shared_ptr > GetPoolingLayer(const LayerParameter& param) { PoolingParameter_Engine engine = param.pooling_param().engine(); if (engine == PoolingParameter_Engine_DEFAULT) { @@ -82,7 +91,9 @@ shared_ptr > GetPoolingLayer(const LayerParameter& param) { engine = PoolingParameter_Engine_CUDNN; #endif } - if (engine == PoolingParameter_Engine_CAFFE) { + if (engine == PoolingParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL + || checkPoolingDilated(param.pooling_param())) { return shared_ptr >(new PoolingLayer(param)); #ifdef USE_CUDNN } else if (engine == PoolingParameter_Engine_CUDNN) { @@ -91,6 +102,10 @@ shared_ptr > GetPoolingLayer(const LayerParameter& param) { << "Using Caffe's own pooling layer."; return shared_ptr >(new PoolingLayer(param)); } + if (checkPoolingDilated(param.pooling_param())) { + LOG(FATAL) << "CuDNN doesn't support the dilated pooling at Layer " + << param.name(); + } // CuDNN assumes layers are not being modified in place, thus // breaking our index tracking for updates in some cases in Caffe. // Until there is a workaround in Caffe (index management) or @@ -103,7 +118,7 @@ shared_ptr > GetPoolingLayer(const LayerParameter& param) { } #endif } else { - LOG(FATAL) << "Layer " << param.name() << " has unknown engine."; + LOG(FATAL)<< "Layer " << param.name() << " has unknown engine."; } } @@ -115,14 +130,14 @@ shared_ptr > GetLRNLayer(const LayerParameter& param) { LRNParameter_Engine engine = param.lrn_param().engine(); if (engine == LRNParameter_Engine_DEFAULT) { + engine = LRNParameter_Engine_CAFFE; #ifdef USE_CUDNN engine = LRNParameter_Engine_CUDNN; -#else - engine = LRNParameter_Engine_CAFFE; #endif } - if (engine == LRNParameter_Engine_CAFFE) { + if (engine == LRNParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL) { return shared_ptr >(new LRNLayer(param)); #ifdef USE_CUDNN } else if (engine == LRNParameter_Engine_CUDNN) { @@ -147,7 +162,7 @@ shared_ptr > GetLRNLayer(const LayerParameter& param) { REGISTER_LAYER_CREATOR(LRN, GetLRNLayer); // Get relu layer according to engine. -template +template shared_ptr > GetReLULayer(const LayerParameter& param) { ReLUParameter_Engine engine = param.relu_param().engine(); if (engine == ReLUParameter_Engine_DEFAULT) { @@ -156,21 +171,22 @@ shared_ptr > GetReLULayer(const LayerParameter& param) { engine = ReLUParameter_Engine_CUDNN; #endif } - if (engine == ReLUParameter_Engine_CAFFE) { + if (engine == ReLUParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL) { return shared_ptr >(new ReLULayer(param)); #ifdef USE_CUDNN } else if (engine == ReLUParameter_Engine_CUDNN) { return shared_ptr >(new CuDNNReLULayer(param)); #endif } else { - LOG(FATAL) << "Layer " << param.name() << " has unknown engine."; + LOG(FATAL)<< "Layer " << param.name() << " has unknown engine."; } } REGISTER_LAYER_CREATOR(ReLU, GetReLULayer); // Get sigmoid layer according to engine. -template +template shared_ptr > GetSigmoidLayer(const LayerParameter& param) { SigmoidParameter_Engine engine = param.sigmoid_param().engine(); if (engine == SigmoidParameter_Engine_DEFAULT) { @@ -179,21 +195,22 @@ shared_ptr > GetSigmoidLayer(const LayerParameter& param) { engine = SigmoidParameter_Engine_CUDNN; #endif } - if (engine == SigmoidParameter_Engine_CAFFE) { + if (engine == SigmoidParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL) { return shared_ptr >(new SigmoidLayer(param)); #ifdef USE_CUDNN } else if (engine == SigmoidParameter_Engine_CUDNN) { return shared_ptr >(new CuDNNSigmoidLayer(param)); #endif } else { - LOG(FATAL) << "Layer " << param.name() << " has unknown engine."; + LOG(FATAL)<< "Layer " << param.name() << " has unknown engine."; } } REGISTER_LAYER_CREATOR(Sigmoid, GetSigmoidLayer); // Get softmax layer according to engine. -template +template shared_ptr > GetSoftmaxLayer(const LayerParameter& param) { SoftmaxParameter_Engine engine = param.softmax_param().engine(); if (engine == SoftmaxParameter_Engine_DEFAULT) { @@ -202,21 +219,22 @@ shared_ptr > GetSoftmaxLayer(const LayerParameter& param) { engine = SoftmaxParameter_Engine_CUDNN; #endif } - if (engine == SoftmaxParameter_Engine_CAFFE) { + if (engine == SoftmaxParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL) { return shared_ptr >(new SoftmaxLayer(param)); #ifdef USE_CUDNN } else if (engine == SoftmaxParameter_Engine_CUDNN) { return shared_ptr >(new CuDNNSoftmaxLayer(param)); #endif } else { - LOG(FATAL) << "Layer " << param.name() << " has unknown engine."; + LOG(FATAL)<< "Layer " << param.name() << " has unknown engine."; } } REGISTER_LAYER_CREATOR(Softmax, GetSoftmaxLayer); // Get tanh layer according to engine. -template +template shared_ptr > GetTanHLayer(const LayerParameter& param) { TanHParameter_Engine engine = param.tanh_param().engine(); if (engine == TanHParameter_Engine_DEFAULT) { @@ -225,14 +243,15 @@ shared_ptr > GetTanHLayer(const LayerParameter& param) { engine = TanHParameter_Engine_CUDNN; #endif } - if (engine == TanHParameter_Engine_CAFFE) { + if (engine == TanHParameter_Engine_CAFFE + || Caffe::GetDevice(param.device(), true)->backend() == BACKEND_OpenCL) { return shared_ptr >(new TanHLayer(param)); #ifdef USE_CUDNN } else if (engine == TanHParameter_Engine_CUDNN) { return shared_ptr >(new CuDNNTanHLayer(param)); #endif } else { - LOG(FATAL) << "Layer " << param.name() << " has unknown engine."; + LOG(FATAL)<< "Layer " << param.name() << " has unknown engine."; } } diff --git a/src/caffe/layers/absval_layer.cpp b/src/caffe/layers/absval_layer.cpp index 855bf0bfacb..b6277aeac47 100644 --- a/src/caffe/layers/absval_layer.cpp +++ b/src/caffe/layers/absval_layer.cpp @@ -16,7 +16,7 @@ void AbsValLayer::LayerSetUp(const vector*>& bottom, template void AbsValLayer::Forward_cpu( const vector*>& bottom, const vector*>& top) { - const int count = top[0]->count(); + const int_tp count = top[0]->count(); Dtype* top_data = top[0]->mutable_cpu_data(); caffe_abs(count, bottom[0]->cpu_data(), top_data); } @@ -24,7 +24,7 @@ void AbsValLayer::Forward_cpu( template void AbsValLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { - const int count = top[0]->count(); + const int_tp count = top[0]->count(); const Dtype* top_diff = top[0]->cpu_diff(); if (propagate_down[0]) { const Dtype* bottom_data = bottom[0]->cpu_data(); diff --git a/src/caffe/layers/absval_layer.cu b/src/caffe/layers/absval_layer.cu index 6c927e6fabc..f19933fea65 100644 --- a/src/caffe/layers/absval_layer.cu +++ b/src/caffe/layers/absval_layer.cu @@ -3,30 +3,59 @@ #include "caffe/layers/absval_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -void AbsValLayer::Forward_gpu( - const vector*>& bottom, const vector*>& top) { - const int count = top[0]->count(); +template +void AbsValLayer::Forward_gpu(const vector*>& bottom, + const vector*>& top) { + const int_tp count = top[0]->count(); Dtype* top_data = top[0]->mutable_gpu_data(); - caffe_gpu_abs(count, bottom[0]->gpu_data(), top_data); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_abs(count, bottom[0]->gpu_data(), top_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_abs(this->device_->id(), count, + (cl_mem) (bottom[0]->gpu_data()), 0, + (cl_mem) (top_data), 0); +#endif // USE_GREENTEA + } } -template +template void AbsValLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - const int count = top[0]->count(); + const vector& propagate_down, + const vector*>& bottom) { + const int_tp count = top[0]->count(); const Dtype* top_diff = top[0]->gpu_diff(); if (propagate_down[0]) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - caffe_gpu_sign(count, bottom_data, bottom_diff); - caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_sign(count, bottom_data, bottom_diff); + caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_sign(this->device_->id(), count, + (cl_mem) bottom_data, 0, (cl_mem) bottom_diff, + 0); + greentea_gpu_mul(this->device_->id(), count, + (cl_mem) bottom_diff, 0, (cl_mem) top_diff, 0, + (cl_mem) bottom_diff, 0); +#endif // USE_GREENTEA + } } } INSTANTIATE_LAYER_GPU_FUNCS(AbsValLayer); - } // namespace caffe diff --git a/src/caffe/layers/accuracy_layer.cpp b/src/caffe/layers/accuracy_layer.cpp index 4eddbb5c850..2e0107e8685 100644 --- a/src/caffe/layers/accuracy_layer.cpp +++ b/src/caffe/layers/accuracy_layer.cpp @@ -33,11 +33,11 @@ void AccuracyLayer::Reshape( << "e.g., if label axis == 1 and prediction shape is (N, C, H, W), " << "label count (number of labels) must be N*H*W, " << "with integer values in {0, 1, ..., C-1}."; - vector top_shape(0); // Accuracy is a scalar; 0 axes. + vector top_shape(0); // Accuracy is a scalar; 0 axes. top[0]->Reshape(top_shape); if (top.size() > 1) { // Per-class accuracy is a vector; 1 axes. - vector top_shape_per_class(1); + vector top_shape_per_class(1); top_shape_per_class[0] = bottom[0]->shape(label_axis_); top[1]->Reshape(top_shape_per_class); nums_buffer_.Reshape(top_shape_per_class); @@ -50,19 +50,19 @@ void AccuracyLayer::Forward_cpu(const vector*>& bottom, Dtype accuracy = 0; const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* bottom_label = bottom[1]->cpu_data(); - const int dim = bottom[0]->count() / outer_num_; - const int num_labels = bottom[0]->shape(label_axis_); + const int_tp dim = bottom[0]->count() / outer_num_; + const int_tp num_labels = bottom[0]->shape(label_axis_); vector maxval(top_k_+1); - vector max_id(top_k_+1); + vector max_id(top_k_+1); if (top.size() > 1) { caffe_set(nums_buffer_.count(), Dtype(0), nums_buffer_.mutable_cpu_data()); caffe_set(top[1]->count(), Dtype(0), top[1]->mutable_cpu_data()); } - int count = 0; - for (int i = 0; i < outer_num_; ++i) { - for (int j = 0; j < inner_num_; ++j) { - const int label_value = - static_cast(bottom_label[i * inner_num_ + j]); + int_tp count = 0; + for (int_tp i = 0; i < outer_num_; ++i) { + for (int_tp j = 0; j < inner_num_; ++j) { + const int_tp label_value = + static_cast(bottom_label[i * inner_num_ + j]); if (has_ignore_label_ && label_value == ignore_label_) { continue; } @@ -70,16 +70,16 @@ void AccuracyLayer::Forward_cpu(const vector*>& bottom, DCHECK_GE(label_value, 0); DCHECK_LT(label_value, num_labels); // Top-k accuracy - std::vector > bottom_data_vector; - for (int k = 0; k < num_labels; ++k) { + std::vector > bottom_data_vector; + for (int_tp k = 0; k < num_labels; ++k) { bottom_data_vector.push_back(std::make_pair( bottom_data[i * dim + k * inner_num_ + j], k)); } std::partial_sort( bottom_data_vector.begin(), bottom_data_vector.begin() + top_k_, - bottom_data_vector.end(), std::greater >()); + bottom_data_vector.end(), std::greater >()); // check if true label is in top k predictions - for (int k = 0; k < top_k_; k++) { + for (int_tp k = 0; k < top_k_; k++) { if (bottom_data_vector[k].second == label_value) { ++accuracy; if (top.size() > 1) ++top[1]->mutable_cpu_data()[label_value]; @@ -93,7 +93,7 @@ void AccuracyLayer::Forward_cpu(const vector*>& bottom, // LOG(INFO) << "Accuracy: " << accuracy; top[0]->mutable_cpu_data()[0] = accuracy / count; if (top.size() > 1) { - for (int i = 0; i < top[1]->count(); ++i) { + for (int_tp i = 0; i < top[1]->count(); ++i) { top[1]->mutable_cpu_data()[i] = nums_buffer_.cpu_data()[i] == 0 ? 0 : top[1]->cpu_data()[i] / nums_buffer_.cpu_data()[i]; diff --git a/src/caffe/layers/affinity_layer.cpp b/src/caffe/layers/affinity_layer.cpp new file mode 100644 index 00000000000..f1166113f3d --- /dev/null +++ b/src/caffe/layers/affinity_layer.cpp @@ -0,0 +1,143 @@ +#include +#include +#include + +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/layer_factory.hpp" +#include "caffe/util/math_functions.hpp" + +#include "caffe/layers/affinity_layer.hpp" + +// #define CAFFE_AFFINITY_DEBUG + +namespace caffe { + +template +void AffinityLayer::LayerSetUp(const vector*>& bottom, + const vector*>& top) { + offsets_.clear(); + offsets_.resize(bottom.size()); + if (this->layer_param().has_affinity_param()) { + AffinityParameter affinity_param = this->layer_param().affinity_param(); + for (int_tp i = 0; i < + std::min(static_cast(bottom.size()), + static_cast(affinity_param.offset_size())); ++i) { + offsets_[i] = affinity_param.offset(i); + } + } + +#ifdef CAFFE_AFFINITY_DEBUG + cv::namedWindow("prob"); + cv::namedWindow("diff"); +#endif +} + +template +void AffinityLayer::Reshape(const vector*>& bottom, + const vector*>& top) { + min_index_.clear(); + for (int_tp bidx = 0; bidx < bottom.size(); ++bidx) { + // 1, #edges, height, width + top[bidx]->Reshape(1, 2, bottom[bidx]->height(), bottom[bidx]->width()); + + shared_ptr > blob_pointer( + new Blob(this->get_device())); + min_index_.push_back(blob_pointer); + + // 1, #edges, height, width + min_index_[bidx]->Reshape(1, 2, bottom[bidx]->height(), + bottom[bidx]->width()); + } +} + +template +void AffinityLayer::Forward_cpu(const vector*>& bottom, + const vector*>& top) { + for (int_tp bidx = 0; bidx < bottom.size(); ++bidx) { + const Dtype* bottom_data = bottom[bidx]->cpu_data(); + Dtype* top_data = top[bidx]->mutable_cpu_data(); + Dtype* min_data = min_index_[bidx]->mutable_cpu_data(); + + int_tp inner_num = bottom[bidx]->width() + * bottom[bidx]->height(); + + int_tp xmin, ymin; + + // Construct affinity graph +#pragma omp parallel for + for (int_tp i = 0; i < bottom[bidx]->height() - 1; ++i) { + for (int_tp j = 0; j < bottom[bidx]->width() - 1; ++j) { + // Center + Dtype p0 = bottom_data[offsets_[bidx] * inner_num + + i * bottom[bidx]->width() + j]; + // Right + Dtype p1 = bottom_data[offsets_[bidx] * inner_num + + i * bottom[bidx]->width() + (j + 1)]; + // Bottom + Dtype p2 = bottom_data[offsets_[bidx] * inner_num + + (i + 1) * bottom[bidx]->width() + j]; + + // Y edge + top_data[i * bottom[bidx]->width() + j] = std::min(p0, p2); + ymin = p0 < p2 ? 0 : 1; + min_data[i * bottom[bidx]->width() + j] = ymin; + + // X edge + top_data[inner_num + + i * bottom[bidx]->width() + j] = std::min(p0, p1); + xmin = p0 < p1 ? 0 : 1; + min_data[inner_num + + i * bottom[bidx]->width() + j] = xmin; + } + } + } +} + +template +void AffinityLayer::Backward_cpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom) { + for (int_tp bidx = 0; bidx < bottom.size(); ++bidx) { + if (propagate_down[bidx]) { + const Dtype* top_diff = top[bidx]->cpu_diff(); + Dtype* bottom_diff = bottom[bidx]->mutable_cpu_diff(); + const Dtype* min_data = min_index_[bidx]->cpu_diff(); + + caffe_set(bottom[0]->count(), Dtype(0.0), bottom_diff); + + int_tp inner_num = bottom[bidx]->width() + * bottom[bidx]->height(); + + // Spread out the affinity losses to pixels + for (int_tp i = 0; i < bottom[0]->height() - 1; ++i) { + for (int_tp j = 0; j < bottom[0]->width() - 1; ++j) { + Dtype ly = top_diff[i * bottom[0]->width() + j]; + Dtype lx = top_diff[inner_num + i * bottom[0]->width() + j]; + + int_tp my = min_data[i * bottom[0]->width() + j]; + int_tp mx = min_data[bottom[0]->width() + * bottom[0]->height() + i * bottom[0]->width() + j]; + + // Only propagate to min index contributor of affinity graph + bottom_diff[offsets_[bidx] + * inner_num + i * bottom[0]->width() + (j + mx)] += lx; + bottom_diff[offsets_[bidx] + * inner_num + (i + my) * bottom[0]->width() + j] += ly; + bottom_diff[((offsets_[bidx] + 1) % 2) + * inner_num + i * bottom[0]->width() + (j + mx)] -= lx; + bottom_diff[((offsets_[bidx] + 1) % 2) + * inner_num + (i + my) * bottom[0]->width() + j] -= ly; + } + } + } + } +} + +INSTANTIATE_CLASS(AffinityLayer); +REGISTER_LAYER_CLASS(Affinity); + +} // namespace caffe diff --git a/src/caffe/layers/argmax_layer.cpp b/src/caffe/layers/argmax_layer.cpp index 2d3d6f2d3ff..f6198b462c2 100644 --- a/src/caffe/layers/argmax_layer.cpp +++ b/src/caffe/layers/argmax_layer.cpp @@ -32,9 +32,9 @@ void ArgMaxLayer::LayerSetUp(const vector*>& bottom, template void ArgMaxLayer::Reshape(const vector*>& bottom, const vector*>& top) { - int num_top_axes = bottom[0]->num_axes(); + int_tp num_top_axes = bottom[0]->num_axes(); if ( num_top_axes < 3 ) num_top_axes = 3; - std::vector shape(num_top_axes, 1); + std::vector shape(num_top_axes, 1); if (has_axis_) { // Produces max_ind or max_val per axis shape = bottom[0]->shape(); @@ -56,7 +56,7 @@ void ArgMaxLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - int dim, axis_dist; + int_tp dim, axis_dist; if (has_axis_) { dim = bottom[0]->shape(axis_); // Distance between values of axis in blob @@ -65,17 +65,17 @@ void ArgMaxLayer::Forward_cpu(const vector*>& bottom, dim = bottom[0]->count(1); axis_dist = 1; } - int num = bottom[0]->count() / dim; - std::vector > bottom_data_vector(dim); - for (int i = 0; i < num; ++i) { - for (int j = 0; j < dim; ++j) { + int_tp num = bottom[0]->count() / dim; + std::vector > bottom_data_vector(dim); + for (int_tp i = 0; i < num; ++i) { + for (int_tp j = 0; j < dim; ++j) { bottom_data_vector[j] = std::make_pair( bottom_data[(i / axis_dist * dim + j) * axis_dist + i % axis_dist], j); } std::partial_sort( bottom_data_vector.begin(), bottom_data_vector.begin() + top_k_, - bottom_data_vector.end(), std::greater >()); - for (int j = 0; j < top_k_; ++j) { + bottom_data_vector.end(), std::greater >()); + for (int_tp j = 0; j < top_k_; ++j) { if (out_max_val_) { if (has_axis_) { // Produces max_val per axis diff --git a/src/caffe/layers/base_conv_layer.cpp b/src/caffe/layers/base_conv_layer.cpp index 4a4c68e009a..eeba7772017 100644 --- a/src/caffe/layers/base_conv_layer.cpp +++ b/src/caffe/layers/base_conv_layer.cpp @@ -6,113 +6,126 @@ #include "caffe/util/im2col.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void BaseConvolutionLayer::LayerSetUp(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { + use_colbuffer_ = true; + // Configure the kernel size, padding, stride, and inputs. ConvolutionParameter conv_param = this->layer_param_.convolution_param(); force_nd_im2col_ = conv_param.force_nd_im2col(); channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis()); - const int first_spatial_axis = channel_axis_ + 1; - const int num_axes = bottom[0]->num_axes(); + const int_tp first_spatial_axis = channel_axis_ + 1; + const int_tp num_axes = bottom[0]->num_axes(); num_spatial_axes_ = num_axes - first_spatial_axis; CHECK_GE(num_spatial_axes_, 0); - vector bottom_dim_blob_shape(1, num_spatial_axes_ + 1); - vector spatial_dim_blob_shape(1, std::max(num_spatial_axes_, 1)); + vector bottom_dim_blob_shape(1, num_spatial_axes_ + 1); + vector spatial_dim_blob_shape( + 1, std::max(num_spatial_axes_, (int_tp) 1)); // Setup filter kernel dimensions (kernel_shape_). kernel_shape_.Reshape(spatial_dim_blob_shape); - int* kernel_shape_data = kernel_shape_.mutable_cpu_data(); + int_tp* kernel_shape_data = kernel_shape_.mutable_cpu_data(); if (conv_param.has_kernel_h() || conv_param.has_kernel_w()) { CHECK_EQ(num_spatial_axes_, 2) - << "kernel_h & kernel_w can only be used for 2D convolution."; + << "kernel_h & kernel_w can only be used for 2D convolution."; CHECK_EQ(0, conv_param.kernel_size_size()) - << "Either kernel_size or kernel_h/w should be specified; not both."; + << "Either kernel_size or kernel_h/w should be specified; not both."; kernel_shape_data[0] = conv_param.kernel_h(); kernel_shape_data[1] = conv_param.kernel_w(); } else { - const int num_kernel_dims = conv_param.kernel_size_size(); + const int_tp num_kernel_dims = conv_param.kernel_size_size(); CHECK(num_kernel_dims == 1 || num_kernel_dims == num_spatial_axes_) - << "kernel_size must be specified once, or once per spatial dimension " - << "(kernel_size specified " << num_kernel_dims << " times; " - << num_spatial_axes_ << " spatial dims)."; - for (int i = 0; i < num_spatial_axes_; ++i) { - kernel_shape_data[i] = - conv_param.kernel_size((num_kernel_dims == 1) ? 0 : i); - } + << "kernel_size must be specified once, or once per spatial dimension " + << "(kernel_size specified " << num_kernel_dims << " times; " + << num_spatial_axes_ << " spatial dims);"; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + kernel_shape_data[i] = + conv_param.kernel_size((num_kernel_dims == 1) ? 0 : i); + } } - for (int i = 0; i < num_spatial_axes_; ++i) { - CHECK_GT(kernel_shape_data[i], 0) << "Filter dimensions must be nonzero."; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + CHECK_GT(kernel_shape_data[i], 0)<< "Filter dimensions must be nonzero."; } // Setup stride dimensions (stride_). stride_.Reshape(spatial_dim_blob_shape); - int* stride_data = stride_.mutable_cpu_data(); + int_tp* stride_data = stride_.mutable_cpu_data(); if (conv_param.has_stride_h() || conv_param.has_stride_w()) { CHECK_EQ(num_spatial_axes_, 2) - << "stride_h & stride_w can only be used for 2D convolution."; + << "stride_h & stride_w can only be used for 2D convolution."; CHECK_EQ(0, conv_param.stride_size()) - << "Either stride or stride_h/w should be specified; not both."; + << "Either stride or stride_h/w should be specified; not both."; stride_data[0] = conv_param.stride_h(); stride_data[1] = conv_param.stride_w(); } else { - const int num_stride_dims = conv_param.stride_size(); + const int_tp num_stride_dims = conv_param.stride_size(); CHECK(num_stride_dims == 0 || num_stride_dims == 1 || - num_stride_dims == num_spatial_axes_) - << "stride must be specified once, or once per spatial dimension " - << "(stride specified " << num_stride_dims << " times; " - << num_spatial_axes_ << " spatial dims)."; - const int kDefaultStride = 1; - for (int i = 0; i < num_spatial_axes_; ++i) { + num_stride_dims == num_spatial_axes_) + << "stride must be specified once, or once per spatial dimension " + << "(stride specified " << num_stride_dims << " times; " + << num_spatial_axes_ << " spatial dims);"; + const int_tp kDefaultStride = 1; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { stride_data[i] = (num_stride_dims == 0) ? kDefaultStride : - conv_param.stride((num_stride_dims == 1) ? 0 : i); + conv_param.stride((num_stride_dims == 1) ? 0 : i); CHECK_GT(stride_data[i], 0) << "Stride dimensions must be nonzero."; } } // Setup pad dimensions (pad_). pad_.Reshape(spatial_dim_blob_shape); - int* pad_data = pad_.mutable_cpu_data(); + int_tp* pad_data = pad_.mutable_cpu_data(); if (conv_param.has_pad_h() || conv_param.has_pad_w()) { CHECK_EQ(num_spatial_axes_, 2) - << "pad_h & pad_w can only be used for 2D convolution."; + << "pad_h & pad_w can only be used for 2D convolution."; CHECK_EQ(0, conv_param.pad_size()) - << "Either pad or pad_h/w should be specified; not both."; + << "Either pad or pad_h/w should be specified; not both."; pad_data[0] = conv_param.pad_h(); pad_data[1] = conv_param.pad_w(); } else { - const int num_pad_dims = conv_param.pad_size(); + const int_tp num_pad_dims = conv_param.pad_size(); CHECK(num_pad_dims == 0 || num_pad_dims == 1 || - num_pad_dims == num_spatial_axes_) - << "pad must be specified once, or once per spatial dimension " - << "(pad specified " << num_pad_dims << " times; " - << num_spatial_axes_ << " spatial dims)."; - const int kDefaultPad = 0; - for (int i = 0; i < num_spatial_axes_; ++i) { + num_pad_dims == num_spatial_axes_) + << "pad must be specified once, or once per spatial dimension " + << "(pad specified " << num_pad_dims << " times; " + << num_spatial_axes_ << " spatial dims);"; + const int_tp kDefaultPad = 0; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { pad_data[i] = (num_pad_dims == 0) ? kDefaultPad : - conv_param.pad((num_pad_dims == 1) ? 0 : i); + conv_param.pad((num_pad_dims == 1) ? 0 : i); } } + // Setup dilation dimensions (dilation_). dilation_.Reshape(spatial_dim_blob_shape); - int* dilation_data = dilation_.mutable_cpu_data(); - const int num_dilation_dims = conv_param.dilation_size(); + int_tp* dilation_data = dilation_.mutable_cpu_data(); + const int_tp num_dilation_dims = conv_param.dilation_size(); CHECK(num_dilation_dims == 0 || num_dilation_dims == 1 || num_dilation_dims == num_spatial_axes_) << "dilation must be specified once, or once per spatial dimension " << "(dilation specified " << num_dilation_dims << " times; " << num_spatial_axes_ << " spatial dims)."; const int kDefaultDilation = 1; - for (int i = 0; i < num_spatial_axes_; ++i) { + for (int_tp i = 0; i < num_spatial_axes_; ++i) { dilation_data[i] = (num_dilation_dims == 0) ? kDefaultDilation : conv_param.dilation((num_dilation_dims == 1) ? 0 : i); } + // Special case: im2col is the identity for 1x1 convolution with stride 1 // and no padding, so flag for skipping the buffer and transformation. is_1x1_ = true; - for (int i = 0; i < num_spatial_axes_; ++i) { - is_1x1_ &= - kernel_shape_data[i] == 1 && stride_data[i] == 1 && pad_data[i] == 0; - if (!is_1x1_) { break; } + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + is_1x1_ &= kernel_shape_data[i] == 1 && stride_data[i] == 1 + && pad_data[i] == 0; + if (!is_1x1_) { + break; + } } // Configure output channels and groups. channels_ = bottom[0]->shape(channel_axis_); @@ -121,7 +134,7 @@ void BaseConvolutionLayer::LayerSetUp(const vector*>& bottom, group_ = this->layer_param_.convolution_param().group(); CHECK_EQ(channels_ % group_, 0); CHECK_EQ(num_output_ % group_, 0) - << "Number of output should be multiples of group."; + << "Number of output should be multiples of group."; if (reverse_dimensions()) { conv_out_channels_ = channels_; conv_in_channels_ = num_output_; @@ -132,28 +145,28 @@ void BaseConvolutionLayer::LayerSetUp(const vector*>& bottom, // Handle the parameters: weights and biases. // - blobs_[0] holds the filter weights // - blobs_[1] holds the biases (optional) - vector weight_shape(2); + vector weight_shape(2); weight_shape[0] = conv_out_channels_; weight_shape[1] = conv_in_channels_ / group_; - for (int i = 0; i < num_spatial_axes_; ++i) { + for (int_tp i = 0; i < num_spatial_axes_; ++i) { weight_shape.push_back(kernel_shape_data[i]); } bias_term_ = this->layer_param_.convolution_param().bias_term(); - vector bias_shape(bias_term_, num_output_); + vector bias_shape(bias_term_, num_output_); if (this->blobs_.size() > 0) { CHECK_EQ(1 + bias_term_, this->blobs_.size()) << "Incorrect number of weight blobs."; if (weight_shape != this->blobs_[0]->shape()) { - Blob weight_shaped_blob(weight_shape); + Blob weight_shaped_blob(weight_shape, this->device_); LOG(FATAL) << "Incorrect weight shape: expected shape " - << weight_shaped_blob.shape_string() << "; instead, shape was " - << this->blobs_[0]->shape_string(); + << weight_shaped_blob.shape_string() << "; instead, shape was " + << this->blobs_[0]->shape_string(); } if (bias_term_ && bias_shape != this->blobs_[1]->shape()) { - Blob bias_shaped_blob(bias_shape); + Blob bias_shaped_blob(bias_shape, this->device_); LOG(FATAL) << "Incorrect bias shape: expected shape " - << bias_shaped_blob.shape_string() << "; instead, shape was " - << this->blobs_[1]->shape_string(); + << bias_shaped_blob.shape_string() << "; instead, shape was " + << this->blobs_[1]->shape_string(); } LOG(INFO) << "Skipping parameter initialization"; } else { @@ -164,15 +177,15 @@ void BaseConvolutionLayer::LayerSetUp(const vector*>& bottom, } // Initialize and fill the weights: // output channels x input channels per-group x kernel height x kernel width - this->blobs_[0].reset(new Blob(weight_shape)); + this->blobs_[0].reset(new Blob(weight_shape, this->device_)); shared_ptr > weight_filler(GetFiller( - this->layer_param_.convolution_param().weight_filler())); + this->layer_param_.convolution_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the biases. if (bias_term_) { - this->blobs_[1].reset(new Blob(bias_shape)); + this->blobs_[1].reset(new Blob(bias_shape, this->device_)); shared_ptr > bias_filler(GetFiller( - this->layer_param_.convolution_param().bias_filler())); + this->layer_param_.convolution_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } @@ -182,30 +195,30 @@ void BaseConvolutionLayer::LayerSetUp(const vector*>& bottom, this->param_propagate_down_.resize(this->blobs_.size(), true); } -template +template void BaseConvolutionLayer::Reshape(const vector*>& bottom, - const vector*>& top) { - const int first_spatial_axis = channel_axis_ + 1; + const vector*>& top) { + const int_tp first_spatial_axis = channel_axis_ + 1; CHECK_EQ(bottom[0]->num_axes(), first_spatial_axis + num_spatial_axes_) - << "bottom num_axes may not change."; + << "bottom num_axes may not change."; num_ = bottom[0]->count(0, channel_axis_); CHECK_EQ(bottom[0]->shape(channel_axis_), channels_) - << "Input size incompatible with convolution kernel."; + << "Input size incompatible with convolution kernel."; // TODO: generalize to handle inputs of different shapes. - for (int bottom_id = 1; bottom_id < bottom.size(); ++bottom_id) { + for (int_tp bottom_id = 1; bottom_id < bottom.size(); ++bottom_id) { CHECK(bottom[0]->shape() == bottom[bottom_id]->shape()) << "All inputs must have the same shape."; } // Shape the tops. bottom_shape_ = &bottom[0]->shape(); compute_output_shape(); - vector top_shape(bottom[0]->shape().begin(), - bottom[0]->shape().begin() + channel_axis_); + vector top_shape(bottom[0]->shape().begin(), + bottom[0]->shape().begin() + channel_axis_); top_shape.push_back(num_output_); - for (int i = 0; i < num_spatial_axes_; ++i) { + for (int_tp i = 0; i < num_spatial_axes_; ++i) { top_shape.push_back(output_shape_[i]); } - for (int top_id = 0; top_id < top.size(); ++top_id) { + for (int_tp top_id = 0; top_id < top.size(); ++top_id) { top[top_id]->Reshape(top_shape); } if (reverse_dimensions()) { @@ -216,10 +229,10 @@ void BaseConvolutionLayer::Reshape(const vector*>& bottom, col_offset_ = kernel_dim_ * conv_out_spatial_dim_; output_offset_ = conv_out_channels_ * conv_out_spatial_dim_ / group_; // Setup input dimensions (conv_input_shape_). - vector bottom_dim_blob_shape(1, num_spatial_axes_ + 1); + vector bottom_dim_blob_shape(1, num_spatial_axes_ + 1); conv_input_shape_.Reshape(bottom_dim_blob_shape); - int* conv_input_shape_data = conv_input_shape_.mutable_cpu_data(); - for (int i = 0; i < num_spatial_axes_ + 1; ++i) { + int_tp* conv_input_shape_data = conv_input_shape_.mutable_cpu_data(); + for (int_tp i = 0; i < num_spatial_axes_ + 1; ++i) { if (reverse_dimensions()) { conv_input_shape_data[i] = top[0]->shape(channel_axis_ + i); } else { @@ -229,33 +242,52 @@ void BaseConvolutionLayer::Reshape(const vector*>& bottom, // The im2col result buffer will only hold one image at a time to avoid // overly large memory usage. In the special case of 1x1 convolution // it goes lazily unused to save memory. + col_buffer_shape_.clear(); col_buffer_shape_.push_back(kernel_dim_ * group_); - for (int i = 0; i < num_spatial_axes_; ++i) { + for (int_tp i = 0; i < num_spatial_axes_; ++i) { if (reverse_dimensions()) { col_buffer_shape_.push_back(input_shape(i + 1)); } else { col_buffer_shape_.push_back(output_shape_[i]); } } + col_buffer_.Reshape(col_buffer_shape_); + if (Caffe::mode() == Caffe::Brew::GPU && use_colbuffer_) { + // Shared column buffer per device-queue across all layers on that device + for (int_tp i = 0; i < this->device_->num_queues(); ++i) { + shared_ptr > buffer = this->device_ + ->template Buffer(i); + buffer->Reshape(col_buffer_shape_); + } + } + bottom_dim_ = bottom[0]->count(channel_axis_); top_dim_ = top[0]->count(channel_axis_); num_kernels_im2col_ = conv_in_channels_ * conv_out_spatial_dim_; num_kernels_col2im_ = reverse_dimensions() ? top_dim_ : bottom_dim_; + // Set up the all ones "bias multiplier" for adding biases by BLAS out_spatial_dim_ = top[0]->count(first_spatial_axis); if (bias_term_) { - vector bias_multiplier_shape(1, out_spatial_dim_); - bias_multiplier_.Reshape(bias_multiplier_shape); - caffe_set(bias_multiplier_.count(), Dtype(1), - bias_multiplier_.mutable_cpu_data()); + vector bias_multiplier_shape(1, out_spatial_dim_); + bool reshaped = bias_multiplier_.Reshape(bias_multiplier_shape); + // This will trigger a memory copy if in GPU mode, + // which may not be necessary. + // Thus omit to set the values if not necessary. + if (reshaped) { + caffe_set(bias_multiplier_.count(), Dtype(1), + bias_multiplier_.mutable_cpu_data()); + } } } -template +template void BaseConvolutionLayer::forward_cpu_gemm(const Dtype* input, - const Dtype* weights, Dtype* output, bool skip_im2col) { + const Dtype* weights, + Dtype* output, + bool skip_im2col) { const Dtype* col_buff = input; if (!is_1x1_) { if (!skip_im2col) { @@ -263,130 +295,248 @@ void BaseConvolutionLayer::forward_cpu_gemm(const Dtype* input, } col_buff = col_buffer_.cpu_data(); } - for (int g = 0; g < group_; ++g) { - caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, conv_out_channels_ / - group_, conv_out_spatial_dim_, kernel_dim_, - (Dtype)1., weights + weight_offset_ * g, col_buff + col_offset_ * g, - (Dtype)0., output + output_offset_ * g); + for (int_tp g = 0; g < group_; ++g) { + caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, + conv_out_channels_ / group_, conv_out_spatial_dim_, + kernel_dim_, (Dtype) 1., weights + weight_offset_ * g, + col_buff + col_offset_ * g, (Dtype) 0., + output + output_offset_ * g); } } -template +template void BaseConvolutionLayer::forward_cpu_bias(Dtype* output, - const Dtype* bias) { + const Dtype* bias) { caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, num_output_, - out_spatial_dim_, 1, (Dtype)1., bias, bias_multiplier_.cpu_data(), - (Dtype)1., output); + out_spatial_dim_, 1, (Dtype) 1., bias, + bias_multiplier_.cpu_data(), (Dtype) 1., output); } -template +template void BaseConvolutionLayer::backward_cpu_gemm(const Dtype* output, - const Dtype* weights, Dtype* input) { + const Dtype* weights, + Dtype* input) { Dtype* col_buff = col_buffer_.mutable_cpu_data(); if (is_1x1_) { col_buff = input; } - for (int g = 0; g < group_; ++g) { + for (int_tp g = 0; g < group_; ++g) { caffe_cpu_gemm(CblasTrans, CblasNoTrans, kernel_dim_, - conv_out_spatial_dim_, conv_out_channels_ / group_, - (Dtype)1., weights + weight_offset_ * g, output + output_offset_ * g, - (Dtype)0., col_buff + col_offset_ * g); + conv_out_spatial_dim_, conv_out_channels_ / group_, + (Dtype) 1., weights + weight_offset_ * g, + output + output_offset_ * g, (Dtype) 0., + col_buff + col_offset_ * g); } if (!is_1x1_) { conv_col2im_cpu(col_buff, input); } } -template +template void BaseConvolutionLayer::weight_cpu_gemm(const Dtype* input, - const Dtype* output, Dtype* weights) { + const Dtype* output, + Dtype* weights) { const Dtype* col_buff = input; if (!is_1x1_) { conv_im2col_cpu(input, col_buffer_.mutable_cpu_data()); col_buff = col_buffer_.cpu_data(); } - for (int g = 0; g < group_; ++g) { + for (int_tp g = 0; g < group_; ++g) { caffe_cpu_gemm(CblasNoTrans, CblasTrans, conv_out_channels_ / group_, - kernel_dim_, conv_out_spatial_dim_, - (Dtype)1., output + output_offset_ * g, col_buff + col_offset_ * g, - (Dtype)1., weights + weight_offset_ * g); + kernel_dim_, conv_out_spatial_dim_, (Dtype) 1., + output + output_offset_ * g, + col_buff + col_offset_ * g, (Dtype) 1., + weights + weight_offset_ * g); } } -template +template void BaseConvolutionLayer::backward_cpu_bias(Dtype* bias, - const Dtype* input) { - caffe_cpu_gemv(CblasNoTrans, num_output_, out_spatial_dim_, 1., - input, bias_multiplier_.cpu_data(), 1., bias); + const Dtype* input) { + caffe_cpu_gemv(CblasNoTrans, num_output_, out_spatial_dim_, 1., input, + bias_multiplier_.cpu_data(), 1., bias); } #ifndef CPU_ONLY -template +template void BaseConvolutionLayer::forward_gpu_gemm(const Dtype* input, - const Dtype* weights, Dtype* output, bool skip_im2col) { + const int_tp input_off, + const Dtype* weights, + Dtype* output, + const int_tp output_off, + bool skip_im2col) { const Dtype* col_buff = input; - if (!is_1x1_) { - if (!skip_im2col) { - conv_im2col_gpu(input, col_buffer_.mutable_gpu_data()); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (!is_1x1_) { + if (!skip_im2col) { + conv_im2col_gpu(input + input_off, col_buffer()->mutable_gpu_data()); + } + col_buff = col_buffer()->gpu_data(); } - col_buff = col_buffer_.gpu_data(); - } - for (int g = 0; g < group_; ++g) { - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, conv_out_channels_ / - group_, conv_out_spatial_dim_, kernel_dim_, - (Dtype)1., weights + weight_offset_ * g, col_buff + col_offset_ * g, - (Dtype)0., output + output_offset_ * g); + for (int_tp g = 0; g < group_; ++g) { + caffe_gpu_gemm( + CblasNoTrans, CblasNoTrans, conv_out_channels_ / group_, + conv_out_spatial_dim_, kernel_dim_, (Dtype) 1., + weights + weight_offset_ * g, + col_buff + (is_1x1_ ? input_off : 0) + col_offset_ * g, (Dtype) 0., + output + output_off + output_offset_ * g); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + if (!is_1x1_) { + if (!skip_im2col) { + greentea_conv_im2col_gpu(input, input_off, + col_buffer()->mutable_gpu_data(), 0); + } + col_buff = col_buffer()->gpu_data(); + } + for (int_tp g = 0; g < group_; ++g) { + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, conv_out_channels_ / group_, + conv_out_spatial_dim_, kernel_dim_, + (Dtype) 1., (cl_mem) weights, weight_offset_ * g, + (cl_mem) col_buff, + (is_1x1_ ? input_off : 0) + col_offset_ * g, + (Dtype) 0., (cl_mem) output, + output_off + output_offset_ * g); + } +#endif // USE_GREENTEA } } -template +template void BaseConvolutionLayer::forward_gpu_bias(Dtype* output, - const Dtype* bias) { - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num_output_, - out_spatial_dim_, 1, (Dtype)1., bias, bias_multiplier_.gpu_data(), - (Dtype)1., output); + const int_tp output_off, + const Dtype* bias) { + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num_output_, + out_spatial_dim_, 1, (Dtype) 1., bias, + bias_multiplier_.gpu_data(), (Dtype) 1., + output + output_off); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, num_output_, out_spatial_dim_, 1, + (Dtype) 1., (cl_mem) bias, 0, + (cl_mem) (bias_multiplier_.gpu_data()), 0, + (Dtype) 1., (cl_mem) output, output_off); +#endif // USE_GREENTEA + } } -template +template void BaseConvolutionLayer::backward_gpu_gemm(const Dtype* output, - const Dtype* weights, Dtype* input) { - Dtype* col_buff = col_buffer_.mutable_gpu_data(); + const int_tp output_off, + const Dtype* weights, + Dtype* input, + const int_tp input_off) { + Dtype* col_buff = col_buffer()->mutable_gpu_data(); if (is_1x1_) { col_buff = input; } - for (int g = 0; g < group_; ++g) { - caffe_gpu_gemm(CblasTrans, CblasNoTrans, kernel_dim_, - conv_out_spatial_dim_, conv_out_channels_ / group_, - (Dtype)1., weights + weight_offset_ * g, output + output_offset_ * g, - (Dtype)0., col_buff + col_offset_ * g); - } - if (!is_1x1_) { - conv_col2im_gpu(col_buff, input); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int_tp g = 0; g < group_; ++g) { + caffe_gpu_gemm( + CblasTrans, CblasNoTrans, kernel_dim_, conv_out_spatial_dim_, + conv_out_channels_ / group_, (Dtype) 1., weights + weight_offset_ * g, + output + output_off + output_offset_ * g, (Dtype) 0., + col_buff + (is_1x1_ ? input_off : 0) + col_offset_ * g); + } + if (!is_1x1_) { + conv_col2im_gpu(col_buff, input + input_off); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + for (int_tp g = 0; g < group_; ++g) { + greentea_gpu_gemm(this->device_->id(), CblasTrans, + CblasNoTrans, kernel_dim_, conv_out_spatial_dim_, + conv_out_channels_ / group_, (Dtype) 1., + (cl_mem) weights, weight_offset_ * g, + (cl_mem) output, output_off + output_offset_ * g, + (Dtype) 0., (cl_mem) col_buff, + (is_1x1_ ? input_off : 0) + col_offset_ * g); + } + if (!is_1x1_) { + greentea_conv_col2im_gpu(col_buff, 0, input, input_off); + } +#endif // USE_GREENTEA } } -template +template void BaseConvolutionLayer::weight_gpu_gemm(const Dtype* input, - const Dtype* output, Dtype* weights) { + const int_tp input_off, + const Dtype* output, + const int_tp output_off, + Dtype* weights) { const Dtype* col_buff = input; - if (!is_1x1_) { - conv_im2col_gpu(input, col_buffer_.mutable_gpu_data()); - col_buff = col_buffer_.gpu_data(); - } - for (int g = 0; g < group_; ++g) { - caffe_gpu_gemm(CblasNoTrans, CblasTrans, conv_out_channels_ / group_, - kernel_dim_, conv_out_spatial_dim_, - (Dtype)1., output + output_offset_ * g, col_buff + col_offset_ * g, - (Dtype)1., weights + weight_offset_ * g); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (!is_1x1_) { + conv_im2col_gpu(input + input_off, col_buffer()->mutable_gpu_data()); + col_buff = col_buffer()->gpu_data(); + } + for (int_tp g = 0; g < group_; ++g) { + caffe_gpu_gemm( + CblasNoTrans, CblasTrans, conv_out_channels_ / group_, kernel_dim_, + conv_out_spatial_dim_, (Dtype) 1., + output + output_off + output_offset_ * g, + col_buff + (is_1x1_ ? input_off : 0) + col_offset_ * g, (Dtype) 1., + weights + weight_offset_ * g); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + if (!is_1x1_) { + greentea_conv_im2col_gpu(input, input_off, + col_buffer()->mutable_gpu_data(), 0); + col_buff = col_buffer()->gpu_data(); + } + for (int_tp g = 0; g < group_; ++g) { + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasTrans, conv_out_channels_ / group_, + kernel_dim_, conv_out_spatial_dim_, (Dtype) 1., + (cl_mem) output, output_off + output_offset_ * g, + (cl_mem) col_buff, + (is_1x1_ ? input_off : 0) + col_offset_ * g, + (Dtype) 1., (cl_mem) weights, + weight_offset_ * g); + } +#endif // USE_GREENTEA } } -template +template void BaseConvolutionLayer::backward_gpu_bias(Dtype* bias, - const Dtype* input) { - caffe_gpu_gemv(CblasNoTrans, num_output_, out_spatial_dim_, 1., - input, bias_multiplier_.gpu_data(), 1., bias); + const Dtype* input, + const int_tp input_off) { + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_gemv(CblasNoTrans, num_output_, out_spatial_dim_, 1., + input + input_off, bias_multiplier_.gpu_data(), 1., + bias); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, + num_output_, out_spatial_dim_, 1., (cl_mem) input, + input_off, (cl_mem) (bias_multiplier_.gpu_data()), + 0, 1., (cl_mem) bias, 0); +#endif // USE_GREENTEA + } +} + +template +shared_ptr > BaseConvolutionLayer::col_buffer() { + return this->device_->template Buffer( + this->device_->current_queue_id()); } #endif // !CPU_ONLY diff --git a/src/caffe/layers/base_data_layer.cpp b/src/caffe/layers/base_data_layer.cpp index 989319f1a07..d1f751d97ea 100644 --- a/src/caffe/layers/base_data_layer.cpp +++ b/src/caffe/layers/base_data_layer.cpp @@ -26,7 +26,8 @@ void BaseDataLayer::LayerSetUp(const vector*>& bottom, output_labels_ = true; } data_transformer_.reset( - new DataTransformer(transform_param_, this->phase_)); + new DataTransformer(transform_param_, + this->phase_, this->device_)); data_transformer_->InitRand(); // The subclasses should setup the size of bottom and top DataLayerSetUp(bottom, top); @@ -36,8 +37,9 @@ template BasePrefetchingDataLayer::BasePrefetchingDataLayer( const LayerParameter& param) : BaseDataLayer(param), - prefetch_free_(), prefetch_full_() { - for (int i = 0; i < PREFETCH_COUNT; ++i) { + prefetch_free_(), + prefetch_full_() { + for (int_tp i = 0; i < PREFETCH_COUNT; ++i) { prefetch_free_.push(&prefetch_[i]); } } @@ -50,7 +52,7 @@ void BasePrefetchingDataLayer::LayerSetUp( // calls so that the prefetch thread does not accidentally make simultaneous // cudaMalloc calls when the main thread is running. In some GPUs this // seems to cause failures if we do not so. - for (int i = 0; i < PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < PREFETCH_COUNT; ++i) { prefetch_[i].data_.mutable_cpu_data(); if (this->output_labels_) { prefetch_[i].label_.mutable_cpu_data(); @@ -58,7 +60,7 @@ void BasePrefetchingDataLayer::LayerSetUp( } #ifndef CPU_ONLY if (Caffe::mode() == Caffe::GPU) { - for (int i = 0; i < PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < PREFETCH_COUNT; ++i) { prefetch_[i].data_.mutable_gpu_data(); if (this->output_labels_) { prefetch_[i].label_.mutable_gpu_data(); @@ -68,39 +70,51 @@ void BasePrefetchingDataLayer::LayerSetUp( #endif DLOG(INFO) << "Initializing prefetch"; this->data_transformer_->InitRand(); - StartInternalThread(); + StartInternalThread(this->get_device()); DLOG(INFO) << "Prefetch initialized."; } template void BasePrefetchingDataLayer::InternalThreadEntry() { #ifndef CPU_ONLY +#ifdef USE_CUDA cudaStream_t stream; if (Caffe::mode() == Caffe::GPU) { - CUDA_CHECK(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); + if (this->get_device()->backend() == BACKEND_CUDA) { + CUDA_CHECK(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); + } } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY try { while (!must_stop()) { Batch* batch = prefetch_free_.pop(); load_batch(batch); #ifndef CPU_ONLY +#ifdef USE_CUDA if (Caffe::mode() == Caffe::GPU) { - batch->data_.data().get()->async_gpu_push(stream); - CUDA_CHECK(cudaStreamSynchronize(stream)); + if (this->get_device()->backend() == BACKEND_CUDA) { + batch->data_.data().get()->async_gpu_push(stream); + CUDA_CHECK(cudaStreamSynchronize(stream)); + } } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY prefetch_full_.push(batch); } } catch (boost::thread_interrupted&) { // Interrupted exception is expected on shutdown } #ifndef CPU_ONLY +#ifdef USE_CUDA if (Caffe::mode() == Caffe::GPU) { - CUDA_CHECK(cudaStreamDestroy(stream)); + if (this->get_device()->backend() == BACKEND_CUDA) { + CUDA_CHECK(cudaStreamDestroy(stream)); + } } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY } template @@ -110,15 +124,15 @@ void BasePrefetchingDataLayer::Forward_cpu( // Reshape to loaded data. top[0]->ReshapeLike(batch->data_); // Copy the data - caffe_copy(batch->data_.count(), batch->data_.cpu_data(), + caffe_cpu_copy(batch->data_.count(), batch->data_.cpu_data(), top[0]->mutable_cpu_data()); DLOG(INFO) << "Prefetch copied"; if (this->output_labels_) { // Reshape to loaded labels. top[1]->ReshapeLike(batch->label_); // Copy the labels. - caffe_copy(batch->label_.count(), batch->label_.cpu_data(), - top[1]->mutable_cpu_data()); + caffe_cpu_copy(batch->label_.count(), batch->label_.cpu_data(), + top[1]->mutable_cpu_data()); } prefetch_free_.push(batch); diff --git a/src/caffe/layers/base_data_layer.cu b/src/caffe/layers/base_data_layer.cu index 4056d36a7b4..50659bdf9df 100644 --- a/src/caffe/layers/base_data_layer.cu +++ b/src/caffe/layers/base_data_layer.cu @@ -4,25 +4,52 @@ namespace caffe { -template +template void BasePrefetchingDataLayer::Forward_gpu( const vector*>& bottom, const vector*>& top) { + Batch* batch = prefetch_full_.pop("Data layer prefetch queue empty"); - // Reshape to loaded data. - top[0]->ReshapeLike(batch->data_); - // Copy the data - caffe_copy(batch->data_.count(), batch->data_.gpu_data(), - top[0]->mutable_gpu_data()); - if (this->output_labels_) { - // Reshape to loaded labels. - top[1]->ReshapeLike(batch->label_); - // Copy the labels. - caffe_copy(batch->label_.count(), batch->label_.gpu_data(), - top[1]->mutable_gpu_data()); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // Reshape to loaded data. + top[0]->ReshapeLike(batch->data_); + // Copy the data + caffe_copy(batch->data_.count(), batch->data_.gpu_data(), + top[0]->mutable_gpu_data()); + if (this->output_labels_) { + // Reshape to loaded labels. + top[1]->ReshapeLike(batch->label_); + // Copy the labels. + caffe_copy(batch->label_.count(), batch->label_.gpu_data(), + top[1]->mutable_gpu_data()); + } + // Ensure the copy is synchronous wrt the host, so that the next batch isn't + // copied in meanwhile. + CUDA_CHECK(cudaStreamSynchronize(cudaStreamDefault)); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + // Reshape to loaded data. + top[0]->ReshapeLike(batch->data_); + // Copy the data + greentea_copy(batch->data_.count(), + (cl_mem) (batch->data_.gpu_data()), 0, + (cl_mem) (top[0]->mutable_gpu_data()), 0, &ctx); + if (this->output_labels_) { + // Reshape to loaded labels. + top[1]->ReshapeLike(batch->label_); + // Copy the labels. + greentea_copy(batch->label_.count(), + (cl_mem) (batch->label_.gpu_data()), 0, + (cl_mem) (top[1]->mutable_gpu_data()), 0, &ctx); + } +#endif // USE_GREENTEA } - // Ensure the copy is synchronous wrt the host, so that the next batch isn't - // copied in meanwhile. - CUDA_CHECK(cudaStreamSynchronize(cudaStreamDefault)); + prefetch_free_.push(batch); } diff --git a/src/caffe/layers/batch_norm_layer.cpp b/src/caffe/layers/batch_norm_layer.cpp index a69d8f99316..9bba62080fd 100644 --- a/src/caffe/layers/batch_norm_layer.cpp +++ b/src/caffe/layers/batch_norm_layer.cpp @@ -6,9 +6,9 @@ namespace caffe { -template +template void BatchNormLayer::LayerSetUp(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { BatchNormParameter param = this->layer_param_.batch_norm_param(); moving_average_fraction_ = param.moving_average_fraction(); use_global_stats_ = this->phase_ == TEST; @@ -20,64 +20,63 @@ void BatchNormLayer::LayerSetUp(const vector*>& bottom, channels_ = bottom[0]->shape(1); eps_ = param.eps(); if (this->blobs_.size() > 0) { - LOG(INFO) << "Skipping parameter initialization"; + LOG(INFO)<< "Skipping parameter initialization"; } else { this->blobs_.resize(3); - vector sz; + vector sz; sz.push_back(channels_); - this->blobs_[0].reset(new Blob(sz)); - this->blobs_[1].reset(new Blob(sz)); + this->blobs_[0].reset(new Blob(sz, this->device_)); + this->blobs_[1].reset(new Blob(sz, this->device_)); sz[0]=1; - this->blobs_[2].reset(new Blob(sz)); - for (int i = 0; i < 3; ++i) { + this->blobs_[2].reset(new Blob(sz, this->device_)); + for (int_tp i = 0; i < 3; ++i) { caffe_set(this->blobs_[i]->count(), Dtype(0), - this->blobs_[i]->mutable_cpu_data()); + this->blobs_[i]->mutable_cpu_data()); } } } -template +template void BatchNormLayer::Reshape(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { if (bottom[0]->num_axes() >= 1) CHECK_EQ(bottom[0]->shape(1), channels_); top[0]->ReshapeLike(*bottom[0]); - vector sz; + vector sz; sz.push_back(channels_); mean_.Reshape(sz); variance_.Reshape(sz); temp_.ReshapeLike(*bottom[0]); x_norm_.ReshapeLike(*bottom[0]); - sz[0]=bottom[0]->shape(0); + sz[0] = bottom[0]->shape(0); batch_sum_multiplier_.Reshape(sz); - int spatial_dim = bottom[0]->count()/(channels_*bottom[0]->shape(0)); - if (spatial_sum_multiplier_.num_axes() == 0 || - spatial_sum_multiplier_.shape(0) != spatial_dim) { + int_tp spatial_dim = bottom[0]->count() / (channels_ * bottom[0]->shape(0)); + if (spatial_sum_multiplier_.num_axes() == 0 + || spatial_sum_multiplier_.shape(0) != spatial_dim) { sz[0] = spatial_dim; spatial_sum_multiplier_.Reshape(sz); Dtype* multiplier_data = spatial_sum_multiplier_.mutable_cpu_data(); caffe_set(spatial_sum_multiplier_.count(), Dtype(1), multiplier_data); } - int numbychans = channels_*bottom[0]->shape(0); - if (num_by_chans_.num_axes() == 0 || - num_by_chans_.shape(0) != numbychans) { + int_tp numbychans = channels_ * bottom[0]->shape(0); + if (num_by_chans_.num_axes() == 0 || num_by_chans_.shape(0) != numbychans) { sz[0] = numbychans; num_by_chans_.Reshape(sz); caffe_set(batch_sum_multiplier_.count(), Dtype(1), - batch_sum_multiplier_.mutable_cpu_data()); + batch_sum_multiplier_.mutable_cpu_data()); } } -template +template void BatchNormLayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - int num = bottom[0]->shape(0); - int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_); + int_tp num = bottom[0]->shape(0); + int_tp spatial_dim = bottom[0]->count() / (bottom[0]->shape(0) * channels_); if (bottom[0] != top[0]) { caffe_copy(bottom[0]->count(), bottom_data, top_data); @@ -88,15 +87,15 @@ void BatchNormLayer::Forward_cpu(const vector*>& bottom, const Dtype scale_factor = this->blobs_[2]->cpu_data()[0] == 0 ? 0 : 1 / this->blobs_[2]->cpu_data()[0]; caffe_cpu_scale(variance_.count(), scale_factor, - this->blobs_[0]->cpu_data(), mean_.mutable_cpu_data()); + this->blobs_[0]->cpu_data(), mean_.mutable_cpu_data()); caffe_cpu_scale(variance_.count(), scale_factor, - this->blobs_[1]->cpu_data(), variance_.mutable_cpu_data()); + this->blobs_[1]->cpu_data(), variance_.mutable_cpu_data()); } else { // compute mean caffe_cpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, - 1. / (num * spatial_dim), bottom_data, - spatial_sum_multiplier_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + 1. / (num * spatial_dim), bottom_data, + spatial_sum_multiplier_.cpu_data(), 0., + num_by_chans_.mutable_cpu_data()); caffe_cpu_gemv(CblasTrans, num, channels_, 1., num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0., mean_.mutable_cpu_data()); @@ -115,9 +114,9 @@ void BatchNormLayer::Forward_cpu(const vector*>& bottom, caffe_powx(top[0]->count(), top_data, Dtype(2), temp_.mutable_cpu_data()); // (X-EX)^2 caffe_cpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, - 1. / (num * spatial_dim), temp_.cpu_data(), - spatial_sum_multiplier_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + 1. / (num * spatial_dim), temp_.cpu_data(), + spatial_sum_multiplier_.cpu_data(), 0., + num_by_chans_.mutable_cpu_data()); caffe_cpu_gemv(CblasTrans, num, channels_, 1., num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0., variance_.mutable_cpu_data()); // E((X_EX)^2) @@ -127,7 +126,7 @@ void BatchNormLayer::Forward_cpu(const vector*>& bottom, this->blobs_[2]->mutable_cpu_data()[0] += 1; caffe_cpu_axpby(mean_.count(), Dtype(1), mean_.cpu_data(), moving_average_fraction_, this->blobs_[0]->mutable_cpu_data()); - int m = bottom[0]->count()/channels_; + int_tp m = bottom[0]->count()/channels_; Dtype bias_correction_factor = m > 1 ? Dtype(m)/(m-1) : 1; caffe_cpu_axpby(variance_.count(), bias_correction_factor, variance_.cpu_data(), moving_average_fraction_, @@ -141,19 +140,19 @@ void BatchNormLayer::Forward_cpu(const vector*>& bottom, // replicate variance to input size caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.cpu_data(), variance_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + batch_sum_multiplier_.cpu_data(), variance_.cpu_data(), + 0., num_by_chans_.mutable_cpu_data()); caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, - spatial_dim, 1, 1., num_by_chans_.cpu_data(), - spatial_sum_multiplier_.cpu_data(), 0., temp_.mutable_cpu_data()); + spatial_dim, 1, 1., num_by_chans_.cpu_data(), + spatial_sum_multiplier_.cpu_data(), 0., + temp_.mutable_cpu_data()); caffe_div(temp_.count(), top_data, temp_.cpu_data(), top_data); // TODO(cdoersch): The caching is only needed because later in-place layers // might clobber the data. Can we skip this if they won't? - caffe_copy(x_norm_.count(), top_data, - x_norm_.mutable_cpu_data()); + caffe_copy(x_norm_.count(), top_data, x_norm_.mutable_cpu_data()); } -template +template void BatchNormLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { @@ -170,8 +169,8 @@ void BatchNormLayer::Backward_cpu(const vector*>& top, return; } const Dtype* top_data = x_norm_.cpu_data(); - int num = bottom[0]->shape()[0]; - int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_); + int_tp num = bottom[0]->shape()[0]; + int_tp spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_); // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then // // dE(Y)/dX = @@ -187,49 +186,50 @@ void BatchNormLayer::Backward_cpu(const vector*>& top, // sum(dE/dY \cdot Y) caffe_mul(temp_.count(), top_data, top_diff, bottom_diff); caffe_cpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, 1., - bottom_diff, spatial_sum_multiplier_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + bottom_diff, spatial_sum_multiplier_.cpu_data(), 0., + num_by_chans_.mutable_cpu_data()); caffe_cpu_gemv(CblasTrans, num, channels_, 1., - num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0., - mean_.mutable_cpu_data()); + num_by_chans_.cpu_data(), + batch_sum_multiplier_.cpu_data(), 0., + mean_.mutable_cpu_data()); // reshape (broadcast) the above caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0., + num_by_chans_.mutable_cpu_data()); caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, - spatial_dim, 1, 1., num_by_chans_.cpu_data(), - spatial_sum_multiplier_.cpu_data(), 0., bottom_diff); + spatial_dim, 1, 1., num_by_chans_.cpu_data(), + spatial_sum_multiplier_.cpu_data(), 0., bottom_diff); // sum(dE/dY \cdot Y) \cdot Y caffe_mul(temp_.count(), top_data, bottom_diff, bottom_diff); // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y caffe_cpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, 1., - top_diff, spatial_sum_multiplier_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + top_diff, spatial_sum_multiplier_.cpu_data(), 0., + num_by_chans_.mutable_cpu_data()); caffe_cpu_gemv(CblasTrans, num, channels_, 1., - num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0., - mean_.mutable_cpu_data()); + num_by_chans_.cpu_data(), + batch_sum_multiplier_.cpu_data(), 0., + mean_.mutable_cpu_data()); // reshape (broadcast) the above to make // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0., - num_by_chans_.mutable_cpu_data()); + batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0., + num_by_chans_.mutable_cpu_data()); caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, num * channels_, - spatial_dim, 1, 1., num_by_chans_.cpu_data(), - spatial_sum_multiplier_.cpu_data(), 1., bottom_diff); + spatial_dim, 1, 1., num_by_chans_.cpu_data(), + spatial_sum_multiplier_.cpu_data(), 1., bottom_diff); // dE/dY - mean(dE/dY)-mean(dE/dY \cdot Y) \cdot Y caffe_cpu_axpby(temp_.count(), Dtype(1), top_diff, - Dtype(-1. / (num * spatial_dim)), bottom_diff); + Dtype(-1. / (num * spatial_dim)), bottom_diff); // note: temp_ still contains sqrt(var(X)+eps), computed during the forward // pass. caffe_div(temp_.count(), bottom_diff, temp_.cpu_data(), bottom_diff); } - #ifdef CPU_ONLY STUB_GPU(BatchNormLayer); #endif diff --git a/src/caffe/layers/batch_norm_layer.cu b/src/caffe/layers/batch_norm_layer.cu index c21713c81d9..b2142bbac72 100644 --- a/src/caffe/layers/batch_norm_layer.cu +++ b/src/caffe/layers/batch_norm_layer.cu @@ -6,166 +6,396 @@ namespace caffe { -template +template void BatchNormLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - int num = bottom[0]->shape(0); - int spatial_dim = bottom[0]->count()/(channels_*bottom[0]->shape(0)); + int_tp num = bottom[0]->shape(0); + int_tp spatial_dim = bottom[0]->count() / (channels_ * bottom[0]->shape(0)); - if (bottom[0] != top[0]) { - caffe_copy(bottom[0]->count(), bottom_data, top_data); - } + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (bottom[0] != top[0]) { + caffe_copy(bottom[0]->count(), bottom_data, top_data); + } + + if (use_global_stats_) { + // use the stored mean/variance estimates. + const Dtype scale_factor = + this->blobs_[2]->cpu_data()[0] == 0 ? + 0 : 1 / this->blobs_[2]->cpu_data()[0]; + caffe_gpu_scale(variance_.count(), scale_factor, + this->blobs_[0]->gpu_data(), mean_.mutable_gpu_data()); + caffe_gpu_scale(variance_.count(), scale_factor, + this->blobs_[1]->gpu_data(), + variance_.mutable_gpu_data()); + } else { + // compute mean + caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, + 1. / (num * spatial_dim), bottom_data, + spatial_sum_multiplier_.gpu_data(), 0., + num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemv(CblasTrans, num, channels_, 1., + num_by_chans_.gpu_data(), + batch_sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); + } + + // subtract mean + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, + batch_sum_multiplier_.gpu_data(), mean_.gpu_data(), + 0., num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, + spatial_dim, 1, -1, num_by_chans_.gpu_data(), + spatial_sum_multiplier_.gpu_data(), 1., top_data); + + if (!use_global_stats_) { + // compute variance using var(X) = E((X-EX)^2) + caffe_gpu_powx(top[0]->count(), top_data, Dtype(2), + temp_.mutable_gpu_data()); // (X-EX)^2 + caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, + 1. / (num * spatial_dim), temp_.gpu_data(), + spatial_sum_multiplier_.gpu_data(), 0., + num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemv(CblasTrans, num, channels_, 1., + num_by_chans_.gpu_data(), + batch_sum_multiplier_.gpu_data(), 0., + variance_.mutable_gpu_data()); // E((X_EX)^2) + + // compute and save moving average + this->blobs_[2]->mutable_cpu_data()[0] *= moving_average_fraction_; + this->blobs_[2]->mutable_cpu_data()[0] += 1; + caffe_gpu_axpby(mean_.count(), Dtype(1), mean_.gpu_data(), + moving_average_fraction_, + this->blobs_[0]->mutable_gpu_data()); + int_tp m = bottom[0]->count() / channels_; + Dtype bias_correction_factor = m > 1 ? Dtype(m) / (m - 1) : 1; + caffe_gpu_axpby(variance_.count(), bias_correction_factor, + variance_.gpu_data(), moving_average_fraction_, + this->blobs_[1]->mutable_gpu_data()); + } + // normalize variance + caffe_gpu_add_scalar(variance_.count(), eps_, variance_.mutable_gpu_data()); + caffe_gpu_powx(variance_.count(), variance_.gpu_data(), Dtype(0.5), + variance_.mutable_gpu_data()); - if (use_global_stats_) { - // use the stored mean/variance estimates. - const Dtype scale_factor = this->blobs_[2]->cpu_data()[0] == 0 ? - 0 : 1 / this->blobs_[2]->cpu_data()[0]; - caffe_gpu_scale(variance_.count(), scale_factor, - this->blobs_[0]->gpu_data(), mean_.mutable_gpu_data()); - caffe_gpu_scale(variance_.count(), scale_factor, - this->blobs_[1]->gpu_data(), variance_.mutable_gpu_data()); + // replicate variance to input size + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, + batch_sum_multiplier_.gpu_data(), + variance_.gpu_data(), 0., + num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, + spatial_dim, 1, 1., num_by_chans_.gpu_data(), + spatial_sum_multiplier_.gpu_data(), 0., + temp_.mutable_gpu_data()); + caffe_gpu_div(temp_.count(), top_data, temp_.gpu_data(), top_data); + // TODO(cdoersch): The caching is only needed because later in-place layers + // might clobber the data. Can we skip this if they won't? + caffe_copy(x_norm_.count(), top_data, x_norm_.mutable_gpu_data()); +#endif // USE_CUDA } else { - // compute mean - caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, - 1. / (num * spatial_dim), bottom_data, - spatial_sum_multiplier_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemv(CblasTrans, num, channels_, 1., - num_by_chans_.gpu_data(), batch_sum_multiplier_.gpu_data(), 0., - mean_.mutable_gpu_data()); - } +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); - // subtract mean - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.gpu_data(), mean_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, - spatial_dim, 1, -1, num_by_chans_.gpu_data(), - spatial_sum_multiplier_.gpu_data(), 1., top_data); - - if (!use_global_stats_) { - // compute variance using var(X) = E((X-EX)^2) - caffe_gpu_powx(top[0]->count(), top_data, Dtype(2), - temp_.mutable_gpu_data()); // (X-EX)^2 - caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, - 1. / (num * spatial_dim), temp_.gpu_data(), - spatial_sum_multiplier_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemv(CblasTrans, num, channels_, 1., - num_by_chans_.gpu_data(), batch_sum_multiplier_.gpu_data(), 0., - variance_.mutable_gpu_data()); // E((X_EX)^2) - - // compute and save moving average - this->blobs_[2]->mutable_cpu_data()[0] *= moving_average_fraction_; - this->blobs_[2]->mutable_cpu_data()[0] += 1; - caffe_gpu_axpby(mean_.count(), Dtype(1), mean_.gpu_data(), - moving_average_fraction_, this->blobs_[0]->mutable_gpu_data()); - int m = bottom[0]->count()/channels_; - Dtype bias_correction_factor = m > 1 ? Dtype(m)/(m-1) : 1; - caffe_gpu_axpby(variance_.count(), bias_correction_factor, - variance_.gpu_data(), moving_average_fraction_, - this->blobs_[1]->mutable_gpu_data()); - } + if (bottom[0] != top[0]) { + greentea_copy(bottom[0]->count(), (cl_mem) bottom_data, 0, + (cl_mem) top_data, 0, &ctx); + } - // normalize variance - caffe_gpu_add_scalar(variance_.count(), eps_, variance_.mutable_gpu_data()); - caffe_gpu_powx(variance_.count(), variance_.gpu_data(), Dtype(0.5), - variance_.mutable_gpu_data()); - - // replicate variance to input size - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.gpu_data(), variance_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, - spatial_dim, 1, 1., num_by_chans_.gpu_data(), - spatial_sum_multiplier_.gpu_data(), 0., temp_.mutable_gpu_data()); - caffe_gpu_div(temp_.count(), top_data, temp_.gpu_data(), top_data); - // TODO(cdoersch): The caching is only needed because later in-place layers - // might clobber the data. Can we skip this if they won't? - caffe_copy(x_norm_.count(), top_data, - x_norm_.mutable_gpu_data()); + if (use_global_stats_) { + // use the stored mean/variance estimates. + const Dtype scale_factor = + this->blobs_[2]->cpu_data()[0] == 0 ? + 0 : 1 / this->blobs_[2]->cpu_data()[0]; + greentea_gpu_scale(this->device_->id(), variance_.count(), + scale_factor, + (cl_mem) (this->blobs_[0]->gpu_data()), 0, + (cl_mem) (mean_.mutable_gpu_data()), 0); + greentea_gpu_scale(this->device_->id(), variance_.count(), + scale_factor, + (cl_mem) (this->blobs_[1]->gpu_data()), 0, + (cl_mem) (variance_.mutable_gpu_data()), 0); + } else { + // compute mean + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, + channels_ * num, spatial_dim, + 1. / (num * spatial_dim), (cl_mem) bottom_data, + 0, (cl_mem) (spatial_sum_multiplier_.gpu_data()), + 0, 0., + (cl_mem) (num_by_chans_.mutable_gpu_data()), 0); + greentea_gpu_gemv(this->device_->id(), CblasTrans, num, channels_, + 1., (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) (mean_.mutable_gpu_data()), 0); + } + + // subtract mean + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num, channels_, 1, 1, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, + (cl_mem) (mean_.gpu_data()), 0, 0., + (cl_mem) (num_by_chans_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + channels_ * num, spatial_dim, 1, -1, + (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 1., (cl_mem) top_data, 0); + + if (!use_global_stats_) { + // compute variance using var(X) = E((X-EX)^2) + greentea_gpu_powx(this->device_->id(), top[0]->count(), + (cl_mem) top_data, 0, Dtype(2), + (cl_mem) (temp_.mutable_gpu_data()), 0); + // (X-EX)^2 + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, + channels_ * num, spatial_dim, + 1. / (num * spatial_dim), + (cl_mem) (temp_.gpu_data()), 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) (num_by_chans_.mutable_gpu_data()), + 0); + greentea_gpu_gemv(this->device_->id(), CblasTrans, num, channels_, + 1., (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) (variance_.mutable_gpu_data()), 0); + // E((X_EX)^2) + + // compute and save moving average + this->blobs_[2]->mutable_cpu_data()[0] *= moving_average_fraction_; + this->blobs_[2]->mutable_cpu_data()[0] += 1; + greentea_gpu_axpby(this->device_->id(), mean_.count(), Dtype(1), + (cl_mem) (mean_.gpu_data()), 0, + moving_average_fraction_, + (cl_mem) (this->blobs_[0]->mutable_gpu_data()), + 0); + int_tp m = bottom[0]->count() / channels_; + Dtype bias_correction_factor = m > 1 ? Dtype(m) / (m - 1) : 1; + greentea_gpu_axpby(this->device_->id(), variance_.count(), + bias_correction_factor, + (cl_mem) (variance_.gpu_data()), 0, + moving_average_fraction_, + (cl_mem) (this->blobs_[1]->mutable_gpu_data()), + 0); + } + + // normalize variance + greentea_gpu_add_scalar(this->device_->id(), variance_.count(), eps_, + (cl_mem) (variance_.mutable_gpu_data()), 0); + greentea_gpu_powx(this->device_->id(), variance_.count(), + (cl_mem) (variance_.gpu_data()), 0, Dtype(0.5), + (cl_mem) (variance_.mutable_gpu_data()), 0); + + // replicate variance to input size + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num, channels_, 1, 1, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, + (cl_mem) (variance_.gpu_data()), 0, 0., + (cl_mem) (num_by_chans_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + channels_ * num, spatial_dim, 1, 1., + (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) (temp_.mutable_gpu_data()), 0); + greentea_gpu_div(this->device_->id(), temp_.count(), + (cl_mem) top_data, 0, (cl_mem) (temp_.gpu_data()), + 0, (cl_mem) top_data, 0); + // TODO(cdoersch): The caching is only needed because later in-place layers + // might clobber the data. Can we skip this if they won't? + greentea_copy(x_norm_.count(), (cl_mem) top_data, 0, + (cl_mem) (x_norm_.mutable_gpu_data()), 0, &ctx); +#endif // USE_GREENTEA + } } -template +template void BatchNormLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* top_diff; - if (bottom[0] != top[0]) { - top_diff = top[0]->gpu_diff(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (bottom[0] != top[0]) { + top_diff = top[0]->gpu_diff(); + } else { + caffe_copy(x_norm_.count(), top[0]->gpu_diff(), + x_norm_.mutable_gpu_diff()); + top_diff = x_norm_.gpu_diff(); + } + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + if (use_global_stats_) { + caffe_gpu_div(temp_.count(), top_diff, temp_.gpu_data(), bottom_diff); + return; + } + const Dtype* top_data = x_norm_.gpu_data(); + int_tp num = bottom[0]->shape()[0]; + int_tp spatial_dim = bottom[0]->count() / (channels_ * bottom[0]->shape(0)); + // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then + // + // dE(Y)/dX = + // (dE/dY - mean(dE/dY) - mean(dE/dY \cdot Y) \cdot Y) + // ./ sqrt(var(X) + eps) + // + // where \cdot and ./ are hadamard product and elementwise division, + // respectively, dE/dY is the top diff, and mean/var/sum are all computed + // along all dimensions except the channels dimension. In the above + // equation, the operations allow for expansion (i.e. broadcast) along all + // dimensions except the channels dimension where required. + + // sum(dE/dY \cdot Y) + caffe_gpu_mul(temp_.count(), top_data, top_diff, bottom_diff); + caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, 1., + bottom_diff, spatial_sum_multiplier_.gpu_data(), 0., + num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemv(CblasTrans, num, channels_, 1., + num_by_chans_.gpu_data(), + batch_sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); + + // reshape (broadcast) the above + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, + batch_sum_multiplier_.gpu_data(), mean_.gpu_data(), + 0., num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, + spatial_dim, 1, 1., num_by_chans_.gpu_data(), + spatial_sum_multiplier_.gpu_data(), 0., bottom_diff); + + // sum(dE/dY \cdot Y) \cdot Y + caffe_gpu_mul(temp_.count(), top_data, bottom_diff, bottom_diff); + + // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y + caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, 1., + top_diff, spatial_sum_multiplier_.gpu_data(), 0., + num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemv(CblasTrans, num, channels_, 1., + num_by_chans_.gpu_data(), + batch_sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); + // reshape (broadcast) the above to make + // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, + batch_sum_multiplier_.gpu_data(), mean_.gpu_data(), + 0., num_by_chans_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num * channels_, + spatial_dim, 1, 1., num_by_chans_.gpu_data(), + spatial_sum_multiplier_.gpu_data(), 1., bottom_diff); + + // dE/dY - mean(dE/dY)-mean(dE/dY \cdot Y) \cdot Y + caffe_gpu_axpby(temp_.count(), Dtype(1), top_diff, + Dtype(-1. / (num * spatial_dim)), bottom_diff); + + // note: temp_ still contains sqrt(var(X)+eps), computed during the forward + // pass. + caffe_gpu_div(temp_.count(), bottom_diff, temp_.gpu_data(), + bottom_diff); +#endif // USE_CUDA } else { - caffe_copy(x_norm_.count(), top[0]->gpu_diff(), x_norm_.mutable_gpu_diff()); - top_diff = x_norm_.gpu_diff(); - } - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - if (use_global_stats_) { - caffe_gpu_div(temp_.count(), top_diff, temp_.gpu_data(), bottom_diff); - return; +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (bottom[0] != top[0]) { + top_diff = top[0]->gpu_diff(); + } else { + greentea_copy(x_norm_.count(), (cl_mem) (top[0]->gpu_diff()), 0, + (cl_mem) (x_norm_.mutable_gpu_diff()), 0, &ctx); + top_diff = x_norm_.gpu_diff(); + } + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + if (use_global_stats_) { + greentea_gpu_div(this->device_->id(), temp_.count(), + (cl_mem) top_diff, 0, (cl_mem) (temp_.gpu_data()), + 0, (cl_mem) bottom_diff, 0); + return; + } + const Dtype* top_data = x_norm_.gpu_data(); + int_tp num = bottom[0]->shape()[0]; + int_tp spatial_dim = bottom[0]->count() / (channels_ * bottom[0]->shape(0)); + // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then + // + // dE(Y)/dX = + // (dE/dY - mean(dE/dY) - mean(dE/dY \cdot Y) \cdot Y) + // ./ sqrt(var(X) + eps) + // + // where \cdot and ./ are hadamard product and elementwise division, + // respectively, dE/dY is the top diff, and mean/var/sum are all computed + // along all dimensions except the channels dimension. In the above + // equation, the operations allow for expansion (i.e. broadcast) along all + // dimensions except the channels dimension where required. + + // sum(dE/dY \cdot Y) + greentea_gpu_mul(this->device_->id(), temp_.count(), + (cl_mem) top_data, 0, (cl_mem) top_diff, 0, + (cl_mem) bottom_diff, 0); + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, channels_ * num, + spatial_dim, 1., (cl_mem) bottom_diff, 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) (num_by_chans_.mutable_gpu_data()), + 0); + greentea_gpu_gemv(this->device_->id(), CblasTrans, num, channels_, + 1., (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (mean_.mutable_gpu_data()), 0); + + // reshape (broadcast) the above + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num, channels_, 1, 1, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, + (cl_mem) (mean_.gpu_data()), 0, 0., + (cl_mem) (num_by_chans_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + channels_ * num, spatial_dim, 1, 1., + (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) bottom_diff, 0); + + // sum(dE/dY \cdot Y) \cdot Y + greentea_gpu_mul(this->device_->id(), temp_.count(), + (cl_mem) top_data, 0, (cl_mem) bottom_diff, 0, + (cl_mem) bottom_diff, 0); + + // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, channels_ * num, + spatial_dim, 1., (cl_mem) top_diff, 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 0., (cl_mem) (num_by_chans_.mutable_gpu_data()), + 0); + greentea_gpu_gemv(this->device_->id(), CblasTrans, num, channels_, + 1., (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (mean_.mutable_gpu_data()), 0); + // reshape (broadcast) the above to make + // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num, channels_, 1, 1, + (cl_mem) (batch_sum_multiplier_.gpu_data()), 0, + (cl_mem) (mean_.gpu_data()), 0, 0., + (cl_mem) (num_by_chans_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num * channels_, spatial_dim, 1, 1., + (cl_mem) (num_by_chans_.gpu_data()), 0, + (cl_mem) (spatial_sum_multiplier_.gpu_data()), 0, + 1., (cl_mem) bottom_diff, 0); + + // dE/dY - mean(dE/dY)-mean(dE/dY \cdot Y) \cdot Y + greentea_gpu_axpby(this->device_->id(), temp_.count(), Dtype(1), + (cl_mem) top_diff, 0, + Dtype(-1. / (num * spatial_dim)), + (cl_mem) bottom_diff, 0); + + // note: temp_ still contains sqrt(var(X)+eps), computed during the forward + // pass. + greentea_gpu_div(this->device_->id(), temp_.count(), + (cl_mem) bottom_diff, 0, + (cl_mem) (temp_.gpu_data()), 0, + (cl_mem) bottom_diff, 0); +#endif // USE_GREENTEA } - const Dtype* top_data = x_norm_.gpu_data(); - int num = bottom[0]->shape()[0]; - int spatial_dim = bottom[0]->count()/(channels_*bottom[0]->shape(0)); - // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then - // - // dE(Y)/dX = - // (dE/dY - mean(dE/dY) - mean(dE/dY \cdot Y) \cdot Y) - // ./ sqrt(var(X) + eps) - // - // where \cdot and ./ are hadamard product and elementwise division, - // respectively, dE/dY is the top diff, and mean/var/sum are all computed - // along all dimensions except the channels dimension. In the above - // equation, the operations allow for expansion (i.e. broadcast) along all - // dimensions except the channels dimension where required. - - // sum(dE/dY \cdot Y) - caffe_gpu_mul(temp_.count(), top_data, top_diff, bottom_diff); - caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, 1., - bottom_diff, spatial_sum_multiplier_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemv(CblasTrans, num, channels_, 1., - num_by_chans_.gpu_data(), batch_sum_multiplier_.gpu_data(), 0., - mean_.mutable_gpu_data()); - - // reshape (broadcast) the above - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.gpu_data(), mean_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, channels_ * num, - spatial_dim, 1, 1., num_by_chans_.gpu_data(), - spatial_sum_multiplier_.gpu_data(), 0., bottom_diff); - - // sum(dE/dY \cdot Y) \cdot Y - caffe_gpu_mul(temp_.count(), top_data, bottom_diff, bottom_diff); - - // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y - caffe_gpu_gemv(CblasNoTrans, channels_ * num, spatial_dim, 1., - top_diff, spatial_sum_multiplier_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemv(CblasTrans, num, channels_, 1., - num_by_chans_.gpu_data(), batch_sum_multiplier_.gpu_data(), 0., - mean_.mutable_gpu_data()); - // reshape (broadcast) the above to make - // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, - batch_sum_multiplier_.gpu_data(), mean_.gpu_data(), 0., - num_by_chans_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num * channels_, - spatial_dim, 1, 1., num_by_chans_.gpu_data(), - spatial_sum_multiplier_.gpu_data(), 1., bottom_diff); - - // dE/dY - mean(dE/dY)-mean(dE/dY \cdot Y) \cdot Y - caffe_gpu_axpby(temp_.count(), Dtype(1), top_diff, - Dtype(-1. / (num * spatial_dim)), bottom_diff); - - // note: temp_ still contains sqrt(var(X)+eps), computed during the forward - // pass. - caffe_gpu_div(temp_.count(), bottom_diff, temp_.gpu_data(), bottom_diff); } INSTANTIATE_LAYER_GPU_FUNCS(BatchNormLayer); - } // namespace caffe diff --git a/src/caffe/layers/batch_reindex_layer.cpp b/src/caffe/layers/batch_reindex_layer.cpp index b14e56f7c6b..d215131489c 100644 --- a/src/caffe/layers/batch_reindex_layer.cpp +++ b/src/caffe/layers/batch_reindex_layer.cpp @@ -9,19 +9,19 @@ template void BatchReindexLayer::Reshape(const vector*>& bottom, const vector*>& top) { CHECK_EQ(1, bottom[1]->num_axes()); - vector newshape; + vector newshape; newshape.push_back(bottom[1]->shape(0)); - for (int i = 1; i < bottom[0]->shape().size(); ++i) { + for (int_tp i = 1; i < bottom[0]->shape().size(); ++i) { newshape.push_back(bottom[0]->shape()[i]); } top[0]->Reshape(newshape); } template -void BatchReindexLayer::check_batch_reindex(int initial_num, - int final_num, +void BatchReindexLayer::check_batch_reindex(int_tp initial_num, + int_tp final_num, const Dtype* ridx_data) { - for (int i = 0; i < final_num; ++i) { + for (int_tp i = 0; i < final_num; ++i) { CHECK_GE(ridx_data[i], 0) << "Index specified for reindex layer was negative."; CHECK_LT(ridx_data[i], initial_num) @@ -37,13 +37,13 @@ void BatchReindexLayer::Forward_cpu(const vector*>& bottom, if (top[0]->count() == 0) { return; } - int inner_dim = bottom[0]->count() / bottom[0]->shape(0); + int_tp inner_dim = bottom[0]->count() / bottom[0]->shape(0); const Dtype* in = bottom[0]->cpu_data(); const Dtype* permut = bottom[1]->cpu_data(); Dtype* out = top[0]->mutable_cpu_data(); - for (int index = 0; index < top[0]->count(); ++index) { - int n = index / (inner_dim); - int in_n = static_cast(permut[n]); + for (int_tp index = 0; index < top[0]->count(); ++index) { + int_tp n = index / (inner_dim); + int_tp in_n = static_cast(permut[n]); out[index] = in[in_n * (inner_dim) + index % (inner_dim)]; } } @@ -56,14 +56,14 @@ void BatchReindexLayer::Backward_cpu( if (!propagate_down[0]) { return; } - int inner_dim = bottom[0]->count() / bottom[0]->shape(0); + int_tp inner_dim = bottom[0]->count() / bottom[0]->shape(0); Dtype* bot_diff = bottom[0]->mutable_cpu_diff(); const Dtype* permut = bottom[1]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); caffe_set(bottom[0]->count(), Dtype(0), bot_diff); - for (int index = 0; index < top[0]->count(); ++index) { - int n = index / (inner_dim); - int in_n = static_cast(permut[n]); + for (int_tp index = 0; index < top[0]->count(); ++index) { + int_tp n = index / (inner_dim); + int_tp in_n = static_cast(permut[n]); bot_diff[in_n * (inner_dim) + index % (inner_dim)] += top_diff[index]; } } diff --git a/src/caffe/layers/batch_reindex_layer.cu b/src/caffe/layers/batch_reindex_layer.cu index 83054d36d33..d4cffe03ab1 100644 --- a/src/caffe/layers/batch_reindex_layer.cu +++ b/src/caffe/layers/batch_reindex_layer.cu @@ -7,15 +7,17 @@ namespace caffe { +#ifdef USE_CUDA template -__global__ void BRForward(const int count, const int inner_dim, const Dtype* in, - const Dtype* permut, Dtype* out) { +__global__ void BRForward(const int_tp count, const int_tp inner_dim, + const Dtype* in, const Dtype* permut, Dtype* out) { CUDA_KERNEL_LOOP(index, count) { - int n = index / (inner_dim); - int in_n = static_cast(permut[n]); + int_tp n = index / (inner_dim); + int_tp in_n = static_cast(permut[n]); out[index] = in[in_n * (inner_dim) + index % (inner_dim)]; } } +#endif // USE_CUDA template void BatchReindexLayer::Forward_gpu(const vector*>& bottom, @@ -25,30 +27,54 @@ void BatchReindexLayer::Forward_gpu(const vector*>& bottom, if (top[0]->count() == 0) { return; } - int threads = top[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - BRForward <<>>( - top[0]->count(), bottom[0]->count() / bottom[0]->shape(0), - bottom[0]->gpu_data(), bottom[1]->gpu_data(), top[0]->mutable_gpu_data()); - CUDA_POST_KERNEL_CHECK; + int_tp threads = top[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + BRForward CUDA_KERNEL(CAFFE_GET_BLOCKS(threads), + CAFFE_CUDA_NUM_THREADS) ( + top[0]->count(), bottom[0]->count() / bottom[0]->shape(0), + bottom[0]->gpu_data(), bottom[1]->gpu_data(), + top[0]->mutable_gpu_data()); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_br = program.get_kernel( + CL_KERNEL_SELECT("br_forward")); + viennacl::ocl::enqueue( + oclk_br(top[0]->count(), bottom[0]->count() / bottom[0]->shape(0), + WrapHandle((cl_mem) (bottom[0]->gpu_data()), &ctx), + WrapHandle((cl_mem) (bottom[1]->gpu_data()), &ctx), + WrapHandle((cl_mem) (top[0]->mutable_gpu_data()), &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } +#ifdef USE_CUDA template -__global__ void BRBackward(const int count, const int inner_dim, +__global__ void BRBackward(const int_tp count, const int_tp inner_dim, const Dtype* in, const Dtype* top_indexes, const Dtype* begins, const Dtype* counts, Dtype* out) { CUDA_KERNEL_LOOP(index, count) { - int n = index / (inner_dim); + int_tp n = index / (inner_dim); out[index] = 0; - int lower = static_cast(begins[n]); - int upper = lower + static_cast(counts[n]); - for (int i = lower; i < upper; ++i) { - int in_n = static_cast(top_indexes[i]); + int_tp lower = static_cast(begins[n]); + int_tp upper = lower + static_cast(counts[n]); + for (int_tp i = lower; i < upper; ++i) { + int_tp in_n = static_cast(top_indexes[i]); out[index] += in[in_n * (inner_dim) + index % (inner_dim)]; } } } +#endif // USE_CUDA template void BatchReindexLayer::Backward_gpu( @@ -59,10 +85,10 @@ void BatchReindexLayer::Backward_gpu( return; } - vector > mapping; + vector > mapping; const Dtype* perm = bottom[1]->cpu_data(); - for (int i = 0; i < bottom[1]->count(); ++i) { - mapping.push_back(pair(static_cast(perm[i]), i)); + for (int_tp i = 0; i < bottom[1]->count(); ++i) { + mapping.push_back(pair(static_cast(perm[i]), i)); } std::sort(mapping.begin(), mapping.end(), pair_sort_first()); @@ -73,18 +99,18 @@ void BatchReindexLayer::Backward_gpu( // k'th element of `begins` points to the location in `top_indexes` where the // list for the k'th example begin, and the k'th element of `counts` is the // length of that list. - vector shape; + vector shape; shape.push_back(bottom[1]->count()); - Blob top_indexes(shape); + Blob top_indexes(shape, this->device_); shape[0] = bottom[0]->shape(0); - Blob counts(shape); - Blob begins(shape); + Blob counts(shape, this->device_); + Blob begins(shape, this->device_); Dtype* t_i_data = top_indexes.mutable_cpu_data(); Dtype* c_data = counts.mutable_cpu_data(); Dtype* b_data = begins.mutable_cpu_data(); caffe_set(begins.count(), Dtype(-1), b_data); caffe_set(counts.count(), Dtype(0), c_data); - for (int i = 0; i < mapping.size(); ++i) { + for (int_tp i = 0; i < mapping.size(); ++i) { t_i_data[i] = mapping[i].second; if (b_data[mapping[i].first] == -1) { b_data[mapping[i].first] = i; @@ -92,13 +118,36 @@ void BatchReindexLayer::Backward_gpu( c_data[mapping[i].first] += 1; } - int threads = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - BRBackward <<>>( - bottom[0]->count(), bottom[0]->count() / bottom[0]->shape(0), - top[0]->gpu_diff(), top_indexes.gpu_data(), begins.gpu_data(), - counts.gpu_data(), bottom[0]->mutable_gpu_diff()); - CUDA_POST_KERNEL_CHECK; + int_tp threads = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + BRBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(threads), + CAFFE_CUDA_NUM_THREADS) ( + bottom[0]->count(), bottom[0]->count() / bottom[0]->shape(0), + top[0]->gpu_diff(), top_indexes.gpu_data(), begins.gpu_data(), + counts.gpu_data(), bottom[0]->mutable_gpu_diff()); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_br = program.get_kernel( + CL_KERNEL_SELECT("br_backward")); + viennacl::ocl::enqueue( + oclk_br(bottom[0]->count(), bottom[0]->count() / bottom[0]->shape(0), + WrapHandle((cl_mem)(top[0]->gpu_diff()), &ctx), + WrapHandle((cl_mem)(top_indexes.gpu_data()), &ctx), + WrapHandle((cl_mem)(begins.gpu_data()), &ctx), + WrapHandle((cl_mem)(counts.gpu_data()), &ctx), + WrapHandle((cl_mem)(bottom[0]->mutable_gpu_diff()), &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } INSTANTIATE_LAYER_GPU_FUNCS(BatchReindexLayer); diff --git a/src/caffe/layers/bias_layer.cpp b/src/caffe/layers/bias_layer.cpp index 4726a729834..28e4bb6b819 100644 --- a/src/caffe/layers/bias_layer.cpp +++ b/src/caffe/layers/bias_layer.cpp @@ -14,8 +14,8 @@ void BiasLayer::LayerSetUp(const vector*>& bottom, } else if (bottom.size() == 1) { // bias is a learned parameter; initialize it const BiasParameter& param = this->layer_param_.bias_param(); - const int axis = bottom[0]->CanonicalAxisIndex(param.axis()); - const int num_axes = param.num_axes(); + const int_tp axis = bottom[0]->CanonicalAxisIndex(param.axis()); + const int_tp num_axes = param.num_axes(); CHECK_GE(num_axes, -1) << "num_axes must be non-negative, " << "or -1 to extend to the end of bottom[0]"; if (num_axes >= 0) { @@ -24,11 +24,11 @@ void BiasLayer::LayerSetUp(const vector*>& bottom, << "starting with bottom[0] axis = " << axis; } this->blobs_.resize(1); - const vector::const_iterator& shape_start = + const vector::const_iterator& shape_start = bottom[0]->shape().begin() + axis; - const vector::const_iterator& shape_end = + const vector::const_iterator& shape_end = (num_axes == -1) ? bottom[0]->shape().end() : (shape_start + num_axes); - vector bias_shape(shape_start, shape_end); + vector bias_shape(shape_start, shape_end); this->blobs_[0].reset(new Blob(bias_shape)); shared_ptr > filler(GetFiller(param.filler())); filler->Fill(this->blobs_[0].get()); @@ -45,12 +45,12 @@ void BiasLayer::Reshape(const vector*>& bottom, // (num_axes == 0). Mathematically equivalent for any choice of axis, so the // actual setting can be safely ignored; and computation is most efficient // with axis == 0 and (therefore) outer_dim_ == 1. - const int axis = (bias->num_axes() == 0) ? + const int_tp axis = (bias->num_axes() == 0) ? 0 : bottom[0]->CanonicalAxisIndex(param.axis()); CHECK_GE(bottom[0]->num_axes(), axis + bias->num_axes()) << "bias blob's shape extends past bottom[0]'s shape when applied " << "starting with bottom[0] axis = " << axis; - for (int i = 0; i < bias->num_axes(); ++i) { + for (int_tp i = 0; i < bias->num_axes(); ++i) { CHECK_EQ(bottom[0]->shape(axis + i), bias->shape(i)) << "dimension mismatch between bottom[0]->shape(" << axis + i << ") and bias->shape(" << i << ")"; @@ -62,7 +62,7 @@ void BiasLayer::Reshape(const vector*>& bottom, if (bottom[0] != top[0]) { top[0]->ReshapeLike(*bottom[0]); } - bias_multiplier_.Reshape(vector(1, inner_dim_)); + bias_multiplier_.Reshape(vector(1, inner_dim_)); if (bias_multiplier_.cpu_data()[inner_dim_ - 1] != Dtype(1)) { caffe_set(inner_dim_, Dtype(1), bias_multiplier_.mutable_cpu_data()); } @@ -78,7 +78,7 @@ void BiasLayer::Forward_cpu(const vector*>& bottom, const Dtype* bottom_data = bottom[0]->cpu_data(); caffe_copy(bottom[0]->count(), bottom_data, top_data); } - for (int n = 0; n < outer_dim_; ++n) { + for (int_tp n = 0; n < outer_dim_; ++n) { caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, bias_dim_, inner_dim_, 1, Dtype(1), bias_data, bias_multiplier_.cpu_data(), Dtype(1), top_data); @@ -102,7 +102,7 @@ void BiasLayer::Backward_cpu(const vector*>& top, Dtype* bias_diff = (bias_param ? this->blobs_[0].get() : bottom[1]) ->mutable_cpu_diff(); bool accum = bias_param; - for (int n = 0; n < outer_dim_; ++n) { + for (int_tp n = 0; n < outer_dim_; ++n) { caffe_cpu_gemv(CblasNoTrans, bias_dim_, inner_dim_, Dtype(1), top_diff, bias_multiplier_.cpu_data(), Dtype(accum), bias_diff); top_diff += dim_; diff --git a/src/caffe/layers/bias_layer.cu b/src/caffe/layers/bias_layer.cu index 8ac913a5d7b..7ce6fd5db85 100644 --- a/src/caffe/layers/bias_layer.cu +++ b/src/caffe/layers/bias_layer.cu @@ -4,53 +4,116 @@ #include "caffe/layers/bias_layer.hpp" #include "caffe/util/math_functions.hpp" + +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { +#ifdef USE_CUDA template -__global__ void BiasForward(const int n, const Dtype* in, - const Dtype* bias, const int bias_dim, const int inner_dim, +__global__ void BiasForward(const int_tp n, const Dtype* in, + const Dtype* bias, const int_tp bias_dim, const int_tp inner_dim, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { - const int bias_index = (index / inner_dim) % bias_dim; + const int_tp bias_index = (index / inner_dim) % bias_dim; out[index] = in[index] + bias[bias_index]; } } +#endif // USE_CUDA template void BiasLayer::Forward_gpu(const vector*>& bottom, const vector*>& top) { - const int count = top[0]->count(); + const int_tp count = top[0]->count(); const Dtype* bottom_data = bottom[0]->gpu_data(); const Dtype* bias_data = ((bottom.size() > 1) ? bottom[1] : this->blobs_[0].get())->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - BiasForward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - count, bottom_data, bias_data, bias_dim_, inner_dim_, top_data); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + BiasForward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bias_data, bias_dim_, inner_dim_, top_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + viennacl::ocl::kernel &oclk_bias_forward = program.get_kernel( + CL_KERNEL_SELECT("bias_forward")); + viennacl::ocl::enqueue( + oclk_bias_forward(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) bias_data, &ctx), bias_dim_, + inner_dim_, WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template +template void BiasLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (propagate_down[0] && bottom[0] != top[0]) { - const Dtype* top_diff = top[0]->gpu_diff(); - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - caffe_copy(bottom[0]->count(), top_diff, bottom_diff); - } - // in-place, we don't need to do anything with the data diff - const bool bias_param = (bottom.size() == 1); - if ((!bias_param && propagate_down[1]) || - (bias_param && this->param_propagate_down_[0])) { - const Dtype* top_diff = top[0]->gpu_diff(); - Dtype* bias_diff = (bias_param ? this->blobs_[0].get() : bottom[1]) - ->mutable_gpu_diff(); - bool accum = bias_param; - for (int n = 0; n < outer_dim_; ++n) { - caffe_gpu_gemv(CblasNoTrans, bias_dim_, inner_dim_, Dtype(1), - top_diff, bias_multiplier_.gpu_data(), Dtype(accum), bias_diff); - top_diff += dim_; - accum = true; + const vector& propagate_down, + const vector*>& bottom) { + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (propagate_down[0] && bottom[0] != top[0]) { + const Dtype* top_diff = top[0]->gpu_diff(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + caffe_copy(bottom[0]->count(), top_diff, bottom_diff); + } + // in-place, we don't need to do anything with the data diff + const bool bias_param = (bottom.size() == 1); + if ((!bias_param && propagate_down[1]) + || (bias_param && this->param_propagate_down_[0])) { + const Dtype* top_diff = top[0]->gpu_diff(); + Dtype* bias_diff = (bias_param ? this->blobs_[0].get() : bottom[1]) + ->mutable_gpu_diff(); + bool accum = bias_param; + + for (int_tp n = 0; n < outer_dim_; ++n) { + caffe_gpu_gemv(CblasNoTrans, bias_dim_, inner_dim_, Dtype(1), top_diff, + bias_multiplier_.gpu_data(), Dtype(accum), bias_diff); + top_diff += dim_; + accum = true; + } + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (propagate_down[0] && bottom[0] != top[0]) { + const Dtype* top_diff = top[0]->gpu_diff(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + greentea_copy(bottom[0]->count(), (cl_mem) top_diff, 0, + (cl_mem) bottom_diff, 0, &ctx); + } + // in-place, we don't need to do anything with the data diff + const bool bias_param = (bottom.size() == 1); + if ((!bias_param && propagate_down[1]) + || (bias_param && this->param_propagate_down_[0])) { + const Dtype* top_diff = top[0]->gpu_diff(); + Dtype* bias_diff = (bias_param ? this->blobs_[0].get() : bottom[1]) + ->mutable_gpu_diff(); + bool accum = bias_param; + + int_tp top_diff_off = 0; + for (int_tp n = 0; n < outer_dim_; ++n) { + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, bias_dim_, + inner_dim_, Dtype(1), (cl_mem) top_diff, top_diff_off, + (cl_mem) (bias_multiplier_.gpu_data()), 0, + Dtype(accum), (cl_mem) bias_diff, 0); + top_diff_off += dim_; + accum = true; + } } +#endif // USE_GREENTEA } } diff --git a/src/caffe/layers/bnll_layer.cpp b/src/caffe/layers/bnll_layer.cpp index 448d86d752d..8ae26aa6a00 100644 --- a/src/caffe/layers/bnll_layer.cpp +++ b/src/caffe/layers/bnll_layer.cpp @@ -5,15 +5,13 @@ namespace caffe { -const float kBNLL_THRESHOLD = 50.; - template void BNLLLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); - for (int i = 0; i < count; ++i) { + const int_tp count = bottom[0]->count(); + for (int_tp i = 0; i < count; ++i) { top_data[i] = bottom_data[i] > 0 ? bottom_data[i] + log(1. + exp(-bottom_data[i])) : log(1. + exp(bottom_data[i])); @@ -28,9 +26,9 @@ void BNLLLayer::Backward_cpu(const vector*>& top, const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); Dtype expval; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { expval = exp(std::min(bottom_data[i], Dtype(kBNLL_THRESHOLD))); bottom_diff[i] = top_diff[i] * expval / (expval + 1.); } diff --git a/src/caffe/layers/bnll_layer.cu b/src/caffe/layers/bnll_layer.cu index 8df8ef09afe..c121497f7b0 100644 --- a/src/caffe/layers/bnll_layer.cu +++ b/src/caffe/layers/bnll_layer.cu @@ -3,57 +3,102 @@ #include "caffe/layers/bnll_layer.hpp" -namespace caffe { +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif -const float kBNLL_THRESHOLD = 50.; +namespace caffe { -template -__global__ void BNLLForward(const int n, const Dtype* in, Dtype* out) { +#ifdef USE_CUDA +template +__global__ void BNLLForward(const int_tp n, const Dtype* in, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { - out[index] = in[index] > 0 ? - in[index] + log(1. + exp(-in[index])) : - log(1. + exp(in[index])); + out[index] = + in[index] > 0 ? + in[index] + log(1. + exp(-in[index])) : log(1. + exp(in[index])); } } +#endif // USE_CUDA -template +template void BNLLLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - BNLLForward<<>>( - count, bottom_data, top_data); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + BNLLForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, top_data); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_bnll = program.get_kernel( + CL_KERNEL_SELECT("bnll_forward")); + viennacl::ocl::enqueue( + oclk_bnll(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template -__global__ void BNLLBackward(const int n, const Dtype* in_diff, - const Dtype* in_data, Dtype* out_diff) { +#ifdef USE_CUDA +template +__global__ void BNLLBackward(const int_tp n, const Dtype* in_diff, + const Dtype* in_data, Dtype* out_diff) { CUDA_KERNEL_LOOP(index, n) { Dtype expval = exp(min(in_data[index], Dtype(kBNLL_THRESHOLD))); out_diff[index] = in_diff[index] * expval / (expval + 1.); } } +#endif // USE_CUDA -template +template void BNLLLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[0]) { const Dtype* bottom_data = bottom[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - BNLLBackward<<>>( - count, top_diff, bottom_data, bottom_diff); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + BNLLBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, bottom_data, bottom_diff); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_bnll = program.get_kernel( + CL_KERNEL_SELECT("bnll_backward")); + viennacl::ocl::enqueue( + oclk_bnll(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } } INSTANTIATE_LAYER_GPU_FUNCS(BNLLLayer); - } // namespace caffe diff --git a/src/caffe/layers/concat_layer.cpp b/src/caffe/layers/concat_layer.cpp index 580bd47977d..ad30a923962 100644 --- a/src/caffe/layers/concat_layer.cpp +++ b/src/caffe/layers/concat_layer.cpp @@ -16,10 +16,10 @@ void ConcatLayer::LayerSetUp(const vector*>& bottom, template void ConcatLayer::Reshape(const vector*>& bottom, const vector*>& top) { - const int num_axes = bottom[0]->num_axes(); + const int_tp num_axes = bottom[0]->num_axes(); const ConcatParameter& concat_param = this->layer_param_.concat_param(); if (concat_param.has_concat_dim()) { - concat_axis_ = static_cast(concat_param.concat_dim()); + concat_axis_ = static_cast(concat_param.concat_dim()); // Don't allow negative indexing for concat_dim, a uint32 -- almost // certainly unintended. CHECK_GE(concat_axis_, 0) << "casting concat_dim from uint32 to int32 " @@ -30,14 +30,14 @@ void ConcatLayer::Reshape(const vector*>& bottom, concat_axis_ = bottom[0]->CanonicalAxisIndex(concat_param.axis()); } // Initialize with the first blob. - vector top_shape = bottom[0]->shape(); + vector top_shape = bottom[0]->shape(); num_concats_ = bottom[0]->count(0, concat_axis_); concat_input_size_ = bottom[0]->count(concat_axis_ + 1); - int bottom_count_sum = bottom[0]->count(); - for (int i = 1; i < bottom.size(); ++i) { + int_tp bottom_count_sum = bottom[0]->count(); + for (int_tp i = 1; i < bottom.size(); ++i) { CHECK_EQ(num_axes, bottom[i]->num_axes()) << "All inputs must have the same #axes."; - for (int j = 0; j < num_axes; ++j) { + for (int_tp j = 0; j < num_axes; ++j) { if (j == concat_axis_) { continue; } CHECK_EQ(top_shape[j], bottom[i]->shape(j)) << "All inputs must have the same shape, except at concat_axis."; @@ -58,13 +58,13 @@ void ConcatLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { if (bottom.size() == 1) { return; } Dtype* top_data = top[0]->mutable_cpu_data(); - int offset_concat_axis = 0; - const int top_concat_axis = top[0]->shape(concat_axis_); - for (int i = 0; i < bottom.size(); ++i) { + int_tp offset_concat_axis = 0; + const int_tp top_concat_axis = top[0]->shape(concat_axis_); + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->cpu_data(); - const int bottom_concat_axis = bottom[i]->shape(concat_axis_); - for (int n = 0; n < num_concats_; ++n) { - caffe_copy(bottom_concat_axis * concat_input_size_, + const int_tp bottom_concat_axis = bottom[i]->shape(concat_axis_); + for (int_tp n = 0; n < num_concats_; ++n) { + caffe_cpu_copy(bottom_concat_axis * concat_input_size_, bottom_data + n * bottom_concat_axis * concat_input_size_, top_data + (n * top_concat_axis + offset_concat_axis) * concat_input_size_); @@ -78,14 +78,14 @@ void ConcatLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (bottom.size() == 1) { return; } const Dtype* top_diff = top[0]->cpu_diff(); - int offset_concat_axis = 0; - const int top_concat_axis = top[0]->shape(concat_axis_); - for (int i = 0; i < bottom.size(); ++i) { - const int bottom_concat_axis = bottom[i]->shape(concat_axis_); + int_tp offset_concat_axis = 0; + const int_tp top_concat_axis = top[0]->shape(concat_axis_); + for (int_tp i = 0; i < bottom.size(); ++i) { + const int_tp bottom_concat_axis = bottom[i]->shape(concat_axis_); if (propagate_down[i]) { Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); - for (int n = 0; n < num_concats_; ++n) { - caffe_copy(bottom_concat_axis * concat_input_size_, top_diff + + for (int_tp n = 0; n < num_concats_; ++n) { + caffe_cpu_copy(bottom_concat_axis * concat_input_size_, top_diff + (n * top_concat_axis + offset_concat_axis) * concat_input_size_, bottom_diff + n * bottom_concat_axis * concat_input_size_); } diff --git a/src/caffe/layers/concat_layer.cu b/src/caffe/layers/concat_layer.cu index a3a0bf6f6ea..a258c795ba4 100644 --- a/src/caffe/layers/concat_layer.cu +++ b/src/caffe/layers/concat_layer.cu @@ -3,19 +3,26 @@ #include "caffe/layers/concat_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -__global__ void Concat(const int nthreads, const Dtype* in_data, - const bool forward, const int num_concats, const int concat_size, - const int top_concat_axis, const int bottom_concat_axis, - const int offset_concat_axis, Dtype* out_data) { +#ifdef USE_CUDA +template +__global__ void Concat(const int_tp nthreads, const Dtype* in_data, + const bool forward, const int_tp num_concats, + const int_tp concat_size, const int_tp top_concat_axis, + const int_tp bottom_concat_axis, + const int_tp offset_concat_axis, Dtype* out_data) { CUDA_KERNEL_LOOP(index, nthreads) { - const int total_concat_size = concat_size * bottom_concat_axis; - const int concat_num = index / total_concat_size; - const int concat_index = index % total_concat_size; - const int top_index = concat_index + - (concat_num * top_concat_axis + offset_concat_axis) * concat_size; + const int_tp total_concat_size = concat_size * bottom_concat_axis; + const int_tp concat_num = index / total_concat_size; + const int_tp concat_index = index % total_concat_size; + const int_tp top_index = concat_index + + (concat_num * top_concat_axis + offset_concat_axis) * concat_size; if (forward) { out_data[top_index] = in_data[index]; } else { @@ -23,46 +30,93 @@ __global__ void Concat(const int nthreads, const Dtype* in_data, } } } +#endif // USE_CUDA -template +template void ConcatLayer::Forward_gpu(const vector*>& bottom, const vector*>& top) { if (bottom.size() == 1) { return; } Dtype* top_data = top[0]->mutable_gpu_data(); - int offset_concat_axis = 0; - const int top_concat_axis = top[0]->shape(concat_axis_); + int_tp offset_concat_axis = 0; + const int_tp top_concat_axis = top[0]->shape(concat_axis_); const bool kForward = true; - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->gpu_data(); - const int bottom_concat_axis = bottom[i]->shape(concat_axis_); - const int bottom_concat_size = bottom_concat_axis * concat_input_size_; - const int nthreads = bottom_concat_size * num_concats_; - Concat // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - nthreads, bottom_data, kForward, num_concats_, concat_input_size_, - top_concat_axis, bottom_concat_axis, offset_concat_axis, top_data); + const int_tp bottom_concat_axis = bottom[i]->shape(concat_axis_); + const int_tp bottom_concat_size = bottom_concat_axis * concat_input_size_; + const int_tp nthreads = bottom_concat_size * num_concats_; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + Concat CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), + CAFFE_CUDA_NUM_THREADS)( + nthreads, bottom_data, kForward, num_concats_, concat_input_size_, + top_concat_axis, bottom_concat_axis, offset_concat_axis, top_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_concat = program.get_kernel( + CL_KERNEL_SELECT("concat")); + viennacl::ocl::enqueue( + oclk_concat(nthreads, WrapHandle((cl_mem) bottom_data, &ctx), + kForward ? 1 : 0, num_concats_, concat_input_size_, + top_concat_axis, bottom_concat_axis, offset_concat_axis, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } offset_concat_axis += bottom_concat_axis; } } -template +template void ConcatLayer::Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (bottom.size() == 1) { return; } const Dtype* top_diff = top[0]->gpu_diff(); - int offset_concat_axis = 0; - const int top_concat_axis = top[0]->shape(concat_axis_); + int_tp offset_concat_axis = 0; + const int_tp top_concat_axis = top[0]->shape(concat_axis_); const bool kForward = false; - for (int i = 0; i < bottom.size(); ++i) { - const int bottom_concat_axis = bottom[i]->shape(concat_axis_); + for (int_tp i = 0; i < bottom.size(); ++i) { + const int_tp bottom_concat_axis = bottom[i]->shape(concat_axis_); if (propagate_down[i]) { Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); - const int bottom_concat_size = bottom_concat_axis * concat_input_size_; - const int nthreads = bottom_concat_size * num_concats_; - Concat // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - nthreads, top_diff, kForward, num_concats_, concat_input_size_, - top_concat_axis, bottom_concat_axis, offset_concat_axis, bottom_diff); + const int_tp bottom_concat_axis = bottom[i]->shape(concat_axis_); + const int_tp bottom_concat_size = bottom_concat_axis * concat_input_size_; + const int_tp nthreads = bottom_concat_size * num_concats_; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + Concat CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), + CAFFE_CUDA_NUM_THREADS)( + nthreads, top_diff, kForward, num_concats_, concat_input_size_, + top_concat_axis, bottom_concat_axis, + offset_concat_axis, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_concat = program.get_kernel( + CL_KERNEL_SELECT("concat")); + viennacl::ocl::enqueue( + oclk_concat(nthreads, WrapHandle((cl_mem) top_diff, &ctx), + kForward ? 1 : 0, num_concats_, concat_input_size_, + top_concat_axis, bottom_concat_axis, offset_concat_axis, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } offset_concat_axis += bottom_concat_axis; } diff --git a/src/caffe/layers/connected_component_layer.cpp b/src/caffe/layers/connected_component_layer.cpp new file mode 100644 index 00000000000..a198c65cff7 --- /dev/null +++ b/src/caffe/layers/connected_component_layer.cpp @@ -0,0 +1,98 @@ +#include +#include + +#include + +#include "caffe/layer.hpp" +#include "caffe/layer_factory.hpp" +#include "caffe/layers/connected_component_layer.hpp" +#include "caffe/util/math_functions.hpp" + + +namespace caffe { + +// Derived from +// http://nghiaho.com/uploads/code/opencv_connected_component/blob.cpp +template +cv::Mat ConnectedComponentLayer::FindBlobs(int maxlabel, + const cv::Mat &input) { + // Fill the label_image with the blobs + cv::Mat label_image; + input.convertTo(label_image, CV_32SC1); + + int label_count = maxlabel + 1; + + // Segment into label numbers higher than the original label numbers + for (int y = 0; y < label_image.rows; y++) { + int *row = reinterpret_cast(label_image.ptr(y)); + for (int x = 0; x < label_image.cols; x++) { + // Skip background and already labeled areas + if (row[x] > maxlabel || row[x] == 0) { + continue; + } + cv::Rect rect; + cv::floodFill(label_image, cv::Point(x, y), label_count, &rect, 0, 0, 4); + label_count++; + } + } + return label_image; +} + +template +void ConnectedComponentLayer::LayerSetUp( + const vector*>& bottom, + const vector*>& top) { +} + +template +void ConnectedComponentLayer::Reshape(const vector*>& bottom, + const vector*>& top) { + top[0]->ReshapeLike(*bottom[0]); +} + +template +void ConnectedComponentLayer::Forward_cpu( + const vector*>& bottom, + const vector*>& top) { + + const Dtype* bottom_data = bottom[0]->cpu_data(); + Dtype* top_data = top[0]->mutable_cpu_data(); + + cv::Mat img(bottom[0]->height(), bottom[0]->width(), CV_8SC1); + + for (int_tp nc = 0; nc < bottom[0]->num() * bottom[0]->channels(); ++nc) { + int maxlabel = 0; + for (int_tp y = 0; y < bottom[0]->height(); ++y) { + for (int_tp x = 0; x < bottom[0]->width(); ++x) { + int val = bottom_data[nc * bottom[0]->width() * bottom[0]->height() + + bottom[0]->width() * y + x]; + if (val > maxlabel) { + maxlabel = val; + } + img.at(y, x) = val; + } + } + cv::Mat seg = FindBlobs(maxlabel, img); +#pragma omp parallel for + for (int_tp y = 0; y < seg.rows; ++y) { + for (int_tp x = 0; x < seg.cols; ++x) { + top_data[nc * bottom[0]->width() * bottom[0]->height() + + bottom[0]->width() * y + x] = seg.at(y, x); + } + } + } +} + +template +void ConnectedComponentLayer::Backward_cpu( + const vector*>& top, + const vector& propagate_down, + const vector*>& bottom) { + // Nothing to do, don't backpropagate to labels + return; +} + +INSTANTIATE_CLASS(ConnectedComponentLayer); +REGISTER_LAYER_CLASS(ConnectedComponent); + +} // namespace caffe diff --git a/src/caffe/layers/contrastive_loss_layer.cpp b/src/caffe/layers/contrastive_loss_layer.cpp index 599e178e9c4..4679fdffcee 100644 --- a/src/caffe/layers/contrastive_loss_layer.cpp +++ b/src/caffe/layers/contrastive_loss_layer.cpp @@ -23,7 +23,7 @@ void ContrastiveLossLayer::LayerSetUp( dist_sq_.Reshape(bottom[0]->num(), 1, 1, 1); // vector of ones used to sum along channels summer_vec_.Reshape(bottom[0]->channels(), 1, 1, 1); - for (int i = 0; i < bottom[0]->channels(); ++i) + for (int_tp i = 0; i < bottom[0]->channels(); ++i) summer_vec_.mutable_cpu_data()[i] = Dtype(1); } @@ -31,21 +31,21 @@ template void ContrastiveLossLayer::Forward_cpu( const vector*>& bottom, const vector*>& top) { - int count = bottom[0]->count(); + int_tp count = bottom[0]->count(); caffe_sub( count, bottom[0]->cpu_data(), // a bottom[1]->cpu_data(), // b diff_.mutable_cpu_data()); // a_i-b_i - const int channels = bottom[0]->channels(); + const int_tp channels = bottom[0]->channels(); Dtype margin = this->layer_param_.contrastive_loss_param().margin(); bool legacy_version = this->layer_param_.contrastive_loss_param().legacy_version(); Dtype loss(0.0); - for (int i = 0; i < bottom[0]->num(); ++i) { + for (int_tp i = 0; i < bottom[0]->num(); ++i) { dist_sq_.mutable_cpu_data()[i] = caffe_cpu_dot(channels, diff_.cpu_data() + (i*channels), diff_.cpu_data() + (i*channels)); - if (static_cast(bottom[2]->cpu_data()[i])) { // similar pairs + if (static_cast(bottom[2]->cpu_data()[i])) { // similar pairs loss += dist_sq_.cpu_data()[i]; } else { // dissimilar pairs if (legacy_version) { @@ -67,16 +67,16 @@ void ContrastiveLossLayer::Backward_cpu(const vector*>& top, Dtype margin = this->layer_param_.contrastive_loss_param().margin(); bool legacy_version = this->layer_param_.contrastive_loss_param().legacy_version(); - for (int i = 0; i < 2; ++i) { + for (int_tp i = 0; i < 2; ++i) { if (propagate_down[i]) { const Dtype sign = (i == 0) ? 1 : -1; const Dtype alpha = sign * top[0]->cpu_diff()[0] / static_cast(bottom[i]->num()); - int num = bottom[i]->num(); - int channels = bottom[i]->channels(); - for (int j = 0; j < num; ++j) { + int_tp num = bottom[i]->num(); + int_tp channels = bottom[i]->channels(); + for (int_tp j = 0; j < num; ++j) { Dtype* bout = bottom[i]->mutable_cpu_diff(); - if (static_cast(bottom[2]->cpu_data()[j])) { // similar pairs + if (static_cast(bottom[2]->cpu_data()[j])) { // similar pairs caffe_cpu_axpby( channels, alpha, diff --git a/src/caffe/layers/contrastive_loss_layer.cu b/src/caffe/layers/contrastive_loss_layer.cu index fd7d67cca94..c1f633a02ae 100644 --- a/src/caffe/layers/contrastive_loss_layer.cu +++ b/src/caffe/layers/contrastive_loss_layer.cu @@ -4,45 +4,65 @@ #include "caffe/layers/contrastive_loss_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void ContrastiveLossLayer::Forward_gpu( const vector*>& bottom, const vector*>& top) { - const int count = bottom[0]->count(); - caffe_gpu_sub( - count, - bottom[0]->gpu_data(), // a - bottom[1]->gpu_data(), // b - diff_.mutable_gpu_data()); // a_i-b_i - caffe_gpu_powx( - count, - diff_.mutable_gpu_data(), // a_i-b_i - Dtype(2), - diff_sq_.mutable_gpu_data()); // (a_i-b_i)^2 - caffe_gpu_gemv( - CblasNoTrans, - bottom[0]->num(), - bottom[0]->channels(), - Dtype(1.0), - diff_sq_.gpu_data(), // (a_i-b_i)^2 - summer_vec_.gpu_data(), - Dtype(0.0), - dist_sq_.mutable_gpu_data()); // \Sum (a_i-b_i)^2 + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_sub(count, bottom[0]->gpu_data(), // a + bottom[1]->gpu_data(), // b + diff_.mutable_gpu_data()); // a_i-b_i + caffe_gpu_powx(count, diff_.mutable_gpu_data(), // a_i-b_i + Dtype(2), diff_sq_.mutable_gpu_data()); // (a_i-b_i)^2 + caffe_gpu_gemv(CblasNoTrans, bottom[0]->num(), bottom[0]->channels(), + Dtype(1.0), + diff_sq_.gpu_data(), // (a_i-b_i)^2 + summer_vec_.gpu_data(), Dtype(0.0), + dist_sq_.mutable_gpu_data()); // \Sum (a_i-b_i)^2 +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_sub(this->device_->id(), count, + (cl_mem) (bottom[0]->gpu_data()), 0, + (cl_mem) (bottom[1]->gpu_data()), 0, + (cl_mem) (diff_.mutable_gpu_data()), 0); + greentea_gpu_powx(this->device_->id(), count, + (cl_mem) (diff_.mutable_gpu_data()), + 0, // a_i-b_i + Dtype(2), (cl_mem) (diff_sq_.mutable_gpu_data()), + 0); // (a_i-b_i)^2 + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, + bottom[0]->num(), bottom[0]->channels(), + Dtype(1.0), (cl_mem) (diff_sq_.gpu_data()), + 0, // (a_i-b_i)^2 + (cl_mem) (summer_vec_.gpu_data()), 0, Dtype(0.0), + (cl_mem) (dist_sq_.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + Dtype margin = this->layer_param_.contrastive_loss_param().margin(); - bool legacy_version = - this->layer_param_.contrastive_loss_param().legacy_version(); + bool legacy_version = this->layer_param_.contrastive_loss_param() + .legacy_version(); Dtype loss(0.0); - for (int i = 0; i < bottom[0]->num(); ++i) { - if (static_cast(bottom[2]->cpu_data()[i])) { // similar pairs + for (int_tp i = 0; i < bottom[0]->num(); ++i) { + if (static_cast(bottom[2]->cpu_data()[i])) { // similar pairs loss += dist_sq_.cpu_data()[i]; } else { // dissimilar pairs if (legacy_version) { loss += std::max(margin - dist_sq_.cpu_data()[i], Dtype(0.0)); } else { - Dtype dist = std::max(margin - sqrt(dist_sq_.cpu_data()[i]), + Dtype dist = std::max(margin - (Dtype) sqrt(dist_sq_.cpu_data()[i]), Dtype(0.0)); - loss += dist*dist; + loss += dist * dist; } } } @@ -50,14 +70,16 @@ void ContrastiveLossLayer::Forward_gpu( top[0]->mutable_cpu_data()[0] = loss; } -template -__global__ void CLLBackward(const int count, const int channels, - const Dtype margin, const bool legacy_version, const Dtype alpha, - const Dtype* y, const Dtype* diff, const Dtype* dist_sq, - Dtype *bottom_diff) { +#ifdef USE_CUDA +template +__global__ void CLLBackward(const int_tp count, const int_tp channels, + const Dtype margin, const bool legacy_version, + const Dtype alpha, const Dtype* y, + const Dtype* diff, const Dtype* dist_sq, + Dtype *bottom_diff) { CUDA_KERNEL_LOOP(i, count) { - int n = i / channels; // the num index, to access y and dist_sq - if (static_cast(y[n])) { // similar pairs + int_tp n = i / channels; // the num index, to access y and dist_sq + if (static_cast(y[n])) { // similar pairs bottom_diff[i] = alpha * diff[i]; } else { // dissimilar pairs Dtype mdist(0.0); @@ -78,28 +100,54 @@ __global__ void CLLBackward(const int count, const int channels, } } } +#endif // USE_CUDA -template -void ContrastiveLossLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - for (int i = 0; i < 2; ++i) { +template +void ContrastiveLossLayer::Backward_gpu( + const vector*>& top, const vector& propagate_down, + const vector*>& bottom) { + for (int_tp i = 0; i < 2; ++i) { if (propagate_down[i]) { - const int count = bottom[0]->count(); - const int channels = bottom[0]->channels(); + const int_tp count = bottom[0]->count(); + const int_tp channels = bottom[0]->channels(); Dtype margin = this->layer_param_.contrastive_loss_param().margin(); - const bool legacy_version = - this->layer_param_.contrastive_loss_param().legacy_version(); + const bool legacy_version = this->layer_param_.contrastive_loss_param() + .legacy_version(); const Dtype sign = (i == 0) ? 1 : -1; - const Dtype alpha = sign * top[0]->cpu_diff()[0] / - static_cast(bottom[0]->num()); - // NOLINT_NEXT_LINE(whitespace/operators) - CLLBackward<<>>( - count, channels, margin, legacy_version, alpha, - bottom[2]->gpu_data(), // pair similarity 0 or 1 - diff_.gpu_data(), // the cached eltwise difference between a and b - dist_sq_.gpu_data(), // the cached square distance between a and b - bottom[i]->mutable_gpu_diff()); - CUDA_POST_KERNEL_CHECK; + const Dtype alpha = sign * top[0]->cpu_diff()[0] + / static_cast(bottom[0]->num()); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + CLLBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, channels, margin, legacy_version, alpha, + bottom[2]->gpu_data(), // pair similarity 0 or 1 + diff_.gpu_data(), // the cached eltwise difference between a and b + dist_sq_.gpu_data(), // the cached square distance between a and b + bottom[i]->mutable_gpu_diff()); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_cll = program.get_kernel( + CL_KERNEL_SELECT("cll_backward")); + viennacl::ocl::enqueue( + oclk_cll( + count, channels, margin, legacy_version ? 1 : 0, alpha, + WrapHandle((cl_mem) (bottom[2]->gpu_data()), &ctx), + WrapHandle((cl_mem) (diff_.gpu_data()), &ctx), + WrapHandle((cl_mem) (dist_sq_.gpu_data()), &ctx), + WrapHandle((cl_mem) (bottom[i]->mutable_gpu_diff()), &ctx)), + ctx.get_queue()); + +#endif // USE_GREENTEA + } } } } diff --git a/src/caffe/layers/conv_layer.cpp b/src/caffe/layers/conv_layer.cpp index 5d522ab31f2..459c1cd22ef 100644 --- a/src/caffe/layers/conv_layer.cpp +++ b/src/caffe/layers/conv_layer.cpp @@ -4,33 +4,34 @@ namespace caffe { -template +template void ConvolutionLayer::compute_output_shape() { - const int* kernel_shape_data = this->kernel_shape_.cpu_data(); - const int* stride_data = this->stride_.cpu_data(); - const int* pad_data = this->pad_.cpu_data(); - const int* dilation_data = this->dilation_.cpu_data(); + const int_tp* kernel_shape_data = this->kernel_shape_.cpu_data(); + const int_tp* stride_data = this->stride_.cpu_data(); + const int_tp* pad_data = this->pad_.cpu_data(); + const int_tp* dilation_data = this->dilation_.cpu_data(); this->output_shape_.clear(); - for (int i = 0; i < this->num_spatial_axes_; ++i) { + for (int_tp i = 0; i < this->num_spatial_axes_; ++i) { // i + 1 to skip channel axis - const int input_dim = this->input_shape(i + 1); - const int kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + 1; - const int output_dim = (input_dim + 2 * pad_data[i] - kernel_extent) + const int_tp input_dim = this->input_shape(i + 1); + const int_tp kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + + 1; + const int_tp output_dim = (input_dim + 2 * pad_data[i] - kernel_extent) / stride_data[i] + 1; this->output_shape_.push_back(output_dim); } } -template +template void ConvolutionLayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* weight = this->blobs_[0]->cpu_data(); - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* top_data = top[i]->mutable_cpu_data(); - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { this->forward_cpu_gemm(bottom_data + n * this->bottom_dim_, weight, - top_data + n * this->top_dim_); + top_data + n * this->top_dim_); if (this->bias_term_) { const Dtype* bias = this->blobs_[1]->cpu_data(); this->forward_cpu_bias(top_data + n * this->top_dim_, bias); @@ -39,33 +40,34 @@ void ConvolutionLayer::Forward_cpu(const vector*>& bottom, } } -template +template void ConvolutionLayer::Backward_cpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* weight = this->blobs_[0]->cpu_data(); Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff(); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->cpu_diff(); const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); // Bias gradient, if necessary. if (this->bias_term_ && this->param_propagate_down_[1]) { Dtype* bias_diff = this->blobs_[1]->mutable_cpu_diff(); - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { this->backward_cpu_bias(bias_diff, top_diff + n * this->top_dim_); } } if (this->param_propagate_down_[0] || propagate_down[i]) { - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { // gradient w.r.t. weight. Note that we will accumulate diffs. if (this->param_propagate_down_[0]) { this->weight_cpu_gemm(bottom_data + n * this->bottom_dim_, - top_diff + n * this->top_dim_, weight_diff); + top_diff + n * this->top_dim_, weight_diff); } // gradient w.r.t. bottom data, if necessary. if (propagate_down[i]) { this->backward_cpu_gemm(top_diff + n * this->top_dim_, weight, - bottom_diff + n * this->bottom_dim_); + bottom_diff + n * this->bottom_dim_); } } } diff --git a/src/caffe/layers/conv_layer.cu b/src/caffe/layers/conv_layer.cu index d06e4b6244e..6aa60b8fb7e 100644 --- a/src/caffe/layers/conv_layer.cu +++ b/src/caffe/layers/conv_layer.cu @@ -2,23 +2,35 @@ #include "caffe/layers/conv_layer.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { template void ConvolutionLayer::Forward_gpu(const vector*>& bottom, const vector*>& top) { const Dtype* weight = this->blobs_[0]->gpu_data(); - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->gpu_data(); Dtype* top_data = top[i]->mutable_gpu_data(); - for (int n = 0; n < this->num_; ++n) { - this->forward_gpu_gemm(bottom_data + n * this->bottom_dim_, weight, - top_data + n * this->top_dim_); + // Multi queue execution, all previous work needs to be done first + this->device_->FinishQueues(); + for (int_tp n = 0; n < this->num_; ++n) { + // Multi queue execution, go through work queues + this->device_->SwitchQueue(n); + this->forward_gpu_gemm(bottom_data, n * this->bottom_dim_, weight, + top_data, n * this->top_dim_); if (this->bias_term_) { const Dtype* bias = this->blobs_[1]->gpu_data(); - this->forward_gpu_bias(top_data + n * this->top_dim_, bias); + this->forward_gpu_bias(top_data, n * this->top_dim_, bias); } } + // Multi queue execution, finish all queues + this->device_->FinishQueues(); } } @@ -27,29 +39,37 @@ void ConvolutionLayer::Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { const Dtype* weight = this->blobs_[0]->gpu_data(); Dtype* weight_diff = this->blobs_[0]->mutable_gpu_diff(); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->gpu_diff(); // Bias gradient, if necessary. if (this->bias_term_ && this->param_propagate_down_[1]) { Dtype* bias_diff = this->blobs_[1]->mutable_gpu_diff(); - for (int n = 0; n < this->num_; ++n) { - this->backward_gpu_bias(bias_diff, top_diff + n * this->top_dim_); + for (int_tp n = 0; n < this->num_; ++n) { + this->backward_gpu_bias(bias_diff, top_diff, n * this->top_dim_); } } if (this->param_propagate_down_[0] || propagate_down[i]) { const Dtype* bottom_data = bottom[i]->gpu_data(); Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { // gradient w.r.t. weight. Note that we will accumulate diffs. if (this->param_propagate_down_[0]) { - this->weight_gpu_gemm(bottom_data + n * this->bottom_dim_, - top_diff + n * this->top_dim_, weight_diff); + this->weight_gpu_gemm(bottom_data, n * this->bottom_dim_, + top_diff, n * this->top_dim_, weight_diff); } - // gradient w.r.t. bottom data, if necessary. - if (propagate_down[i]) { - this->backward_gpu_gemm(top_diff + n * this->top_dim_, weight, - bottom_diff + n * this->bottom_dim_); + } + // gradient w.r.t. bottom data, if necessary. + if (propagate_down[i]) { + // Multi queue execution, all previous work needs to be done first + this->device_->FinishQueues(); + for (int_tp n = 0; n < this->num_; ++n) { + // Multi queue execution, go through work queues + this->device_->SwitchQueue(n); + this->backward_gpu_gemm(top_diff, n * this->top_dim_, weight, + bottom_diff, n * this->bottom_dim_); } + // Multi queue execution, finish all queues + this->device_->FinishQueues(); } } } diff --git a/src/caffe/layers/cudnn_conv_layer.cpp b/src/caffe/layers/cudnn_conv_layer.cpp index 1987fb096b0..20e6612d9b7 100644 --- a/src/caffe/layers/cudnn_conv_layer.cpp +++ b/src/caffe/layers/cudnn_conv_layer.cpp @@ -18,6 +18,9 @@ template void CuDNNConvolutionLayer::LayerSetUp( const vector*>& bottom, const vector*>& top) { ConvolutionLayer::LayerSetUp(bottom, top); + + this->use_colbuffer_ = false; + // Initialize CUDA streams and cuDNN. stream_ = new cudaStream_t[this->group_ * CUDNN_STREAMS_PER_GROUP]; handle_ = new cudnnHandle_t[this->group_ * CUDNN_STREAMS_PER_GROUP]; @@ -37,7 +40,7 @@ void CuDNNConvolutionLayer::LayerSetUp( workspaceData = NULL; workspace = new void*[this->group_ * CUDNN_STREAMS_PER_GROUP]; - for (size_t i = 0; i < bottom.size(); ++i) { + for (uint_tp i = 0; i < bottom.size(); ++i) { // initialize all to default algorithms fwd_algo_[i] = (cudnnConvolutionFwdAlgo_t)0; bwd_filter_algo_[i] = (cudnnConvolutionBwdFilterAlgo_t)0; @@ -48,7 +51,7 @@ void CuDNNConvolutionLayer::LayerSetUp( workspace_bwd_filter_sizes_[i] = 0; } - for (int g = 0; g < this->group_ * CUDNN_STREAMS_PER_GROUP; g++) { + for (int_tp g = 0; g < this->group_ * CUDNN_STREAMS_PER_GROUP; g++) { CUDA_CHECK(cudaStreamCreate(&stream_[g])); CUDNN_CHECK(cudnnCreate(&handle_[g])); CUDNN_CHECK(cudnnSetStream(handle_[g], stream_[g])); @@ -59,20 +62,18 @@ void CuDNNConvolutionLayer::LayerSetUp( bias_offset_ = (this->num_output_ / this->group_); // Create filter descriptor. - const int* kernel_shape_data = this->kernel_shape_.cpu_data(); - const int kernel_h = kernel_shape_data[0]; - const int kernel_w = kernel_shape_data[1]; - cudnn::createFilterDesc(&filter_desc_, + const int_tp* kernel_shape_data = this->kernel_shape_.cpu_data(); + cudnn::createFilterDesc(&filter_desc_, this->num_spatial_axes_, this->num_output_ / this->group_, this->channels_ / this->group_, - kernel_h, kernel_w); + kernel_shape_data); // Create tensor descriptor(s) for data and corresponding convolution(s). - for (int i = 0; i < bottom.size(); i++) { + for (int_tp i = 0; i < bottom.size(); i++) { cudnnTensorDescriptor_t bottom_desc; - cudnn::createTensor4dDesc(&bottom_desc); + cudnn::createTensorNdDesc(&bottom_desc); bottom_descs_.push_back(bottom_desc); cudnnTensorDescriptor_t top_desc; - cudnn::createTensor4dDesc(&top_desc); + cudnn::createTensorNdDesc(&top_desc); top_descs_.push_back(top_desc); cudnnConvolutionDescriptor_t conv_desc; cudnn::createConvolutionDesc(&conv_desc); @@ -81,7 +82,7 @@ void CuDNNConvolutionLayer::LayerSetUp( // Tensor descriptor for bias. if (this->bias_term_) { - cudnn::createTensor4dDesc(&bias_desc_); + cudnn::createTensorNdDesc(&bias_desc_); } handles_setup_ = true; @@ -90,42 +91,70 @@ void CuDNNConvolutionLayer::LayerSetUp( template void CuDNNConvolutionLayer::Reshape( const vector*>& bottom, const vector*>& top) { + + this->use_colbuffer_ = false; + ConvolutionLayer::Reshape(bottom, top); - CHECK_EQ(2, this->num_spatial_axes_) - << "CuDNNConvolution input must have 2 spatial axes " - << "(e.g., height and width). " - << "Use 'engine: CAFFE' for general ND convolution."; + bottom_offset_ = this->bottom_dim_ / this->group_; top_offset_ = this->top_dim_ / this->group_; - const int height = bottom[0]->shape(this->channel_axis_ + 1); - const int width = bottom[0]->shape(this->channel_axis_ + 2); - const int height_out = top[0]->shape(this->channel_axis_ + 1); - const int width_out = top[0]->shape(this->channel_axis_ + 2); - const int* pad_data = this->pad_.cpu_data(); - const int pad_h = pad_data[0]; - const int pad_w = pad_data[1]; - const int* stride_data = this->stride_.cpu_data(); - const int stride_h = stride_data[0]; - const int stride_w = stride_data[1]; + const int_tp* pad_data = this->pad_.cpu_data(); + const int_tp* stride_data = this->stride_.cpu_data(); // Specify workspace limit for kernels directly until we have a // planning strategy and a rewrite of Caffe's GPU memory mangagement - size_t workspace_limit_bytes = 8*1024*1024; - - for (int i = 0; i < bottom.size(); i++) { - cudnn::setTensor4dDesc(&bottom_descs_[i], - this->num_, - this->channels_ / this->group_, height, width, - this->channels_ * height * width, - height * width, width, 1); - cudnn::setTensor4dDesc(&top_descs_[i], - this->num_, - this->num_output_ / this->group_, height_out, width_out, - this->num_output_ * this->out_spatial_dim_, - this->out_spatial_dim_, width_out, 1); + uint_tp workspace_limit_bytes = 8*1024*1024; + + for (int_tp i = 0; i < bottom.size(); i++) { + { + int_tp total_dims = bottom[i]->shape().size(); + std::vector full_shape(total_dims); + std::vector full_stride(total_dims); + + for (int_tp j = total_dims - 1; j >= 2; --j) { + full_shape[j] = bottom[i]->shape()[j]; + if (j == total_dims - 1) { + full_stride[j] = 1; + } else { + full_stride[j] = full_stride[j + 1] * full_shape[j + 1]; + } + } + + full_shape[1] = this->channels_ / this->group_; + full_stride[1] = full_shape[2] * full_stride[2]; + full_shape[0] = this->num_; + full_stride[0] = this->channels_ * full_stride[1]; + + cudnn::setTensorNdDesc(&bottom_descs_[i], total_dims, + &full_shape[0], &full_stride[0]); + } + + + { + int_tp total_dims = top[i]->shape().size(); + std::vector full_shape(total_dims); + std::vector full_stride(total_dims); + + for (int_tp j = total_dims - 1; j >= 2; --j) { + full_shape[j] = top[i]->shape()[j]; + if (j == total_dims - 1) { + full_stride[j] = 1; + } else { + full_stride[j] = full_stride[j + 1] * full_shape[j + 1]; + } + } + + full_shape[1] = this->num_output_ / this->group_; + full_stride[1] = full_shape[2] * full_stride[2]; + full_shape[0] = this->num_; + full_stride[0] = this->num_output_ * full_stride[1]; + + cudnn::setTensorNdDesc(&top_descs_[i], total_dims, &full_shape[0], + &full_stride[0]); + } + cudnn::setConvolutionDesc(&conv_descs_[i], bottom_descs_[i], - filter_desc_, pad_h, pad_w, - stride_h, stride_w); + filter_desc_, this->num_spatial_axes_, pad_data, stride_data); // choose forward and backward algorithms + workspace(s) CUDNN_CHECK(cudnnGetConvolutionForwardAlgorithm(handle_[0], @@ -173,7 +202,7 @@ void CuDNNConvolutionLayer::Reshape( size_t total_workspace_bwd_data = 0; size_t total_workspace_bwd_filter = 0; - for (size_t i = 0; i < bottom.size(); i++) { + for (uint_tp i = 0; i < bottom.size(); i++) { total_workspace_fwd = std::max(total_workspace_fwd, workspace_fwd_sizes_[i]); total_workspace_bwd_data = std::max(total_workspace_bwd_data, @@ -200,7 +229,7 @@ void CuDNNConvolutionLayer::Reshape( cudaError_t err = cudaMalloc(&(this->workspaceData), workspaceSizeInBytes); if (err != cudaSuccess) { // force zero memory path - for (int i = 0; i < bottom.size(); i++) { + for (int_tp i = 0; i < bottom.size(); i++) { workspace_fwd_sizes_[i] = 0; workspace_bwd_filter_sizes_[i] = 0; workspace_bwd_data_sizes_[i] = 0; @@ -210,7 +239,7 @@ void CuDNNConvolutionLayer::Reshape( } // NULL out all workspace pointers - for (int g = 0; g < (this->group_ * CUDNN_STREAMS_PER_GROUP); g++) { + for (int_tp g = 0; g < (this->group_ * CUDNN_STREAMS_PER_GROUP); g++) { workspace[g] = NULL; } // NULL out underlying data @@ -219,15 +248,19 @@ void CuDNNConvolutionLayer::Reshape( } // if we succeed in the allocation, set pointer aliases for workspaces - for (int g = 0; g < (this->group_ * CUDNN_STREAMS_PER_GROUP); g++) { + for (int_tp g = 0; g < (this->group_ * CUDNN_STREAMS_PER_GROUP); g++) { workspace[g] = reinterpret_cast(workspaceData) + g*max_workspace; } } + std::vector ones(this->num_spatial_axes_, 1); + const int_tp* ones_ptr = &ones[0]; + // Tensor descriptor for bias. if (this->bias_term_) { - cudnn::setTensor4dDesc(&bias_desc_, - 1, this->num_output_ / this->group_, 1, 1); + cudnn::setTensorNdDesc(&bias_desc_, + this->num_spatial_axes_, + 1, this->num_output_ / this->group_, ones_ptr); } } @@ -236,7 +269,7 @@ CuDNNConvolutionLayer::~CuDNNConvolutionLayer() { // Check that handles have been setup before destroying. if (!handles_setup_) { return; } - for (int i = 0; i < bottom_descs_.size(); i++) { + for (int_tp i = 0; i < bottom_descs_.size(); i++) { cudnnDestroyTensorDescriptor(bottom_descs_[i]); cudnnDestroyTensorDescriptor(top_descs_[i]); cudnnDestroyConvolutionDescriptor(conv_descs_[i]); @@ -246,7 +279,7 @@ CuDNNConvolutionLayer::~CuDNNConvolutionLayer() { } cudnnDestroyFilterDescriptor(filter_desc_); - for (int g = 0; g < this->group_ * CUDNN_STREAMS_PER_GROUP; g++) { + for (int_tp g = 0; g < this->group_ * CUDNN_STREAMS_PER_GROUP; g++) { cudaStreamDestroy(stream_[g]); cudnnDestroy(handle_[g]); } diff --git a/src/caffe/layers/cudnn_conv_layer.cu b/src/caffe/layers/cudnn_conv_layer.cu index 42c4fd0260c..2e6e5ad3ad7 100644 --- a/src/caffe/layers/cudnn_conv_layer.cu +++ b/src/caffe/layers/cudnn_conv_layer.cu @@ -11,12 +11,12 @@ template void CuDNNConvolutionLayer::Forward_gpu( const vector*>& bottom, const vector*>& top) { const Dtype* weight = this->blobs_[0]->gpu_data(); - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->gpu_data(); Dtype* top_data = top[i]->mutable_gpu_data(); // Forward through cuDNN in parallel over groups. - for (int g = 0; g < this->group_; g++) { + for (int_tp g = 0; g < this->group_; g++) { // Filters. CUDNN_CHECK(cudnnConvolutionForward(handle_[g], cudnn::dataType::one, @@ -49,7 +49,7 @@ void CuDNNConvolutionLayer::Forward_gpu( // Synchronize the work across groups, each of which went into its own // stream, by launching an empty kernel into the default (null) stream. // NOLINT_NEXT_LINE(whitespace/operators) - sync_conv_groups<<<1, 1>>>(); + sync_conv_groups CUDA_KERNEL(1, 1)(); } } @@ -66,10 +66,10 @@ void CuDNNConvolutionLayer::Backward_gpu(const vector*>& top, if (this->bias_term_ && this->param_propagate_down_[1]) { bias_diff = this->blobs_[1]->mutable_gpu_diff(); } - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->gpu_diff(); // Backward through cuDNN in parallel over groups and gradients. - for (int g = 0; g < this->group_; g++) { + for (int_tp g = 0; g < this->group_; g++) { // Gradient w.r.t. bias. if (this->bias_term_ && this->param_propagate_down_[1]) { CUDNN_CHECK(cudnnConvolutionBackwardBias(handle_[0*this->group_ + g], @@ -82,7 +82,7 @@ void CuDNNConvolutionLayer::Backward_gpu(const vector*>& top, // Gradient w.r.t. weights. if (this->param_propagate_down_[0]) { const Dtype* bottom_data = bottom[i]->gpu_data(); - CUDNN_CHECK(cudnnConvolutionBackwardFilter_v3( + CUDNN_CHECK(cudnnConvolutionBackwardFilter( handle_[1*this->group_ + g], cudnn::dataType::one, bottom_descs_[i], bottom_data + bottom_offset_ * g, @@ -100,7 +100,7 @@ void CuDNNConvolutionLayer::Backward_gpu(const vector*>& top, weight = this->blobs_[0]->gpu_data(); } Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); - CUDNN_CHECK(cudnnConvolutionBackwardData_v3( + CUDNN_CHECK(cudnnConvolutionBackwardData( handle_[2*this->group_ + g], cudnn::dataType::one, filter_desc_, weight + this->weight_offset_ * g, @@ -116,7 +116,7 @@ void CuDNNConvolutionLayer::Backward_gpu(const vector*>& top, // Synchronize the work across groups, each of which went into its own // stream, by launching an empty kernel into the default (null) stream. // NOLINT_NEXT_LINE(whitespace/operators) - sync_conv_groups<<<1, 1>>>(); + sync_conv_groups CUDA_KERNEL(1, 1)(); } } diff --git a/src/caffe/layers/cudnn_lcn_layer.cpp b/src/caffe/layers/cudnn_lcn_layer.cpp index 9c09bf26b4d..8eb99abfbe9 100644 --- a/src/caffe/layers/cudnn_lcn_layer.cpp +++ b/src/caffe/layers/cudnn_lcn_layer.cpp @@ -12,8 +12,8 @@ void CuDNNLCNLayer::LayerSetUp(const vector*>& bottom, CUDNN_CHECK(cudnnCreate(&handle_)); CUDNN_CHECK(cudnnCreateLRNDescriptor(&norm_desc_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); // create a LRN handle handles_setup_ = true; @@ -29,14 +29,22 @@ template void CuDNNLCNLayer::Reshape(const vector*>& bottom, const vector*>& top) { LRNLayer::Reshape(bottom, top); - cudnn::setTensor4dDesc(&bottom_desc_, bottom[0]->num(), - this->channels_, this->height_, this->width_); - cudnn::setTensor4dDesc(&top_desc_, bottom[0]->num(), - this->channels_, this->height_, this->width_); + std::vector shape; + + shape.push_back(bottom[0]->num()); + shape.push_back(this->channels_); + shape.push_back(this->height_); + shape.push_back(this->width_); + + + const int_tp* shape_ptr = &shape[0]; + + cudnn::setTensorNdDesc(&bottom_desc_, 4, shape_ptr); + cudnn::setTensorNdDesc(&top_desc_, 4, shape_ptr); CUDNN_CHECK(cudnnSetLRNDescriptor(norm_desc_, size_, alpha_, beta_, k_)); // allocate / reallocate tempData buffers - size_t totalSizeInBytes = sizeof(Dtype)*bottom[0]->num()* \ + uint_tp totalSizeInBytes = sizeof(Dtype)*bottom[0]->num()* \ this->channels_*this->height_*this->width_; if (totalSizeInBytes > tempDataSize) { diff --git a/src/caffe/layers/cudnn_lrn_layer.cpp b/src/caffe/layers/cudnn_lrn_layer.cpp index 0495b802baf..ba31f970f7f 100644 --- a/src/caffe/layers/cudnn_lrn_layer.cpp +++ b/src/caffe/layers/cudnn_lrn_layer.cpp @@ -12,8 +12,8 @@ void CuDNNLRNLayer::LayerSetUp(const vector*>& bottom, CUDNN_CHECK(cudnnCreate(&handle_)); CUDNN_CHECK(cudnnCreateLRNDescriptor(&norm_desc_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); // create a LRN handle handles_setup_ = true; @@ -28,10 +28,19 @@ template void CuDNNLRNLayer::Reshape(const vector*>& bottom, const vector*>& top) { LRNLayer::Reshape(bottom, top); - cudnn::setTensor4dDesc(&bottom_desc_, bottom[0]->num(), - this->channels_, this->height_, this->width_); - cudnn::setTensor4dDesc(&top_desc_, bottom[0]->num(), - this->channels_, this->height_, this->width_); + + std::vector shape; + + shape.push_back(bottom[0]->num()); + shape.push_back(this->channels_); + shape.push_back(this->height_); + shape.push_back(this->width_); + + + const int_tp* shape_ptr = &shape[0]; + + cudnn::setTensorNdDesc(&bottom_desc_, 4, shape_ptr); + cudnn::setTensorNdDesc(&top_desc_, 4, shape_ptr); CUDNN_CHECK(cudnnSetLRNDescriptor(norm_desc_, size_, alpha_, beta_, k_)); } diff --git a/src/caffe/layers/cudnn_pooling_layer.cpp b/src/caffe/layers/cudnn_pooling_layer.cpp index 24f14780b4f..879690bd4f5 100644 --- a/src/caffe/layers/cudnn_pooling_layer.cpp +++ b/src/caffe/layers/cudnn_pooling_layer.cpp @@ -8,14 +8,19 @@ namespace caffe { template void CuDNNPoolingLayer::LayerSetUp(const vector*>& bottom, const vector*>& top) { - PoolingLayer::LayerSetUp(bottom, top); CUDNN_CHECK(cudnnCreate(&handle_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); + PoolingLayer::LayerSetUp(bottom, top); + + const int_tp* kernel_data = this->kernel_shape_.cpu_data(); + const int_tp* pad_data = this->pad_.cpu_data(); + const int_tp* stride_data = this->stride_.cpu_data(); + cudnn::createPoolingDesc(&pooling_desc_, this->layer_param_.pooling_param().pool(), &mode_, - this->kernel_h_, this->kernel_w_, this->pad_h_, this->pad_w_, - this->stride_h_, this->stride_w_); + this->num_spatial_axes_, + kernel_data, pad_data, stride_data); handles_setup_ = true; } @@ -23,10 +28,18 @@ template void CuDNNPoolingLayer::Reshape(const vector*>& bottom, const vector*>& top) { PoolingLayer::Reshape(bottom, top); - cudnn::setTensor4dDesc(&bottom_desc_, bottom[0]->num(), - this->channels_, this->height_, this->width_); - cudnn::setTensor4dDesc(&top_desc_, bottom[0]->num(), - this->channels_, this->pooled_height_, this->pooled_width_); + + cudnn::setTensorNdDesc(&bottom_desc_, + bottom[0]->shape().size() - 2, + bottom[0]->shape()[0], + this->channels_, + &(bottom[0]->shape()[2])); + const int_tp* pooled_size_data = this->pooled_size_.cpu_data(); + cudnn::setTensorNdDesc(&top_desc_, + bottom[0]->shape().size() - 2, + bottom[0]->shape()[0], + this->channels_, + pooled_size_data); } template diff --git a/src/caffe/layers/cudnn_relu_layer.cpp b/src/caffe/layers/cudnn_relu_layer.cpp index c86c6907113..2ae3418440c 100644 --- a/src/caffe/layers/cudnn_relu_layer.cpp +++ b/src/caffe/layers/cudnn_relu_layer.cpp @@ -11,8 +11,8 @@ void CuDNNReLULayer::LayerSetUp(const vector*>& bottom, ReLULayer::LayerSetUp(bottom, top); // initialize cuDNN CUDNN_CHECK(cudnnCreate(&handle_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); handles_setup_ = true; } @@ -20,12 +20,10 @@ template void CuDNNReLULayer::Reshape(const vector*>& bottom, const vector*>& top) { ReLULayer::Reshape(bottom, top); - const int N = bottom[0]->num(); - const int K = bottom[0]->channels(); - const int H = bottom[0]->height(); - const int W = bottom[0]->width(); - cudnn::setTensor4dDesc(&bottom_desc_, N, K, H, W); - cudnn::setTensor4dDesc(&top_desc_, N, K, H, W); + cudnn::setTensorNdDesc(&bottom_desc_, bottom[0]->shape().size(), + &(bottom[0]->shape()[0])); + cudnn::setTensorNdDesc(&top_desc_, top[0]->shape().size(), + &(top[0]->shape()[0])); } template diff --git a/src/caffe/layers/cudnn_sigmoid_layer.cpp b/src/caffe/layers/cudnn_sigmoid_layer.cpp index ccb955cdaff..7422dff354d 100644 --- a/src/caffe/layers/cudnn_sigmoid_layer.cpp +++ b/src/caffe/layers/cudnn_sigmoid_layer.cpp @@ -11,8 +11,8 @@ void CuDNNSigmoidLayer::LayerSetUp(const vector*>& bottom, SigmoidLayer::LayerSetUp(bottom, top); // initialize cuDNN CUDNN_CHECK(cudnnCreate(&handle_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); handles_setup_ = true; } @@ -20,12 +20,10 @@ template void CuDNNSigmoidLayer::Reshape(const vector*>& bottom, const vector*>& top) { SigmoidLayer::Reshape(bottom, top); - const int N = bottom[0]->num(); - const int K = bottom[0]->channels(); - const int H = bottom[0]->height(); - const int W = bottom[0]->width(); - cudnn::setTensor4dDesc(&bottom_desc_, N, K, H, W); - cudnn::setTensor4dDesc(&top_desc_, N, K, H, W); + cudnn::setTensorNdDesc(&bottom_desc_, bottom[0]->shape().size(), + &(bottom[0]->shape()[0])); + cudnn::setTensorNdDesc(&top_desc_, top[0]->shape().size(), + &(top[0]->shape()[0])); } template diff --git a/src/caffe/layers/cudnn_softmax_layer.cpp b/src/caffe/layers/cudnn_softmax_layer.cpp index 6440df9805b..b4be07ebfb1 100644 --- a/src/caffe/layers/cudnn_softmax_layer.cpp +++ b/src/caffe/layers/cudnn_softmax_layer.cpp @@ -13,8 +13,8 @@ void CuDNNSoftmaxLayer::LayerSetUp(const vector*>& bottom, SoftmaxLayer::LayerSetUp(bottom, top); // Initialize CUDNN. CUDNN_CHECK(cudnnCreate(&handle_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); handles_setup_ = true; } @@ -22,12 +22,19 @@ template void CuDNNSoftmaxLayer::Reshape(const vector*>& bottom, const vector*>& top) { SoftmaxLayer::Reshape(bottom, top); - int N = this->outer_num_; - int K = bottom[0]->shape(this->softmax_axis_); - int H = this->inner_num_; - int W = 1; - cudnn::setTensor4dDesc(&bottom_desc_, N, K, H, W); - cudnn::setTensor4dDesc(&top_desc_, N, K, H, W); + + std::vector shape; + + shape.push_back(this->outer_num_); + shape.push_back(bottom[0]->shape(this->softmax_axis_)); + shape.push_back(this->inner_num_); + shape.push_back(1); + + + const int_tp* shape_ptr = &shape[0]; + + cudnn::setTensorNdDesc(&bottom_desc_, 4, shape_ptr); + cudnn::setTensorNdDesc(&top_desc_, 4, shape_ptr); } template diff --git a/src/caffe/layers/cudnn_tanh_layer.cpp b/src/caffe/layers/cudnn_tanh_layer.cpp index 1a56418227c..ef0355d87f1 100644 --- a/src/caffe/layers/cudnn_tanh_layer.cpp +++ b/src/caffe/layers/cudnn_tanh_layer.cpp @@ -11,8 +11,8 @@ void CuDNNTanHLayer::LayerSetUp(const vector*>& bottom, TanHLayer::LayerSetUp(bottom, top); // initialize cuDNN CUDNN_CHECK(cudnnCreate(&handle_)); - cudnn::createTensor4dDesc(&bottom_desc_); - cudnn::createTensor4dDesc(&top_desc_); + cudnn::createTensorNdDesc(&bottom_desc_); + cudnn::createTensorNdDesc(&top_desc_); handles_setup_ = true; } @@ -20,12 +20,10 @@ template void CuDNNTanHLayer::Reshape(const vector*>& bottom, const vector*>& top) { TanHLayer::Reshape(bottom, top); - const int N = bottom[0]->num(); - const int K = bottom[0]->channels(); - const int H = bottom[0]->height(); - const int W = bottom[0]->width(); - cudnn::setTensor4dDesc(&bottom_desc_, N, K, H, W); - cudnn::setTensor4dDesc(&top_desc_, N, K, H, W); + const int_tp* shape = &(bottom[0]->shape()[0]); + cudnn::setTensorNdDesc(&bottom_desc_, bottom[0]->shape().size(), + shape); + cudnn::setTensorNdDesc(&top_desc_, bottom[0]->shape().size(), shape); } template diff --git a/src/caffe/layers/data_layer.cpp b/src/caffe/layers/data_layer.cpp index 66e6301fd45..93506acfa01 100644 --- a/src/caffe/layers/data_layer.cpp +++ b/src/caffe/layers/data_layer.cpp @@ -11,41 +11,41 @@ namespace caffe { -template + +template DataLayer::DataLayer(const LayerParameter& param) - : BasePrefetchingDataLayer(param), - reader_(param) { + : BasePrefetchingDataLayer(param), reader_(param) { } -template +template DataLayer::~DataLayer() { this->StopInternalThread(); } -template +template void DataLayer::DataLayerSetUp(const vector*>& bottom, - const vector*>& top) { - const int batch_size = this->layer_param_.data_param().batch_size(); + const vector*>& top) { + const int_tp batch_size = this->layer_param_.data_param().batch_size(); // Read a data point, and use it to initialize the top blob. Datum& datum = *(reader_.full().peek()); // Use data_transformer to infer the expected blob shape from datum. - vector top_shape = this->data_transformer_->InferBlobShape(datum); + vector top_shape = this->data_transformer_->InferBlobShape(datum); this->transformed_data_.Reshape(top_shape); // Reshape top[0] and prefetch_data according to the batch_size. top_shape[0] = batch_size; top[0]->Reshape(top_shape); - for (int i = 0; i < this->PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < this->PREFETCH_COUNT; ++i) { this->prefetch_[i].data_.Reshape(top_shape); } - LOG(INFO) << "output data size: " << top[0]->num() << "," - << top[0]->channels() << "," << top[0]->height() << "," - << top[0]->width(); + LOG(INFO)<< "output data size: " << top[0]->num() << "," + << top[0]->channels() << "," << top[0]->height() << "," + << top[0]->width(); // label if (this->output_labels_) { - vector label_shape(1, batch_size); + vector label_shape(1, batch_size); top[1]->Reshape(label_shape); - for (int i = 0; i < this->PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < this->PREFETCH_COUNT; ++i) { this->prefetch_[i].label_.Reshape(label_shape); } } @@ -64,10 +64,10 @@ void DataLayer::load_batch(Batch* batch) { // Reshape according to the first datum of each batch // on single input batches allows for inputs of varying dimension. - const int batch_size = this->layer_param_.data_param().batch_size(); + const int_tp batch_size = this->layer_param_.data_param().batch_size(); Datum& datum = *(reader_.full().peek()); // Use data_transformer to infer the expected blob shape from datum. - vector top_shape = this->data_transformer_->InferBlobShape(datum); + vector top_shape = this->data_transformer_->InferBlobShape(datum); this->transformed_data_.Reshape(top_shape); // Reshape batch according to the batch_size. top_shape[0] = batch_size; @@ -79,14 +79,14 @@ void DataLayer::load_batch(Batch* batch) { if (this->output_labels_) { top_label = batch->label_.mutable_cpu_data(); } - for (int item_id = 0; item_id < batch_size; ++item_id) { + for (int_tp item_id = 0; item_id < batch_size; ++item_id) { timer.Start(); // get a datum Datum& datum = *(reader_.full().pop("Waiting for data")); read_time += timer.MicroSeconds(); timer.Start(); // Apply data transformations (mirror, scale, crop...) - int offset = batch->data_.offset(item_id); + int_tp offset = batch->data_.offset(item_id); this->transformed_data_.set_cpu_data(top_data + offset); this->data_transformer_->Transform(datum, &(this->transformed_data_)); // Copy label. @@ -94,14 +94,13 @@ void DataLayer::load_batch(Batch* batch) { top_label[item_id] = datum.label(); } trans_time += timer.MicroSeconds(); - reader_.free().push(const_cast(&datum)); } timer.Stop(); batch_timer.Stop(); - DLOG(INFO) << "Prefetch batch: " << batch_timer.MilliSeconds() << " ms."; - DLOG(INFO) << " Read time: " << read_time / 1000 << " ms."; - DLOG(INFO) << "Transform time: " << trans_time / 1000 << " ms."; + DLOG(INFO)<< "Prefetch batch: " << batch_timer.MilliSeconds() << " ms."; + DLOG(INFO)<< " Read time: " << read_time / 1000 << " ms."; + DLOG(INFO)<< "Transform time: " << trans_time / 1000 << " ms."; } INSTANTIATE_CLASS(DataLayer); diff --git a/src/caffe/layers/deconv_layer.cpp b/src/caffe/layers/deconv_layer.cpp index 20a460fbdea..9752e2a7fc2 100644 --- a/src/caffe/layers/deconv_layer.cpp +++ b/src/caffe/layers/deconv_layer.cpp @@ -4,18 +4,19 @@ namespace caffe { -template +template void DeconvolutionLayer::compute_output_shape() { - const int* kernel_shape_data = this->kernel_shape_.cpu_data(); - const int* stride_data = this->stride_.cpu_data(); - const int* pad_data = this->pad_.cpu_data(); - const int* dilation_data = this->dilation_.cpu_data(); + const int_tp* kernel_shape_data = this->kernel_shape_.cpu_data(); + const int_tp* stride_data = this->stride_.cpu_data(); + const int_tp* pad_data = this->pad_.cpu_data(); + const int_tp* dilation_data = this->dilation_.cpu_data(); this->output_shape_.clear(); - for (int i = 0; i < this->num_spatial_axes_; ++i) { + for (int_tp i = 0; i < this->num_spatial_axes_; ++i) { // i + 1 to skip channel axis - const int input_dim = this->input_shape(i + 1); - const int kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + 1; - const int output_dim = stride_data[i] * (input_dim - 1) + const int_tp input_dim = this->input_shape(i + 1); + const int_tp kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + + 1; + const int_tp output_dim = stride_data[i] * (input_dim - 1) + kernel_extent - 2 * pad_data[i]; this->output_shape_.push_back(output_dim); } @@ -25,10 +26,10 @@ template void DeconvolutionLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* weight = this->blobs_[0]->cpu_data(); - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* top_data = top[i]->mutable_cpu_data(); - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { this->backward_cpu_gemm(bottom_data + n * this->bottom_dim_, weight, top_data + n * this->top_dim_); if (this->bias_term_) { @@ -44,19 +45,19 @@ void DeconvolutionLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { const Dtype* weight = this->blobs_[0]->cpu_data(); Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff(); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->cpu_diff(); const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); // Bias gradient, if necessary. if (this->bias_term_ && this->param_propagate_down_[1]) { Dtype* bias_diff = this->blobs_[1]->mutable_cpu_diff(); - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { this->backward_cpu_bias(bias_diff, top_diff + n * this->top_dim_); } } if (this->param_propagate_down_[0] || propagate_down[i]) { - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { // Gradient w.r.t. weight. Note that we will accumulate diffs. if (this->param_propagate_down_[0]) { this->weight_cpu_gemm(top_diff + n * this->top_dim_, diff --git a/src/caffe/layers/deconv_layer.cu b/src/caffe/layers/deconv_layer.cu index 226763223fa..725d2f5b107 100644 --- a/src/caffe/layers/deconv_layer.cu +++ b/src/caffe/layers/deconv_layer.cu @@ -2,54 +2,61 @@ #include "caffe/layers/deconv_layer.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void DeconvolutionLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* weight = this->blobs_[0]->gpu_data(); - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->gpu_data(); Dtype* top_data = top[i]->mutable_gpu_data(); - for (int n = 0; n < this->num_; ++n) { - this->backward_gpu_gemm(bottom_data + n * this->bottom_dim_, weight, - top_data + n * this->top_dim_); + for (int_tp n = 0; n < this->num_; ++n) { + this->backward_gpu_gemm(bottom_data, n * this->bottom_dim_, weight, + top_data, n * this->top_dim_); if (this->bias_term_) { const Dtype* bias = this->blobs_[1]->gpu_data(); - this->forward_gpu_bias(top_data + n * this->top_dim_, bias); + this->forward_gpu_bias(top_data, n * this->top_dim_, bias); } } } } -template -void DeconvolutionLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { +template +void DeconvolutionLayer::Backward_gpu( + const vector*>& top, const vector& propagate_down, + const vector*>& bottom) { const Dtype* weight = this->blobs_[0]->gpu_data(); Dtype* weight_diff = this->blobs_[0]->mutable_gpu_diff(); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->gpu_diff(); const Dtype* bottom_data = bottom[i]->gpu_data(); Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); // Bias gradient, if necessary. if (this->bias_term_ && this->param_propagate_down_[1]) { Dtype* bias_diff = this->blobs_[1]->mutable_gpu_diff(); - for (int n = 0; n < this->num_; ++n) { - this->backward_gpu_bias(bias_diff, top_diff + n * this->top_dim_); + for (int_tp n = 0; n < this->num_; ++n) { + this->backward_gpu_bias(bias_diff, top_diff, n * this->top_dim_); } } if (this->param_propagate_down_[0] || propagate_down[i]) { - for (int n = 0; n < this->num_; ++n) { + for (int_tp n = 0; n < this->num_; ++n) { // gradient w.r.t. weight. Note that we will accumulate diffs. if (this->param_propagate_down_[0]) { - this->weight_gpu_gemm(top_diff + n * this->top_dim_, - bottom_data + n * this->bottom_dim_, weight_diff); + this->weight_gpu_gemm(top_diff, n * this->top_dim_, bottom_data, + n * this->bottom_dim_, weight_diff); } // gradient w.r.t. bottom data, if necessary. if (propagate_down[i]) { - this->forward_gpu_gemm(top_diff + n * this->top_dim_, weight, - bottom_diff + n * this->bottom_dim_, - this->param_propagate_down_[0]); + this->forward_gpu_gemm(top_diff, n * this->top_dim_, weight, + bottom_diff, n * this->bottom_dim_, + this->param_propagate_down_[0]); } } } diff --git a/src/caffe/layers/dropout_layer.cpp b/src/caffe/layers/dropout_layer.cpp index 9cb64d9735f..c6d3fcd0c9e 100644 --- a/src/caffe/layers/dropout_layer.cpp +++ b/src/caffe/layers/dropout_layer.cpp @@ -1,5 +1,6 @@ // TODO (sergeyk): effect should not be dependent on phase. wasted memcpy. +#include #include #include "caffe/layers/dropout_layer.hpp" @@ -15,7 +16,10 @@ void DropoutLayer::LayerSetUp(const vector*>& bottom, DCHECK(threshold_ > 0.); DCHECK(threshold_ < 1.); scale_ = 1. / (1. - threshold_); - uint_thres_ = static_cast(UINT_MAX * threshold_); + uint_thres_ = + static_cast(static_cast + (std::numeric_limits::max()) + * static_cast(threshold_)); } template @@ -23,8 +27,7 @@ void DropoutLayer::Reshape(const vector*>& bottom, const vector*>& top) { NeuronLayer::Reshape(bottom, top); // Set up the cache for random number generation - rand_vec_.Reshape(bottom[0]->num(), bottom[0]->channels(), - bottom[0]->height(), bottom[0]->width()); + rand_vec_.Reshape(bottom[0]->shape()); } template @@ -32,16 +35,16 @@ void DropoutLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - unsigned int* mask = rand_vec_.mutable_cpu_data(); - const int count = bottom[0]->count(); + uint_tp* mask = rand_vec_.mutable_cpu_data(); + const int_tp count = bottom[0]->count(); if (this->phase_ == TRAIN) { // Create random numbers caffe_rng_bernoulli(count, 1. - threshold_, mask); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { top_data[i] = bottom_data[i] * mask[i] * scale_; } } else { - caffe_copy(bottom[0]->count(), bottom_data, top_data); + caffe_cpu_copy(bottom[0]->count(), bottom_data, top_data); } } @@ -53,13 +56,13 @@ void DropoutLayer::Backward_cpu(const vector*>& top, const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); if (this->phase_ == TRAIN) { - const unsigned int* mask = rand_vec_.cpu_data(); - const int count = bottom[0]->count(); - for (int i = 0; i < count; ++i) { + const uint_tp* mask = rand_vec_.cpu_data(); + const int_tp count = bottom[0]->count(); + for (int_tp i = 0; i < count; ++i) { bottom_diff[i] = top_diff[i] * mask[i] * scale_; } } else { - caffe_copy(top[0]->count(), top_diff, bottom_diff); + caffe_cpu_copy(top[0]->count(), top_diff, bottom_diff); } } } diff --git a/src/caffe/layers/dropout_layer.cu b/src/caffe/layers/dropout_layer.cu index 186c10ca489..aba3c790826 100644 --- a/src/caffe/layers/dropout_layer.cu +++ b/src/caffe/layers/dropout_layer.cu @@ -5,62 +5,122 @@ namespace caffe { -template -__global__ void DropoutForward(const int n, const Dtype* in, - const unsigned int* mask, const unsigned int threshold, const float scale, - Dtype* out) { + +#ifdef USE_CUDA +template +__global__ void DropoutForward(const int_tp n, const Dtype* in, + const uint_tp* mask, + const uint_tp threshold, const float scale, + Dtype* out) { CUDA_KERNEL_LOOP(index, n) { out[index] = in[index] * (mask[index] > threshold) * scale; } } +#endif // USE_CUDA -template +template void DropoutLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - if (this->phase_ == TRAIN) { - unsigned int* mask = - static_cast(rand_vec_.mutable_gpu_data()); - caffe_gpu_rng_uniform(count, mask); - // set thresholds - // NOLINT_NEXT_LINE(whitespace/operators) - DropoutForward<<>>( - count, bottom_data, mask, uint_thres_, scale_, top_data); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (this->phase_ == TRAIN) { + uint_tp* mask = + static_cast(rand_vec_.mutable_gpu_data()); + caffe_gpu_rng_uniform(count, (uint_tpc*) (mask)); // NOLINT + // set thresholds + // NOLINT_NEXT_LINE(whitespace/operators) + DropoutForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, mask, uint_thres_, scale_, top_data); + CUDA_POST_KERNEL_CHECK; + } else { + caffe_copy(count, bottom_data, top_data); + } +#endif // USE_CUDA } else { - caffe_copy(count, bottom_data, top_data); +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + if (this->phase_ == TRAIN) { + cl_mem mask = (cl_mem) (rand_vec_.mutable_gpu_data()); + greentea_gpu_rng_uniform(this->device_->id(), count, mask, 0); + // set thresholds + viennacl::ocl::kernel &oclk_dropout = program.get_kernel( + CL_KERNEL_SELECT("dropout_forward")); + viennacl::ocl::enqueue( + oclk_dropout(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle(mask, &ctx), uint_thres_, scale_, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + } else { + greentea_copy(count, (cl_mem) bottom_data, 0, (cl_mem) top_data, 0, + &ctx); + } +#endif // USE_GREENTEA } } -template -__global__ void DropoutBackward(const int n, const Dtype* in_diff, - const unsigned int* mask, const unsigned int threshold, const float scale, - Dtype* out_diff) { +#ifdef USE_CUDA +template +__global__ void DropoutBackward(const int_tp n, const Dtype* in_diff, + const uint_tp* mask, + const uint_tp threshold, const float scale, + Dtype* out_diff) { CUDA_KERNEL_LOOP(index, n) { out_diff[index] = in_diff[index] * scale * (mask[index] > threshold); } } +#endif // USE_CUDA -template +template void DropoutLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[0]) { const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - if (this->phase_ == TRAIN) { - const unsigned int* mask = - static_cast(rand_vec_.gpu_data()); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - DropoutBackward<<>>( - count, top_diff, mask, uint_thres_, scale_, bottom_diff); - CUDA_POST_KERNEL_CHECK; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (this->phase_ == TRAIN) { + const uint_tp* mask = static_cast(rand_vec_ + .gpu_data()); + const int_tp count = bottom[0]->count(); + // NOLINT_NEXT_LINE(whitespace/operators) + DropoutBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, mask, uint_thres_, scale_, bottom_diff); + CUDA_POST_KERNEL_CHECK; + } else { + caffe_copy(top[0]->count(), top_diff, bottom_diff); + } +#endif // USE_CUDA } else { - caffe_copy(top[0]->count(), top_diff, bottom_diff); +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if (this->phase_ == TRAIN) { + cl_mem mask = (cl_mem) (rand_vec_.gpu_data()); + const int_tp count = bottom[0]->count(); + viennacl::ocl::kernel &oclk_dropout = program.get_kernel( + CL_KERNEL_SELECT("dropout_backward")); + viennacl::ocl::enqueue( + oclk_dropout(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle(mask, &ctx), uint_thres_, scale_, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } else { + greentea_copy(top[0]->count(), (cl_mem) top_diff, 0, + (cl_mem) bottom_diff, 0, &ctx); + } +#endif // USE_GREENTEA } } } diff --git a/src/caffe/layers/dummy_data_layer.cpp b/src/caffe/layers/dummy_data_layer.cpp index e382bfea802..b8f63bacbf3 100644 --- a/src/caffe/layers/dummy_data_layer.cpp +++ b/src/caffe/layers/dummy_data_layer.cpp @@ -8,9 +8,9 @@ namespace caffe { template void DummyDataLayer::LayerSetUp(const vector*>& bottom, const vector*>& top) { - const int num_top = top.size(); + const int_tp num_top = top.size(); const DummyDataParameter& param = this->layer_param_.dummy_data_param(); - const int num_data_filler = param.data_filler_size(); + const int_tp num_data_filler = param.data_filler_size(); CHECK(num_data_filler == 0 || num_data_filler == 1 || num_data_filler == num_top) << "Number of data fillers must be 0, 1 or equal to the number of tops: " @@ -65,7 +65,7 @@ void DummyDataLayer::LayerSetUp(const vector*>& bottom, } else { refill_.resize(num_top); fillers_.resize(num_top); - for (int i = 0; i < num_top; ++i) { + for (int_tp i = 0; i < num_top; ++i) { fillers_[i].reset(GetFiller(param.data_filler(i))); // Refill on each iteration iff not using a constant filler, // but use the inverse of this rule for the first run. @@ -73,18 +73,18 @@ void DummyDataLayer::LayerSetUp(const vector*>& bottom, (strcmp(param.data_filler(i).type().c_str(), "constant") == 0); } } - for (int i = 0; i < num_top; ++i) { + for (int_tp i = 0; i < num_top; ++i) { if (legacy_dims) { - const int num = (param.num_size() == 1) ? param.num(0) : param.num(i); - const int channels = + const int_tp num = (param.num_size() == 1) ? param.num(0) : param.num(i); + const int_tp channels = (param.channels_size() == 1) ? param.channels(0) : param.channels(i); - const int height = + const int_tp height = (param.height_size() == 1) ? param.height(0) : param.height(i); - const int width = + const int_tp width = (param.width_size() == 1) ? param.width(0) : param.width(i); top[i]->Reshape(num, channels, height, width); } else { - const int shape_index = (param.shape_size() == 1) ? 0 : i; + const int_tp shape_index = (param.shape_size() == 1) ? 0 : i; top[i]->Reshape(param.shape(shape_index)); } } @@ -92,7 +92,7 @@ void DummyDataLayer::LayerSetUp(const vector*>& bottom, this->Forward(bottom, top); // Invert the inverted refill_ values to refill the desired (non-constant) // Blobs in every usual forward pass. - for (int i = 0; i < refill_.size(); ++i) { + for (int_tp i = 0; i < refill_.size(); ++i) { refill_[i] = !refill_[i]; } } @@ -100,8 +100,8 @@ void DummyDataLayer::LayerSetUp(const vector*>& bottom, template void DummyDataLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { - for (int i = 0; i < top.size(); ++i) { - const int filler_id = (fillers_.size() > 1) ? i : 0; + for (int_tp i = 0; i < top.size(); ++i) { + const int_tp filler_id = (fillers_.size() > 1) ? i : 0; if (refill_[filler_id]) { fillers_[filler_id]->Fill(top[i]); } diff --git a/src/caffe/layers/eltwise_layer.cpp b/src/caffe/layers/eltwise_layer.cpp index 21256166bfa..882a25f77a1 100644 --- a/src/caffe/layers/eltwise_layer.cpp +++ b/src/caffe/layers/eltwise_layer.cpp @@ -20,7 +20,7 @@ void EltwiseLayer::LayerSetUp(const vector*>& bottom, // Blob-wise coefficients for the elementwise operation. coeffs_ = vector(bottom.size(), 1); if (this->layer_param().eltwise_param().coeff_size()) { - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { coeffs_[i] = this->layer_param().eltwise_param().coeff(i); } } @@ -30,7 +30,7 @@ void EltwiseLayer::LayerSetUp(const vector*>& bottom, template void EltwiseLayer::Reshape(const vector*>& bottom, const vector*>& top) { - for (int i = 1; i < bottom.size(); ++i) { + for (int_tp i = 1; i < bottom.size(); ++i) { CHECK(bottom[i]->shape() == bottom[0]->shape()); } top[0]->ReshapeLike(*bottom[0]); @@ -44,34 +44,34 @@ void EltwiseLayer::Reshape(const vector*>& bottom, template void EltwiseLayer::Forward_cpu( const vector*>& bottom, const vector*>& top) { - int* mask = NULL; + int_tp* mask = NULL; const Dtype* bottom_data_a = NULL; const Dtype* bottom_data_b = NULL; - const int count = top[0]->count(); + const int_tp count = top[0]->count(); Dtype* top_data = top[0]->mutable_cpu_data(); switch (op_) { case EltwiseParameter_EltwiseOp_PROD: caffe_mul(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), top_data); - for (int i = 2; i < bottom.size(); ++i) { + for (int_tp i = 2; i < bottom.size(); ++i) { caffe_mul(count, top_data, bottom[i]->cpu_data(), top_data); } break; case EltwiseParameter_EltwiseOp_SUM: caffe_set(count, Dtype(0), top_data); // TODO(shelhamer) does BLAS optimize to sum for coeff = 1? - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { caffe_axpy(count, coeffs_[i], bottom[i]->cpu_data(), top_data); } break; case EltwiseParameter_EltwiseOp_MAX: // Initialize mask = max_idx_.mutable_cpu_data(); - caffe_set(count, -1, mask); + caffe_set(count, (int_tp)-1, mask); caffe_set(count, Dtype(-FLT_MAX), top_data); // bottom 0 & 1 bottom_data_a = bottom[0]->cpu_data(); bottom_data_b = bottom[1]->cpu_data(); - for (int idx = 0; idx < count; ++idx) { + for (int_tp idx = 0; idx < count; ++idx) { if (bottom_data_a[idx] > bottom_data_b[idx]) { top_data[idx] = bottom_data_a[idx]; // maxval mask[idx] = 0; // maxid @@ -81,9 +81,9 @@ void EltwiseLayer::Forward_cpu( } } // bottom 2++ - for (int blob_idx = 2; blob_idx < bottom.size(); ++blob_idx) { + for (int_tp blob_idx = 2; blob_idx < bottom.size(); ++blob_idx) { bottom_data_b = bottom[blob_idx]->cpu_data(); - for (int idx = 0; idx < count; ++idx) { + for (int_tp idx = 0; idx < count; ++idx) { if (bottom_data_b[idx] > top_data[idx]) { top_data[idx] = bottom_data_b[idx]; // maxval mask[idx] = blob_idx; // maxid @@ -99,11 +99,11 @@ void EltwiseLayer::Forward_cpu( template void EltwiseLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { - const int* mask = NULL; - const int count = top[0]->count(); + const int_tp* mask = NULL; + const int_tp count = top[0]->count(); const Dtype* top_data = top[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { if (propagate_down[i]) { const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); @@ -111,10 +111,10 @@ void EltwiseLayer::Backward_cpu(const vector*>& top, case EltwiseParameter_EltwiseOp_PROD: if (stable_prod_grad_) { bool initialized = false; - for (int j = 0; j < bottom.size(); ++j) { + for (int_tp j = 0; j < bottom.size(); ++j) { if (i == j) { continue; } if (!initialized) { - caffe_copy(count, bottom[j]->cpu_data(), bottom_diff); + caffe_cpu_copy(count, bottom[j]->cpu_data(), bottom_diff); initialized = true; } else { caffe_mul(count, bottom[j]->cpu_data(), bottom_diff, @@ -128,14 +128,14 @@ void EltwiseLayer::Backward_cpu(const vector*>& top, break; case EltwiseParameter_EltwiseOp_SUM: if (coeffs_[i] == Dtype(1)) { - caffe_copy(count, top_diff, bottom_diff); + caffe_cpu_copy(count, top_diff, bottom_diff); } else { caffe_cpu_scale(count, coeffs_[i], top_diff, bottom_diff); } break; case EltwiseParameter_EltwiseOp_MAX: mask = max_idx_.cpu_data(); - for (int index = 0; index < count; ++index) { + for (int_tp index = 0; index < count; ++index) { Dtype gradient = 0; if (mask[index] == i) { gradient += top_diff[index]; diff --git a/src/caffe/layers/eltwise_layer.cu b/src/caffe/layers/eltwise_layer.cu index c142852e03d..a2688bbbbd0 100644 --- a/src/caffe/layers/eltwise_layer.cu +++ b/src/caffe/layers/eltwise_layer.cu @@ -4,15 +4,21 @@ #include "caffe/layers/eltwise_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -__global__ void MaxForward(const int nthreads, const Dtype* bottom_data_a, - const Dtype* bottom_data_b, const int blob_idx, Dtype* top_data, - int* mask) { +#ifdef USE_CUDA +template +__global__ void MaxForward(const int_tp nthreads, const Dtype* bottom_data_a, + const Dtype* bottom_data_b, const int_tp blob_idx, + Dtype* top_data, int_tp* mask) { CUDA_KERNEL_LOOP(index, nthreads) { Dtype maxval = -FLT_MAX; - int maxidx = -1; + int_tp maxidx = -1; if (bottom_data_a[index] > bottom_data_b[index]) { // only update for very first bottom_data blob (blob_idx == 0) if (blob_idx == 0) { @@ -29,47 +35,119 @@ __global__ void MaxForward(const int nthreads, const Dtype* bottom_data_a, } } } +#endif // USE_CUDA -template +template void EltwiseLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - int* mask = NULL; - const int count = top[0]->count(); + const vector*>& top) { + int_tp* mask = NULL; + const int_tp count = top[0]->count(); Dtype* top_data = top[0]->mutable_gpu_data(); - switch (op_) { - case EltwiseParameter_EltwiseOp_PROD: - caffe_gpu_mul(count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), - top_data); - for (int i = 2; i < bottom.size(); ++i) { - caffe_gpu_mul(count, top_data, bottom[i]->gpu_data(), top_data); - } - break; - case EltwiseParameter_EltwiseOp_SUM: - caffe_gpu_set(count, Dtype(0.), top_data); - // TODO(shelhamer) does cuBLAS optimize to sum for coeff = 1? - for (int i = 0; i < bottom.size(); ++i) { - caffe_gpu_axpy(count, coeffs_[i], bottom[i]->gpu_data(), top_data); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + switch (op_) { + case EltwiseParameter_EltwiseOp_PROD: + caffe_gpu_mul(count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), + top_data); + for (int_tp i = 2; i < bottom.size(); ++i) { + caffe_gpu_mul(count, top_data, bottom[i]->gpu_data(), top_data); + } + break; + case EltwiseParameter_EltwiseOp_SUM: + caffe_gpu_set(count, Dtype(0.), top_data); + // TODO(shelhamer) does cuBLAS optimize to sum for coeff = 1? + for (int_tp i = 0; i < bottom.size(); ++i) { + caffe_gpu_axpy(count, coeffs_[i], bottom[i]->gpu_data(), top_data); + } + break; + case EltwiseParameter_EltwiseOp_MAX: + mask = max_idx_.mutable_gpu_data(); + // NOLINT_NEXT_LINE(whitespace/operators) + MaxForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), + 0, top_data, mask); + for (int_tp i = 2; i < bottom.size(); ++i) { + // NOLINT_NEXT_LINE(whitespace/operators) + MaxForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_data, bottom[i]->gpu_data(), i-1, top_data, mask); + } + break; + default: { + LOG(FATAL)<< "Unknown elementwise operation."; + } } - break; - case EltwiseParameter_EltwiseOp_MAX: - mask = max_idx_.mutable_gpu_data(); - // NOLINT_NEXT_LINE(whitespace/operators) - MaxForward <<>>( - count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), 0, top_data, mask); - for (int i = 2; i < bottom.size(); ++i) { - // NOLINT_NEXT_LINE(whitespace/operators) - MaxForward<<>>( - count, top_data, bottom[i]->gpu_data(), i-1, top_data, mask); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + switch (op_) { + case EltwiseParameter_EltwiseOp_PROD: { + greentea_gpu_mul(this->device_->id(), + count, (cl_mem)(bottom[0]->gpu_data()), 0, + (cl_mem)(bottom[1]->gpu_data()), 0, + (cl_mem)top_data, 0); + for (int_tp i = 2; i < bottom.size(); ++i) { + greentea_gpu_mul(this->device_->id(), + count, (cl_mem)top_data, 0, + (cl_mem)(bottom[i]->gpu_data()), 0, + (cl_mem)top_data, 0); + } + } + break; + case EltwiseParameter_EltwiseOp_SUM: { + greentea_gpu_set(this->device_->id(), count, 0, + (cl_mem)top_data, 0); + for (int_tp i = 0; i < bottom.size(); ++i) { + greentea_gpu_axpy(this->device_->id(), + count, coeffs_[i], + (cl_mem)(bottom[i]->gpu_data()), + 0, (cl_mem)top_data, 0); + } + } + break; + case EltwiseParameter_EltwiseOp_MAX: { + mask = max_idx_.mutable_gpu_data(); + + viennacl::ocl::kernel &oclk_max_forward = program.get_kernel( + CL_KERNEL_SELECT("eltwise_max_forward")); + + viennacl::ocl::enqueue( + oclk_max_forward(count, + WrapHandle((cl_mem)(bottom[0]->gpu_data()), &ctx), + WrapHandle((cl_mem)(bottom[1]->gpu_data()), &ctx), (int_tp)0, + WrapHandle((cl_mem)top_data, &ctx), + WrapHandle((cl_mem)mask, &ctx)), + ctx.get_queue()); + + for (int_tp i = 2; i < bottom.size(); ++i) { + viennacl::ocl::enqueue( + oclk_max_forward(count, WrapHandle((cl_mem)(top_data), &ctx), + WrapHandle((cl_mem)(bottom[i]->gpu_data()), &ctx), i-1, + WrapHandle((cl_mem)top_data, &ctx), + WrapHandle((cl_mem)mask, &ctx)), + ctx.get_queue()); + } + } + break; + default: { + LOG(FATAL)<< "Unknown elementwise operation."; + } } - break; - default: - LOG(FATAL) << "Unknown elementwise operation."; +#endif // USE_GREENTEA } } -template -__global__ void MaxBackward(const int nthreads, const Dtype* top_diff, - const int blob_idx, const int* mask, Dtype* bottom_diff) { +#ifdef USE_CUDA +template +__global__ void MaxBackward(const int_tp nthreads, const Dtype* top_diff, + const int_tp blob_idx, const int_tp* mask, + Dtype* bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { Dtype gradient = 0; if (mask[index] == blob_idx) { @@ -78,54 +156,135 @@ __global__ void MaxBackward(const int nthreads, const Dtype* top_diff, bottom_diff[index] = gradient; } } +#endif // USE_CUDA -template +template void EltwiseLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - const int* mask = NULL; - const int count = top[0]->count(); + const vector& propagate_down, + const vector*>& bottom) { + const int_tp* mask = NULL; + const int_tp count = top[0]->count(); const Dtype* top_data = top[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); - for (int i = 0; i < bottom.size(); ++i) { - if (propagate_down[i]) { - const Dtype* bottom_data = bottom[i]->gpu_data(); - Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); - switch (op_) { - case EltwiseParameter_EltwiseOp_PROD: - if (stable_prod_grad_) { - bool initialized = false; - for (int j = 0; j < bottom.size(); ++j) { - if (i == j) { continue; } - if (!initialized) { - caffe_copy(count, bottom[j]->gpu_data(), bottom_diff); - initialized = true; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int_tp i = 0; i < bottom.size(); ++i) { + if (propagate_down[i]) { + const Dtype* bottom_data = bottom[i]->gpu_data(); + Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); + switch (op_) { + case EltwiseParameter_EltwiseOp_PROD: + if (stable_prod_grad_) { + bool initialized = false; + for (int_tp j = 0; j < bottom.size(); ++j) { + if (i == j) { + continue; + } + if (!initialized) { + caffe_copy(count, bottom[j]->gpu_data(), bottom_diff); + initialized = true; + } else { + caffe_gpu_mul(count, bottom[j]->gpu_data(), bottom_diff, + bottom_diff); + } + } } else { - caffe_gpu_mul(count, bottom[j]->gpu_data(), bottom_diff, - bottom_diff); + caffe_gpu_div(count, top_data, bottom_data, bottom_diff); } + caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff); + break; + case EltwiseParameter_EltwiseOp_SUM: + if (coeffs_[i] == Dtype(1.)) { + caffe_copy(count, top_diff, bottom_diff); + } else { + caffe_gpu_scale(count, coeffs_[i], top_diff, bottom_diff); + } + break; + case EltwiseParameter_EltwiseOp_MAX: + mask = max_idx_.gpu_data(); + MaxBackward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS)( + count, top_diff, i, mask, bottom_diff); + break; + default: { + LOG(FATAL)<< "Unknown elementwise operation."; } - } else { - caffe_gpu_div(count, top_data, bottom_data, bottom_diff); } - caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff); - break; - case EltwiseParameter_EltwiseOp_SUM: - if (coeffs_[i] == Dtype(1.)) { - caffe_copy(count, top_diff, bottom_diff); - } else { - caffe_gpu_scale(count, coeffs_[i], top_diff, bottom_diff); + } + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + for (int_tp i = 0; i < bottom.size(); ++i) { + if (propagate_down[i]) { + const Dtype* bottom_data = bottom[i]->gpu_data(); + Dtype* bottom_diff = bottom[i]->mutable_gpu_diff(); + switch (op_) { + case EltwiseParameter_EltwiseOp_PROD: { + if (stable_prod_grad_) { + bool initialized = false; + for (int_tp j = 0; j < bottom.size(); ++j) { + if (i == j) { + continue; + } + if (!initialized) { + greentea_copy(count, + (cl_mem)(bottom[j]->gpu_data()), 0, + (cl_mem)(bottom_diff), 0, &ctx); + initialized = true; + } else { + greentea_gpu_mul(this->device_->id(), count, + (cl_mem)bottom[j]->gpu_data(), 0, + (cl_mem)bottom_diff, 0, + (cl_mem)bottom_diff, 0); + } + } + } else { + greentea_gpu_div(this->device_->id(), + count, (cl_mem)top_data, 0, + (cl_mem)bottom_data, 0, (cl_mem)bottom_diff, 0); + } + greentea_gpu_mul(this->device_->id(), + count, (cl_mem)bottom_diff, 0, + (cl_mem)top_diff, 0, (cl_mem)bottom_diff, 0); + } + break; + case EltwiseParameter_EltwiseOp_SUM: { + if (coeffs_[i] == Dtype(1.)) { + greentea_copy(count, (cl_mem)top_diff, + 0, (cl_mem)bottom_diff, 0, &ctx); + } else { + greentea_gpu_scale(this->device_->id(), + count, coeffs_[i], (cl_mem)top_diff, + 0, (cl_mem)bottom_diff, 0); + } + } + break; + case EltwiseParameter_EltwiseOp_MAX: { + mask = max_idx_.gpu_data(); + + viennacl::ocl::kernel &oclk_max_backward = program.get_kernel( + CL_KERNEL_SELECT("eltwise_max_backward")); + + viennacl::ocl::enqueue( + oclk_max_backward(count, WrapHandle((cl_mem)top_diff, &ctx), i, + WrapHandle((cl_mem)mask, &ctx), + WrapHandle((cl_mem)bottom_diff, &ctx)), + ctx.get_queue()); + } + break; + default: { + LOG(FATAL)<< "Unknown elementwise operation."; + } } - break; - case EltwiseParameter_EltwiseOp_MAX: - mask = max_idx_.gpu_data(); - MaxBackward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - count, top_diff, i, mask, bottom_diff); - break; - default: - LOG(FATAL) << "Unknown elementwise operation."; } } +#endif } } diff --git a/src/caffe/layers/elu_layer.cu b/src/caffe/layers/elu_layer.cu index 12545aa8253..0b57cf83379 100644 --- a/src/caffe/layers/elu_layer.cu +++ b/src/caffe/layers/elu_layer.cu @@ -5,6 +5,7 @@ namespace caffe { +#ifdef USE_CUDA template __global__ void ELUForward(const int n, const Dtype* in, Dtype* out, Dtype alpha) { @@ -13,6 +14,7 @@ __global__ void ELUForward(const int n, const Dtype* in, Dtype* out, alpha * (exp(in[index]) - 1); } } +#endif // USE_CUDA template void ELULayer::Forward_gpu(const vector*>& bottom, @@ -21,12 +23,32 @@ void ELULayer::Forward_gpu(const vector*>& bottom, Dtype* top_data = top[0]->mutable_gpu_data(); const int count = bottom[0]->count(); Dtype alpha = this->layer_param_.elu_param().alpha(); - // NOLINT_NEXT_LINE(whitespace/operators) - ELUForward<<>>( - count, bottom_data, top_data, alpha); - CUDA_POST_KERNEL_CHECK; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + ELUForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, top_data, alpha); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_elu = program.get_kernel( + CL_KERNEL_SELECT("elu_forward")); + viennacl::ocl::enqueue( + oclk_elu(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx), alpha), + ctx.get_queue()); +#endif // USE_GREENTEA + } } +#ifdef USE_CUDA template __global__ void ELUBackward(const int n, const Dtype* in_diff, const Dtype* out_data, const Dtype* in_data, @@ -36,6 +58,7 @@ __global__ void ELUBackward(const int n, const Dtype* in_diff, in_diff[index] * (out_data[index] + alpha); } } +#endif // USE_CUDA template void ELULayer::Backward_gpu(const vector*>& top, @@ -48,10 +71,31 @@ void ELULayer::Backward_gpu(const vector*>& top, Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); const int count = bottom[0]->count(); Dtype alpha = this->layer_param_.elu_param().alpha(); - // NOLINT_NEXT_LINE(whitespace/operators) - ELUBackward<<>>( - count, top_diff, top_data, bottom_data, bottom_diff, alpha); - CUDA_POST_KERNEL_CHECK; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + ELUBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, top_data, bottom_data, bottom_diff, alpha); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_elu = program.get_kernel( + CL_KERNEL_SELECT("elu_backward")); + viennacl::ocl::enqueue( + oclk_elu(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx), alpha), + ctx.get_queue()); +#endif // USE_GREENTEA + } } } diff --git a/src/caffe/layers/embed_layer.cpp b/src/caffe/layers/embed_layer.cpp index 36b40d700fd..4329a0cb015 100644 --- a/src/caffe/layers/embed_layer.cpp +++ b/src/caffe/layers/embed_layer.cpp @@ -25,18 +25,18 @@ void EmbedLayer::LayerSetUp(const vector*>& bottom, } // Initialize the weights -- // transposed from InnerProductLayer for spatial locality. - vector weight_shape(2); + vector weight_shape(2); weight_shape[0] = K_; weight_shape[1] = N_; - this->blobs_[0].reset(new Blob(weight_shape)); + this->blobs_[0].reset(new Blob(weight_shape, this->device_)); // fill the weights shared_ptr > weight_filler(GetFiller( this->layer_param_.embed_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the bias term if (bias_term_) { - vector bias_shape(1, N_); - this->blobs_[1].reset(new Blob(bias_shape)); + vector bias_shape(1, N_); + this->blobs_[1].reset(new Blob(bias_shape, this->device_)); shared_ptr > bias_filler(GetFiller( this->layer_param_.embed_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); @@ -50,12 +50,12 @@ void EmbedLayer::Reshape(const vector*>& bottom, const vector*>& top) { // Figure out the dimensions M_ = bottom[0]->count(); - vector top_shape = bottom[0]->shape(); + vector top_shape = bottom[0]->shape(); top_shape.push_back(N_); top[0]->Reshape(top_shape); // Set up the bias multiplier if (bias_term_) { - vector bias_shape(1, M_); + vector bias_shape(1, M_); bias_multiplier_.Reshape(bias_shape); caffe_set(M_, Dtype(1), bias_multiplier_.mutable_cpu_data()); } @@ -67,13 +67,13 @@ void EmbedLayer::Forward_cpu(const vector*>& bottom, const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* weight = this->blobs_[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - int index; - for (int n = 0; n < M_; ++n) { - index = static_cast(bottom_data[n]); + int_tp index; + for (int_tp n = 0; n < M_; ++n) { + index = static_cast(bottom_data[n]); DCHECK_GE(index, 0); DCHECK_LT(index, K_); DCHECK_EQ(static_cast(index), bottom_data[n]) << "non-integer input"; - caffe_copy(N_, weight + index * N_, top_data + n * N_); + caffe_cpu_copy(N_, weight + index * N_, top_data + n * N_); } if (bias_term_) { const Dtype* bias = this->blobs_[1]->cpu_data(); @@ -91,9 +91,9 @@ void EmbedLayer::Backward_cpu(const vector*>& top, const Dtype* bottom_data = bottom[0]->cpu_data(); // Gradient with respect to weight Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff(); - int index; - for (int n = 0; n < M_; ++n) { - index = static_cast(bottom_data[n]); + int_tp index; + for (int_tp n = 0; n < M_; ++n) { + index = static_cast(bottom_data[n]); DCHECK_GE(index, 0); DCHECK_LT(index, K_); DCHECK_EQ(static_cast(index), bottom_data[n]) diff --git a/src/caffe/layers/embed_layer.cu b/src/caffe/layers/embed_layer.cu index 6324a3a8937..7d479a0ec67 100644 --- a/src/caffe/layers/embed_layer.cu +++ b/src/caffe/layers/embed_layer.cu @@ -2,41 +2,46 @@ #include "caffe/filler.hpp" #include "caffe/layers/embed_layer.hpp" +#ifdef USE_CUDA #include "caffe/util/gpu_util.cuh" +#endif // USE_CUDA #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + + namespace caffe { +#ifdef USE_CUDA template -__global__ void EmbedForward(const int nthreads, const Dtype* bottom_data, - const Dtype* weight, const int M, const int N, const int K, +__global__ void EmbedForward(const int_tp nthreads, const Dtype* bottom_data, + const Dtype* weight, const int_tp M, const int_tp N, const int_tp K, Dtype* top_data) { CUDA_KERNEL_LOOP(top_index, nthreads) { - const int n = top_index / N; - const int d = top_index % N; - const int index = static_cast(bottom_data[n]); - const int weight_index = index * N + d; + const int_tp n = top_index / N; + const int_tp d = top_index % N; + const int_tp index = static_cast(bottom_data[n]); + const int_tp weight_index = index * N + d; top_data[top_index] = weight[weight_index]; } } template -__global__ void EmbedBackward(const int nthreads, const Dtype* bottom_data, - const Dtype* top_diff, const int M, const int N, const int K, - Dtype* weight_diff); - -template -__global__ void EmbedBackward(const int nthreads, const Dtype* bottom_data, - const Dtype* top_diff, const int M, const int N, const int K, +__global__ void EmbedBackward(const int_tp nthreads, const Dtype* bottom_data, + const Dtype* top_diff, const int_tp M, const int_tp N, const int_tp K, Dtype* weight_diff) { CUDA_KERNEL_LOOP(top_index, nthreads) { - const int n = top_index / N; - const int d = top_index % N; - const int index = static_cast(bottom_data[n]); - const int weight_index = index * N + d; + const int_tp n = top_index / N; + const int_tp d = top_index % N; + const int_tp index = static_cast(bottom_data[n]); + const int_tp weight_index = index * N + d; caffe_gpu_atomic_add(top_diff[top_index], weight_diff + weight_index); } } +#endif // USE_CUDA template void EmbedLayer::Forward_gpu(const vector*>& bottom, @@ -44,15 +49,43 @@ void EmbedLayer::Forward_gpu(const vector*>& bottom, const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); const Dtype* weight = this->blobs_[0]->gpu_data(); - const int count = top[0]->count(); - EmbedForward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - count, bottom_data, weight, M_, N_, K_, top_data); - if (bias_term_) { - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, Dtype(1), - bias_multiplier_.gpu_data(), - this->blobs_[1]->gpu_data(), Dtype(1), top_data); - } + const int_tp count = top[0]->count(); + if (this->get_device()->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + + EmbedForward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, weight, M_, N_, K_, top_data); + if (bias_term_) { + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, Dtype(1), + bias_multiplier_.gpu_data(), + this->blobs_[1]->gpu_data(), Dtype(1), top_data); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_embed = program.get_kernel( + CL_KERNEL_SELECT("embed_forward")); + viennacl::ocl::enqueue( + oclk_embed(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) weight, &ctx), M_, N_, K_, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + + if (bias_term_) { + greentea_gpu_gemm(this->get_device()->id(), CblasNoTrans, + CblasNoTrans, M_, N_, 1, Dtype(1), + (cl_mem) (bias_multiplier_.gpu_data()), 0, + (cl_mem) (this->blobs_[1]->gpu_data()), 0, + Dtype(1), (cl_mem) top_data, 0); + } + +#endif // USE_GREENTEA + } } template @@ -60,22 +93,52 @@ void EmbedLayer::Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { CHECK(!propagate_down[0]) << "Can't backpropagate to EmbedLayer input."; if (this->param_propagate_down_[0]) { - const int top_count = top[0]->count(); + const int_tp top_count = top[0]->count(); const Dtype* top_diff = top[0]->gpu_diff(); const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* weight_diff = this->blobs_[0]->mutable_gpu_diff(); + if (this->get_device()->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA EmbedBackward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(top_count), CAFFE_CUDA_NUM_THREADS)( top_count, bottom_data, top_diff, M_, N_, K_, weight_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_embed = program.get_kernel( + CL_KERNEL_SELECT("embed_backward")); + viennacl::ocl::enqueue( + oclk_embed(top_count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_diff, &ctx), M_, N_, K_, + WrapHandle((cl_mem) weight_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } if (bias_term_ && this->param_propagate_down_[1]) { const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bias_diff = this->blobs_[1]->mutable_gpu_diff(); + if (this->get_device()->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_gemv(CblasTrans, M_, N_, Dtype(1), top_diff, bias_multiplier_.gpu_data(), Dtype(1), bias_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemv(this->get_device()->id(), CblasTrans, M_, N_, + Dtype(1), (cl_mem) top_diff, 0, + (cl_mem) (bias_multiplier_.gpu_data()), 0, + Dtype(1), (cl_mem) bias_diff, 0); +#endif // USE_GREENTEA + } } } INSTANTIATE_LAYER_GPU_FUNCS(EmbedLayer); } // namespace caffe + diff --git a/src/caffe/layers/euclidean_loss_layer.cpp b/src/caffe/layers/euclidean_loss_layer.cpp index 300d991e765..4714b4a266c 100644 --- a/src/caffe/layers/euclidean_loss_layer.cpp +++ b/src/caffe/layers/euclidean_loss_layer.cpp @@ -5,42 +5,45 @@ namespace caffe { -template -void EuclideanLossLayer::Reshape( - const vector*>& bottom, const vector*>& top) { +template +void EuclideanLossLayer::Reshape(const vector*>& bottom, + const vector*>& top) { LossLayer::Reshape(bottom, top); CHECK_EQ(bottom[0]->count(1), bottom[1]->count(1)) << "Inputs must have the same dimension."; diff_.ReshapeLike(*bottom[0]); } -template +template void EuclideanLossLayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { - int count = bottom[0]->count(); - caffe_sub( - count, - bottom[0]->cpu_data(), - bottom[1]->cpu_data(), - diff_.mutable_cpu_data()); + const vector*>& top) { + int_tp count = bottom[0]->count(); + caffe_sub(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), + diff_.mutable_cpu_data()); + // Scale the error element-wise + if (bottom.size() == 3) { + caffe_mul(count, diff_.mutable_cpu_data(), bottom[2]->gpu_data(), + diff_.mutable_cpu_data()); + } Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data()); - Dtype loss = dot / bottom[0]->num() / Dtype(2); + Dtype loss = dot / static_cast(bottom[0]->count(0)) / Dtype(2); top[0]->mutable_cpu_data()[0] = loss; } -template -void EuclideanLossLayer::Backward_cpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - for (int i = 0; i < 2; ++i) { +template +void EuclideanLossLayer::Backward_cpu( + const vector*>& top, const vector& propagate_down, + const vector*>& bottom) { + for (int_tp i = 0; i < 2; ++i) { if (propagate_down[i]) { const Dtype sign = (i == 0) ? 1 : -1; - const Dtype alpha = sign * top[0]->cpu_diff()[0] / bottom[i]->num(); - caffe_cpu_axpby( - bottom[i]->count(), // count + const Dtype alpha = sign * top[0]->cpu_diff()[0] + / static_cast(bottom[0]->count(0)); + caffe_cpu_axpby(bottom[i]->count(), // count alpha, // alpha diff_.cpu_data(), // a Dtype(0), // beta - bottom[i]->mutable_cpu_diff()); // b + bottom[i]->mutable_cpu_diff()); // b } } } diff --git a/src/caffe/layers/euclidean_loss_layer.cu b/src/caffe/layers/euclidean_loss_layer.cu index 4c221b64faf..07b1e7fda8e 100644 --- a/src/caffe/layers/euclidean_loss_layer.cu +++ b/src/caffe/layers/euclidean_loss_layer.cu @@ -3,36 +3,76 @@ #include "caffe/layers/euclidean_loss_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void EuclideanLossLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - int count = bottom[0]->count(); - caffe_gpu_sub( - count, - bottom[0]->gpu_data(), - bottom[1]->gpu_data(), - diff_.mutable_gpu_data()); + const vector*>& top) { + int_tp count = bottom[0]->count(); Dtype dot; - caffe_gpu_dot(count, diff_.gpu_data(), diff_.gpu_data(), &dot); - Dtype loss = dot / bottom[0]->num() / Dtype(2); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_sub(count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), + diff_.mutable_gpu_data()); + // Scale the error element-wise + if (bottom.size() == 3) { + caffe_gpu_mul(count, diff_.mutable_gpu_data(), + bottom[2]->gpu_data(), diff_.mutable_gpu_data()); + } + caffe_gpu_dot(count, diff_.gpu_data(), diff_.gpu_data(), &dot); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_sub(this->device_->id(), count, + (cl_mem) (bottom[0]->gpu_data()), 0, + (cl_mem) (bottom[1]->gpu_data()), 0, + (cl_mem) (diff_.mutable_gpu_data()), 0); + // Scale the error element-wise + if (bottom.size() == 3) { + greentea_gpu_mul(this->device_->id(), count, + (cl_mem) (diff_.mutable_gpu_data()), 0, + (cl_mem) (bottom[2]->gpu_data()), 0, + (cl_mem) (diff_.mutable_gpu_data()), 0); + } + greentea_gpu_dot(this->device_->id(), count, + (cl_mem) (diff_.gpu_data()), 0, + (cl_mem) (diff_.gpu_data()), 0, &dot); +#endif // USE_GREENTEA + } + Dtype loss = dot / static_cast(bottom[0]->count(0)) / Dtype(2); top[0]->mutable_cpu_data()[0] = loss; } -template -void EuclideanLossLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - for (int i = 0; i < 2; ++i) { +template +void EuclideanLossLayer::Backward_gpu( + const vector*>& top, const vector& propagate_down, + const vector*>& bottom) { + for (int_tp i = 0; i < 2; ++i) { if (propagate_down[i]) { const Dtype sign = (i == 0) ? 1 : -1; - const Dtype alpha = sign * top[0]->cpu_diff()[0] / bottom[i]->num(); - caffe_gpu_axpby( - bottom[i]->count(), // count - alpha, // alpha - diff_.gpu_data(), // a - Dtype(0), // beta - bottom[i]->mutable_gpu_diff()); // b + const Dtype alpha = sign * top[0]->cpu_diff()[0] + / static_cast(bottom[0]->count(0)); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_axpby(bottom[i]->count(), // count + alpha, // alpha + diff_.gpu_data(), // a + Dtype(0), // beta + bottom[i]->mutable_gpu_diff()); // b +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_axpby(this->device_->id(), bottom[i]->count(), alpha, + (cl_mem) (diff_.gpu_data()), 0, Dtype(0), + (cl_mem) (bottom[i]->mutable_gpu_diff()), 0); +#endif // USE_GREENTEA + } } } } diff --git a/src/caffe/layers/exp_layer.cpp b/src/caffe/layers/exp_layer.cpp index 1f4a309fe25..12f1fbf7de4 100644 --- a/src/caffe/layers/exp_layer.cpp +++ b/src/caffe/layers/exp_layer.cpp @@ -29,7 +29,7 @@ void ExpLayer::LayerSetUp(const vector*>& bottom, template void ExpLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); if (inner_scale_ == Dtype(1)) { @@ -47,7 +47,7 @@ template void ExpLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (!propagate_down[0]) { return; } - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); const Dtype* top_data = top[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); diff --git a/src/caffe/layers/exp_layer.cu b/src/caffe/layers/exp_layer.cu index 61f7f11dd46..baf1e3f70d5 100644 --- a/src/caffe/layers/exp_layer.cu +++ b/src/caffe/layers/exp_layer.cu @@ -5,38 +5,78 @@ namespace caffe { -template +template void ExpLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - const int count = bottom[0]->count(); + const vector*>& top) { + const int_tp count = bottom[0]->count(); const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - if (inner_scale_ == Dtype(1)) { - caffe_gpu_exp(count, bottom_data, top_data); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (inner_scale_ == Dtype(1)) { + caffe_gpu_exp(count, bottom_data, top_data); + } else { + caffe_gpu_scale(count, inner_scale_, bottom_data, top_data); + caffe_gpu_exp(count, top_data, top_data); + } + if (outer_scale_ != Dtype(1)) { + caffe_gpu_scal(count, outer_scale_, top_data); + } +#endif // USE_CUDA } else { - caffe_gpu_scale(count, inner_scale_, bottom_data, top_data); - caffe_gpu_exp(count, top_data, top_data); - } - if (outer_scale_ != Dtype(1)) { - caffe_gpu_scal(count, outer_scale_, top_data); +#ifdef USE_GREENTEA + if (inner_scale_ == Dtype(1)) { + greentea_gpu_exp(this->device_->id(), count, + (cl_mem) bottom_data, 0, (cl_mem) top_data, 0); + } else { + greentea_gpu_scale(this->device_->id(), + count, inner_scale_, + (cl_mem) bottom_data, 0, (cl_mem) top_data, 0); + greentea_gpu_exp(this->device_->id(), count, + (cl_mem) top_data, 0, (cl_mem) top_data, 0); + } + if (outer_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), + count, outer_scale_, + (cl_mem) top_data, 0); + } +#endif // USE_GREENTEA } } -template +template void ExpLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (!propagate_down[0]) { return; } - const int count = bottom[0]->count(); + const vector& propagate_down, + const vector*>& bottom) { + if (!propagate_down[0]) { + return; + } + const int_tp count = bottom[0]->count(); const Dtype* top_data = top[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - caffe_gpu_mul(count, top_data, top_diff, bottom_diff); - if (inner_scale_ != Dtype(1)) { - caffe_gpu_scal(count, inner_scale_, bottom_diff); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_mul(count, top_data, top_diff, bottom_diff); + if (inner_scale_ != Dtype(1)) { + caffe_gpu_scal(count, inner_scale_, bottom_diff); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_mul(this->device_->id(), count, + (cl_mem) top_data, 0, (cl_mem) top_diff, 0, + (cl_mem) bottom_diff, 0); + if (inner_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, inner_scale_, + (cl_mem) bottom_diff, 0); + } +#endif // USE_GREENTEA } } INSTANTIATE_LAYER_GPU_FUNCS(ExpLayer); - } // namespace caffe diff --git a/src/caffe/layers/filter_layer.cpp b/src/caffe/layers/filter_layer.cpp index e226c0b6c9b..c99392b16e5 100644 --- a/src/caffe/layers/filter_layer.cpp +++ b/src/caffe/layers/filter_layer.cpp @@ -17,12 +17,12 @@ void FilterLayer::Reshape(const vector*>& bottom, const vector*>& top) { // bottom[0...k-1] are the blobs to filter // bottom[last] is the "selector_blob" - int selector_index = bottom.size() - 1; - for (int i = 1; i < bottom[selector_index]->num_axes(); ++i) { + int_tp selector_index = bottom.size() - 1; + for (int_tp i = 1; i < bottom[selector_index]->num_axes(); ++i) { CHECK_EQ(bottom[selector_index]->shape(i), 1) << "Selector blob dimensions must be singletons (1), except the first"; } - for (int i = 0; i < bottom.size() - 1; ++i) { + for (int_tp i = 0; i < bottom.size() - 1; ++i) { CHECK_EQ(bottom[selector_index]->shape(0), bottom[i]->shape(0)) << "Each bottom should have the same 0th dimension as the selector blob"; } @@ -33,7 +33,8 @@ void FilterLayer::Reshape(const vector*>& bottom, // look for non-zero elements in bottom[0]. Items of each bottom that // have the same index as the items in bottom[0] with value == non-zero // will be forwarded - for (int item_id = 0; item_id < bottom[selector_index]->shape(0); ++item_id) { + for (int_tp item_id = 0; item_id < bottom[selector_index]->shape(0); + ++item_id) { // we don't need an offset because item size == 1 const Dtype* tmp_data_selector = bottom_data_selector + item_id; if (*tmp_data_selector) { @@ -41,17 +42,17 @@ void FilterLayer::Reshape(const vector*>& bottom, } } // only filtered items will be forwarded - int new_tops_num = indices_to_forward_.size(); + int_tp new_tops_num = indices_to_forward_.size(); // init if (first_reshape_) { new_tops_num = bottom[0]->shape(0); first_reshape_ = false; } - for (int t = 0; t < top.size(); ++t) { - int num_axes = bottom[t]->num_axes(); - vector shape_top(num_axes); + for (int_tp t = 0; t < top.size(); ++t) { + int_tp num_axes = bottom[t]->num_axes(); + vector shape_top(num_axes); shape_top[0] = new_tops_num; - for (int ts = 1; ts < num_axes; ++ts) + for (int_tp ts = 1; ts < num_axes; ++ts) shape_top[ts] = bottom[t]->shape(ts); top[t]->Reshape(shape_top); } @@ -60,16 +61,16 @@ void FilterLayer::Reshape(const vector*>& bottom, template void FilterLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { - int new_tops_num = indices_to_forward_.size(); + int_tp new_tops_num = indices_to_forward_.size(); // forward all filtered items for all bottoms but the Selector (bottom[last]) - for (int t = 0; t < top.size(); ++t) { + for (int_tp t = 0; t < top.size(); ++t) { const Dtype* bottom_data = bottom[t]->cpu_data(); Dtype* top_data = top[t]->mutable_cpu_data(); - int dim = bottom[t]->count() / bottom[t]->shape(0); - for (int n = 0; n < new_tops_num; ++n) { - int data_offset_top = n * dim; - int data_offset_bottom = indices_to_forward_[n] * bottom[t]->count(1); - caffe_copy(dim, bottom_data + data_offset_bottom, + int_tp dim = bottom[t]->count() / bottom[t]->shape(0); + for (int_tp n = 0; n < new_tops_num; ++n) { + int_tp data_offset_top = n * dim; + int_tp data_offset_bottom = indices_to_forward_[n] * bottom[t]->count(1); + caffe_cpu_copy(dim, bottom_data + data_offset_bottom, top_data + data_offset_top); } } @@ -82,16 +83,16 @@ void FilterLayer::Backward_cpu(const vector*>& top, LOG(FATAL) << this->type() << "Layer cannot backpropagate to filter index inputs"; } - for (int i = 0; i < top.size(); i++) { + for (int_tp i = 0; i < top.size(); i++) { // bottom[last] is the selector and never needs backpropagation // so we can iterate over top vector because top.size() == bottom.size() -1 if (propagate_down[i]) { - const int dim = top[i]->count() / top[i]->shape(0); - int next_to_backward_offset = 0; - int batch_offset = 0; - int data_offset_bottom = 0; - int data_offset_top = 0; - for (int n = 0; n < bottom[i]->shape(0); n++) { + const int_tp dim = top[i]->count() / top[i]->shape(0); + int_tp next_to_backward_offset = 0; + int_tp batch_offset = 0; + int_tp data_offset_bottom = 0; + int_tp data_offset_top = 0; + for (int_tp n = 0; n < bottom[i]->shape(0); n++) { data_offset_bottom = n * dim; if (next_to_backward_offset >= indices_to_forward_.size()) { // we already visited all items that were been forwarded, so @@ -106,7 +107,7 @@ void FilterLayer::Backward_cpu(const vector*>& top, } else { // this data was been forwarded data_offset_top = next_to_backward_offset * dim; next_to_backward_offset++; // point to next forwarded item index - caffe_copy(dim, top[i]->mutable_cpu_diff() + data_offset_top, + caffe_cpu_copy(dim, top[i]->mutable_cpu_diff() + data_offset_top, bottom[i]->mutable_cpu_diff() + data_offset_bottom); } } diff --git a/src/caffe/layers/filter_layer.cu b/src/caffe/layers/filter_layer.cu index b01b16f840c..b2bb13aa6cf 100644 --- a/src/caffe/layers/filter_layer.cu +++ b/src/caffe/layers/filter_layer.cu @@ -5,60 +5,108 @@ namespace caffe { -template +template void FilterLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - int new_tops_num = indices_to_forward_.size(); + const vector*>& top) { + int_tp new_tops_num = indices_to_forward_.size(); // forward all filtered items for all bottoms but the Selector (bottom[last]) - for (int t = 0; t < top.size(); ++t) { + for (int_tp t = 0; t < top.size(); ++t) { const Dtype* bottom_data = bottom[t]->gpu_data(); Dtype* top_data = top[t]->mutable_gpu_data(); - int dim = bottom[t]->count() / bottom[t]->shape(0); - for (int n = 0; n < new_tops_num; ++n) { - int data_offset_top = n * dim; - int data_offset_bottom = indices_to_forward_[n] * dim; - caffe_copy(dim, bottom_data + data_offset_bottom, - top_data + data_offset_top); + int_tp dim = bottom[t]->count() / bottom[t]->shape(0); + for (int_tp n = 0; n < new_tops_num; ++n) { + int_tp data_offset_top = n * dim; + int_tp data_offset_bottom = indices_to_forward_[n] * dim; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_copy(dim, bottom_data + data_offset_bottom, + top_data + data_offset_top); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + greentea_copy(dim, (cl_mem) bottom_data, data_offset_bottom, + (cl_mem) top_data, data_offset_top, &ctx); +#endif // USE_GREENTEA + } } } } -template +template void FilterLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[bottom.size() - 1]) { - LOG(FATAL) << this->type() - << "Layer cannot backpropagate to filter index inputs"; + LOG(FATAL)<< this->type() + << "Layer cannot backpropagate to filter index inputs"; } - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { // bottom[last] is the selector and never needs backpropagation // so we can iterate over top vector because top.size() == bottom.size() -1 if (propagate_down[i]) { - const int dim = top[i]->count() / top[i]->shape(0); - int next_to_backward_offset = 0; - int batch_offset = 0; - int data_offset_bottom = 0; - int data_offset_top = 0; - for (int n = 0; n < bottom[i]->shape(0); ++n) { - if (next_to_backward_offset >= indices_to_forward_.size()) { - // we already visited all items that were been forwarded, so - // just set to zero remaining ones - data_offset_bottom = n * dim; - caffe_gpu_set(dim, Dtype(0), - bottom[i]->mutable_gpu_diff() + data_offset_bottom); - } else { - batch_offset = indices_to_forward_[next_to_backward_offset]; - data_offset_bottom = n * dim; - if (n != batch_offset) { // this data was not been forwarded + const int_tp dim = top[i]->count() / top[i]->shape(0); + int_tp next_to_backward_offset = 0; + int_tp batch_offset = 0; + int_tp data_offset_bottom = 0; + int_tp data_offset_top = 0; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int_tp n = 0; n < bottom[i]->shape(0); ++n) { + if (next_to_backward_offset >= indices_to_forward_.size()) { + // we already visited all items that were been forwarded, so + // just set to zero remaining ones + data_offset_bottom = n * dim; caffe_gpu_set(dim, Dtype(0), bottom[i]->mutable_gpu_diff() + data_offset_bottom); - } else { // this data was been forwarded - data_offset_top = next_to_backward_offset * dim; - ++next_to_backward_offset; // point to next forwarded item index - caffe_copy(dim, top[i]->mutable_gpu_diff() + data_offset_top, - bottom[i]->mutable_gpu_diff() + data_offset_bottom); + } else { + batch_offset = indices_to_forward_[next_to_backward_offset]; + data_offset_bottom = n * dim; + if (n != batch_offset) { // this data was not been forwarded + caffe_gpu_set(dim, Dtype(0), + bottom[i]->mutable_gpu_diff() + data_offset_bottom); + } else { // this data was been forwarded + data_offset_top = next_to_backward_offset * dim; + ++next_to_backward_offset; // point to next forwarded item index + caffe_copy(dim, top[i]->mutable_gpu_diff() + data_offset_top, + bottom[i]->mutable_gpu_diff() + data_offset_bottom); + } + } + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + for (int_tp n = 0; n < bottom[i]->shape(0); ++n) { + if (next_to_backward_offset >= indices_to_forward_.size()) { + // we already visited all items that were been forwarded, so + // just set to zero remaining ones + data_offset_bottom = n * dim; + greentea_gpu_set(this->device_->id(), dim, Dtype(0), + (cl_mem)(bottom[i]->mutable_gpu_diff()), data_offset_bottom); + } else { + batch_offset = indices_to_forward_[next_to_backward_offset]; + data_offset_bottom = n * dim; + if (n != batch_offset) { // this data was not been forwarded + greentea_gpu_set(this->device_->id(), dim, Dtype(0), + (cl_mem)(bottom[i]->mutable_gpu_diff()), data_offset_bottom); + } else { // this data was been forwarded + data_offset_top = next_to_backward_offset * dim; + ++next_to_backward_offset; // point to next forwarded item index + greentea_copy(dim, (cl_mem)(top[i]->mutable_gpu_diff()), + data_offset_top, + (cl_mem)(bottom[i]->mutable_gpu_diff()), + data_offset_bottom, &ctx); + } } } +#endif // USE_GREENTEA } } } diff --git a/src/caffe/layers/flatten_layer.cpp b/src/caffe/layers/flatten_layer.cpp index d4ab3935760..e0f430e5c40 100644 --- a/src/caffe/layers/flatten_layer.cpp +++ b/src/caffe/layers/flatten_layer.cpp @@ -9,17 +9,17 @@ void FlattenLayer::Reshape(const vector*>& bottom, const vector*>& top) { CHECK_NE(top[0], bottom[0]) << this->type() << " Layer does not " "allow in-place computation."; - const int start_axis = bottom[0]->CanonicalAxisIndex( + const int_tp start_axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.flatten_param().axis()); - const int end_axis = bottom[0]->CanonicalAxisIndex( + const int_tp end_axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.flatten_param().end_axis()); - vector top_shape; - for (int i = 0; i < start_axis; ++i) { + vector top_shape; + for (int_tp i = 0; i < start_axis; ++i) { top_shape.push_back(bottom[0]->shape(i)); } - const int flattened_dim = bottom[0]->count(start_axis, end_axis + 1); + const int_tp flattened_dim = bottom[0]->count(start_axis, end_axis + 1); top_shape.push_back(flattened_dim); - for (int i = end_axis + 1; i < bottom[0]->num_axes(); ++i) { + for (int_tp i = end_axis + 1; i < bottom[0]->num_axes(); ++i) { top_shape.push_back(bottom[0]->shape(i)); } top[0]->Reshape(top_shape); diff --git a/src/caffe/layers/hdf5_data_layer.cpp b/src/caffe/layers/hdf5_data_layer.cpp index 2f13dc641df..514855c4ccd 100644 --- a/src/caffe/layers/hdf5_data_layer.cpp +++ b/src/caffe/layers/hdf5_data_layer.cpp @@ -31,13 +31,13 @@ void HDF5DataLayer::LoadHDF5FileData(const char* filename) { LOG(FATAL) << "Failed opening HDF5 file: " << filename; } - int top_size = this->layer_param_.top_size(); + int_tp top_size = this->layer_param_.top_size(); hdf_blobs_.resize(top_size); - const int MIN_DATA_DIM = 1; - const int MAX_DATA_DIM = INT_MAX; + const int_tp MIN_DATA_DIM = 1; + const int_tp MAX_DATA_DIM = INT_MAX; - for (int i = 0; i < top_size; ++i) { + for (int_tp i = 0; i < top_size; ++i) { hdf_blobs_[i] = shared_ptr >(new Blob()); hdf5_load_nd_dataset(file_id, this->layer_param_.top(i).c_str(), MIN_DATA_DIM, MAX_DATA_DIM, hdf_blobs_[i].get()); @@ -48,14 +48,14 @@ void HDF5DataLayer::LoadHDF5FileData(const char* filename) { // MinTopBlobs==1 guarantees at least one top blob CHECK_GE(hdf_blobs_[0]->num_axes(), 1) << "Input must have at least 1 axis."; - const int num = hdf_blobs_[0]->shape(0); - for (int i = 1; i < top_size; ++i) { + const int_tp num = hdf_blobs_[0]->shape(0); + for (int_tp i = 1; i < top_size; ++i) { CHECK_EQ(hdf_blobs_[i]->shape(0), num); } // Default to identity permutation. data_permutation_.clear(); data_permutation_.resize(hdf_blobs_[0]->shape(0)); - for (int i = 0; i < hdf_blobs_[0]->shape(0); i++) + for (int_tp i = 0; i < hdf_blobs_[0]->shape(0); i++) data_permutation_[i] = i; // Shuffle if needed. @@ -97,7 +97,7 @@ void HDF5DataLayer::LayerSetUp(const vector*>& bottom, file_permutation_.clear(); file_permutation_.resize(num_files_); // Default to identity permutation. - for (int i = 0; i < num_files_; i++) { + for (int_tp i = 0; i < num_files_; i++) { file_permutation_[i] = i; } @@ -111,13 +111,13 @@ void HDF5DataLayer::LayerSetUp(const vector*>& bottom, current_row_ = 0; // Reshape blobs. - const int batch_size = this->layer_param_.hdf5_data_param().batch_size(); - const int top_size = this->layer_param_.top_size(); - vector top_shape; - for (int i = 0; i < top_size; ++i) { + const int_tp batch_size = this->layer_param_.hdf5_data_param().batch_size(); + const int_tp top_size = this->layer_param_.top_size(); + vector top_shape; + for (int_tp i = 0; i < top_size; ++i) { top_shape.resize(hdf_blobs_[i]->num_axes()); top_shape[0] = batch_size; - for (int j = 1; j < top_shape.size(); ++j) { + for (int_tp j = 1; j < top_shape.size(); ++j) { top_shape[j] = hdf_blobs_[i]->shape(j); } top[i]->Reshape(top_shape); @@ -127,8 +127,8 @@ void HDF5DataLayer::LayerSetUp(const vector*>& bottom, template void HDF5DataLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { - const int batch_size = this->layer_param_.hdf5_data_param().batch_size(); - for (int i = 0; i < batch_size; ++i, ++current_row_) { + const int_tp batch_size = this->layer_param_.hdf5_data_param().batch_size(); + for (int_tp i = 0; i < batch_size; ++i, ++current_row_) { if (current_row_ == hdf_blobs_[0]->shape(0)) { if (num_files_ > 1) { ++current_file_; @@ -147,9 +147,9 @@ void HDF5DataLayer::Forward_cpu(const vector*>& bottom, if (this->layer_param_.hdf5_data_param().shuffle()) std::random_shuffle(data_permutation_.begin(), data_permutation_.end()); } - for (int j = 0; j < this->layer_param_.top_size(); ++j) { - int data_dim = top[j]->count() / top[j]->shape(0); - caffe_copy(data_dim, + for (int_tp j = 0; j < this->layer_param_.top_size(); ++j) { + int_tp data_dim = top[j]->count() / top[j]->shape(0); + caffe_cpu_copy(data_dim, &hdf_blobs_[j]->cpu_data()[data_permutation_[current_row_] * data_dim], &top[j]->mutable_cpu_data()[i * data_dim]); } diff --git a/src/caffe/layers/hdf5_data_layer.cu b/src/caffe/layers/hdf5_data_layer.cu index 595d2230220..64f31b49698 100644 --- a/src/caffe/layers/hdf5_data_layer.cu +++ b/src/caffe/layers/hdf5_data_layer.cu @@ -1,7 +1,7 @@ /* -TODO: -- only load parts of the file, in accordance with a prototxt param "max_mem" -*/ + TODO: + - only load parts of the file, in accordance with a prototxt param "max_mem" + */ #include #include @@ -13,35 +13,46 @@ TODO: namespace caffe { -template +template void HDF5DataLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - const int batch_size = this->layer_param_.hdf5_data_param().batch_size(); - for (int i = 0; i < batch_size; ++i, ++current_row_) { - if (current_row_ == hdf_blobs_[0]->shape(0)) { - if (num_files_ > 1) { - current_file_ += 1; - if (current_file_ == num_files_) { - current_file_ = 0; - if (this->layer_param_.hdf5_data_param().shuffle()) { - std::random_shuffle(file_permutation_.begin(), - file_permutation_.end()); + const vector*>& top) { + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + const int_tp batch_size = this->layer_param_.hdf5_data_param().batch_size(); + for (int_tp i = 0; i < batch_size; ++i, ++current_row_) { + if (current_row_ == hdf_blobs_[0]->shape(0)) { + if (num_files_ > 1) { + current_file_ += 1; + if (current_file_ == num_files_) { + current_file_ = 0; + if (this->layer_param_.hdf5_data_param().shuffle()) { + std::random_shuffle(file_permutation_.begin(), + file_permutation_.end()); + } + DLOG(INFO)<< "Looping around to first file."; } - DLOG(INFO) << "Looping around to first file."; + LoadHDF5FileData( + hdf_filenames_[file_permutation_[current_file_]].c_str()); } - LoadHDF5FileData( - hdf_filenames_[file_permutation_[current_file_]].c_str()); + current_row_ = 0; + if (this->layer_param_.hdf5_data_param().shuffle()) + std::random_shuffle(data_permutation_.begin(), + data_permutation_.end()); + } + for (int_tp j = 0; j < this->layer_param_.top_size(); ++j) { + int_tp data_dim = top[j]->count() / top[j]->shape(0); + caffe_copy( + data_dim, + &hdf_blobs_[j]->cpu_data()[data_permutation_[current_row_] + * data_dim], + &top[j]->mutable_gpu_data()[i * data_dim]); } - current_row_ = 0; - if (this->layer_param_.hdf5_data_param().shuffle()) - std::random_shuffle(data_permutation_.begin(), data_permutation_.end()); - } - for (int j = 0; j < this->layer_param_.top_size(); ++j) { - int data_dim = top[j]->count() / top[j]->shape(0); - caffe_copy(data_dim, - &hdf_blobs_[j]->cpu_data()[data_permutation_[current_row_] - * data_dim], &top[j]->mutable_gpu_data()[i * data_dim]); } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + Forward_cpu(bottom, top); +#endif // USE_GREENTEA } } diff --git a/src/caffe/layers/hdf5_output_layer.cpp b/src/caffe/layers/hdf5_output_layer.cpp index f8f1edcd18e..78994a6b12e 100644 --- a/src/caffe/layers/hdf5_output_layer.cpp +++ b/src/caffe/layers/hdf5_output_layer.cpp @@ -46,13 +46,13 @@ void HDF5OutputLayer::Forward_cpu(const vector*>& bottom, bottom[0]->height(), bottom[0]->width()); label_blob_.Reshape(bottom[1]->num(), bottom[1]->channels(), bottom[1]->height(), bottom[1]->width()); - const int data_datum_dim = bottom[0]->count() / bottom[0]->num(); - const int label_datum_dim = bottom[1]->count() / bottom[1]->num(); + const int_tp data_datum_dim = bottom[0]->count() / bottom[0]->num(); + const int_tp label_datum_dim = bottom[1]->count() / bottom[1]->num(); - for (int i = 0; i < bottom[0]->num(); ++i) { - caffe_copy(data_datum_dim, &bottom[0]->cpu_data()[i * data_datum_dim], + for (int_tp i = 0; i < bottom[0]->num(); ++i) { + caffe_cpu_copy(data_datum_dim, &bottom[0]->cpu_data()[i * data_datum_dim], &data_blob_.mutable_cpu_data()[i * data_datum_dim]); - caffe_copy(label_datum_dim, &bottom[1]->cpu_data()[i * label_datum_dim], + caffe_cpu_copy(label_datum_dim, &bottom[1]->cpu_data()[i * label_datum_dim], &label_blob_.mutable_cpu_data()[i * label_datum_dim]); } SaveBlobs(); diff --git a/src/caffe/layers/hdf5_output_layer.cu b/src/caffe/layers/hdf5_output_layer.cu index c1685cd34a7..d67b7bb2cf7 100644 --- a/src/caffe/layers/hdf5_output_layer.cu +++ b/src/caffe/layers/hdf5_output_layer.cu @@ -7,30 +7,39 @@ namespace caffe { -template +template void HDF5OutputLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - CHECK_GE(bottom.size(), 2); - CHECK_EQ(bottom[0]->num(), bottom[1]->num()); - data_blob_.Reshape(bottom[0]->num(), bottom[0]->channels(), - bottom[0]->height(), bottom[0]->width()); - label_blob_.Reshape(bottom[1]->num(), bottom[1]->channels(), - bottom[1]->height(), bottom[1]->width()); - const int data_datum_dim = bottom[0]->count() / bottom[0]->num(); - const int label_datum_dim = bottom[1]->count() / bottom[1]->num(); - - for (int i = 0; i < bottom[0]->num(); ++i) { - caffe_copy(data_datum_dim, &bottom[0]->gpu_data()[i * data_datum_dim], - &data_blob_.mutable_cpu_data()[i * data_datum_dim]); - caffe_copy(label_datum_dim, &bottom[1]->gpu_data()[i * label_datum_dim], - &label_blob_.mutable_cpu_data()[i * label_datum_dim]); + const vector*>& top) { + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + CHECK_GE(bottom.size(), 2); + CHECK_EQ(bottom[0]->num(), bottom[1]->num()); + data_blob_.Reshape(bottom[0]->num(), bottom[0]->channels(), + bottom[0]->height(), bottom[0]->width()); + label_blob_.Reshape(bottom[1]->num(), bottom[1]->channels(), + bottom[1]->height(), bottom[1]->width()); + const int_tp data_datum_dim = bottom[0]->count() / bottom[0]->num(); + const int_tp label_datum_dim = bottom[1]->count() / bottom[1]->num(); + + for (int_tp i = 0; i < bottom[0]->num(); ++i) { + caffe_copy(data_datum_dim, &bottom[0]->gpu_data()[i * data_datum_dim], + &data_blob_.mutable_cpu_data()[i * data_datum_dim]); + caffe_copy(label_datum_dim, &bottom[1]->gpu_data()[i * label_datum_dim], + &label_blob_.mutable_cpu_data()[i * label_datum_dim]); + } + SaveBlobs(); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + Forward_cpu(bottom, top); +#endif // USE_GREENTEA } - SaveBlobs(); } -template +template void HDF5OutputLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { return; } diff --git a/src/caffe/layers/hinge_loss_layer.cpp b/src/caffe/layers/hinge_loss_layer.cpp index 374aed3c98f..3aeb35afb99 100644 --- a/src/caffe/layers/hinge_loss_layer.cpp +++ b/src/caffe/layers/hinge_loss_layer.cpp @@ -12,16 +12,16 @@ void HingeLossLayer::Forward_cpu(const vector*>& bottom, const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); const Dtype* label = bottom[1]->cpu_data(); - int num = bottom[0]->num(); - int count = bottom[0]->count(); - int dim = count / num; + int_tp num = bottom[0]->num(); + int_tp count = bottom[0]->count(); + int_tp dim = count / num; - caffe_copy(count, bottom_data, bottom_diff); - for (int i = 0; i < num; ++i) { - bottom_diff[i * dim + static_cast(label[i])] *= -1; + caffe_cpu_copy(count, bottom_data, bottom_diff); + for (int_tp i = 0; i < num; ++i) { + bottom_diff[i * dim + static_cast(label[i])] *= -1; } - for (int i = 0; i < num; ++i) { - for (int j = 0; j < dim; ++j) { + for (int_tp i = 0; i < num; ++i) { + for (int_tp j = 0; j < dim; ++j) { bottom_diff[i * dim + j] = std::max( Dtype(0), 1 + bottom_diff[i * dim + j]); } @@ -49,12 +49,12 @@ void HingeLossLayer::Backward_cpu(const vector*>& top, if (propagate_down[0]) { Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); const Dtype* label = bottom[1]->cpu_data(); - int num = bottom[0]->num(); - int count = bottom[0]->count(); - int dim = count / num; + int_tp num = bottom[0]->num(); + int_tp count = bottom[0]->count(); + int_tp dim = count / num; - for (int i = 0; i < num; ++i) { - bottom_diff[i * dim + static_cast(label[i])] *= -1; + for (int_tp i = 0; i < num; ++i) { + bottom_diff[i * dim + static_cast(label[i])] *= -1; } const Dtype loss_weight = top[0]->cpu_diff()[0]; diff --git a/src/caffe/layers/im2col_layer.cpp b/src/caffe/layers/im2col_layer.cpp index 2fb9b3c1099..a80313b7342 100644 --- a/src/caffe/layers/im2col_layer.cpp +++ b/src/caffe/layers/im2col_layer.cpp @@ -10,15 +10,15 @@ void Im2colLayer::LayerSetUp(const vector*>& bottom, const vector*>& top) { ConvolutionParameter conv_param = this->layer_param_.convolution_param(); force_nd_im2col_ = conv_param.force_nd_im2col(); - const int input_num_dims = bottom[0]->shape().size(); + const int_tp input_num_dims = bottom[0]->shape().size(); channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis()); - const int first_spatial_dim = channel_axis_ + 1; + const int_tp first_spatial_dim = channel_axis_ + 1; num_spatial_axes_ = input_num_dims - first_spatial_dim; CHECK_GE(num_spatial_axes_, 1); - vector dim_blob_shape(1, num_spatial_axes_); + vector dim_blob_shape(1, num_spatial_axes_); // Setup filter kernel dimensions (kernel_shape_). kernel_shape_.Reshape(dim_blob_shape); - int* kernel_shape_data = kernel_shape_.mutable_cpu_data(); + int_tp* kernel_shape_data = kernel_shape_.mutable_cpu_data(); if (conv_param.has_kernel_h() || conv_param.has_kernel_w()) { CHECK_EQ(num_spatial_axes_, 2) << "kernel_h & kernel_w can only be used for 2D convolution."; @@ -27,22 +27,22 @@ void Im2colLayer::LayerSetUp(const vector*>& bottom, kernel_shape_data[0] = conv_param.kernel_h(); kernel_shape_data[1] = conv_param.kernel_w(); } else { - const int num_kernel_dims = conv_param.kernel_size_size(); + const int_tp num_kernel_dims = conv_param.kernel_size_size(); CHECK(num_kernel_dims == 1 || num_kernel_dims == num_spatial_axes_) << "kernel_size must be specified once, or once per spatial dimension " << "(kernel_size specified " << num_kernel_dims << " times; " << num_spatial_axes_ << " spatial dims);"; - for (int i = 0; i < num_spatial_axes_; ++i) { + for (int_tp i = 0; i < num_spatial_axes_; ++i) { kernel_shape_data[i] = conv_param.kernel_size((num_kernel_dims == 1) ? 0 : i); } } - for (int i = 0; i < num_spatial_axes_; ++i) { + for (int_tp i = 0; i < num_spatial_axes_; ++i) { CHECK_GT(kernel_shape_data[i], 0) << "Filter dimensions must be nonzero."; } // Setup stride dimensions (stride_). stride_.Reshape(dim_blob_shape); - int* stride_data = stride_.mutable_cpu_data(); + int_tp* stride_data = stride_.mutable_cpu_data(); if (conv_param.has_stride_h() || conv_param.has_stride_w()) { CHECK_EQ(num_spatial_axes_, 2) << "stride_h & stride_w can only be used for 2D convolution."; @@ -51,14 +51,14 @@ void Im2colLayer::LayerSetUp(const vector*>& bottom, stride_data[0] = conv_param.stride_h(); stride_data[1] = conv_param.stride_w(); } else { - const int num_stride_dims = conv_param.stride_size(); + const int_tp num_stride_dims = conv_param.stride_size(); CHECK(num_stride_dims == 0 || num_stride_dims == 1 || num_stride_dims == num_spatial_axes_) << "stride must be specified once, or once per spatial dimension " << "(stride specified " << num_stride_dims << " times; " << num_spatial_axes_ << " spatial dims);"; - const int kDefaultStride = 1; - for (int i = 0; i < num_spatial_axes_; ++i) { + const int_tp kDefaultStride = 1; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { stride_data[i] = (num_stride_dims == 0) ? kDefaultStride : conv_param.stride((num_stride_dims == 1) ? 0 : i); CHECK_GT(stride_data[i], 0) << "Stride dimensions must be nonzero."; @@ -66,7 +66,7 @@ void Im2colLayer::LayerSetUp(const vector*>& bottom, } // Setup pad dimensions (pad_). pad_.Reshape(dim_blob_shape); - int* pad_data = pad_.mutable_cpu_data(); + int_tp* pad_data = pad_.mutable_cpu_data(); if (conv_param.has_pad_h() || conv_param.has_pad_w()) { CHECK_EQ(num_spatial_axes_, 2) << "pad_h & pad_w can only be used for 2D convolution."; @@ -75,29 +75,29 @@ void Im2colLayer::LayerSetUp(const vector*>& bottom, pad_data[0] = conv_param.pad_h(); pad_data[1] = conv_param.pad_w(); } else { - const int num_pad_dims = conv_param.pad_size(); + const int_tp num_pad_dims = conv_param.pad_size(); CHECK(num_pad_dims == 0 || num_pad_dims == 1 || num_pad_dims == num_spatial_axes_) << "pad must be specified once, or once per spatial dimension " << "(pad specified " << num_pad_dims << " times; " << num_spatial_axes_ << " spatial dims);"; - const int kDefaultPad = 0; - for (int i = 0; i < num_spatial_axes_; ++i) { + const int_tp kDefaultPad = 0; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { pad_data[i] = (num_pad_dims == 0) ? kDefaultPad : conv_param.pad((num_pad_dims == 1) ? 0 : i); } } // Setup dilation dimensions (dilation_). dilation_.Reshape(dim_blob_shape); - int* dilation_data = dilation_.mutable_cpu_data(); - const int num_dilation_dims = conv_param.dilation_size(); + int_tp* dilation_data = dilation_.mutable_cpu_data(); + const int_tp num_dilation_dims = conv_param.dilation_size(); CHECK(num_dilation_dims == 0 || num_dilation_dims == 1 || num_dilation_dims == num_spatial_axes_) << "dilation must be specified once, or once per spatial dimension " << "(dilation specified " << num_dilation_dims << " times; " << num_spatial_axes_ << " spatial dims)."; - const int kDefaultDilation = 1; - for (int i = 0; i < num_spatial_axes_; ++i) { + const int_tp kDefaultDilation = 1; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { dilation_data[i] = (num_dilation_dims == 0) ? kDefaultDilation : conv_param.dilation((num_dilation_dims == 1) ? 0 : i); } @@ -106,16 +106,17 @@ void Im2colLayer::LayerSetUp(const vector*>& bottom, template void Im2colLayer::Reshape(const vector*>& bottom, const vector*>& top) { - vector top_shape = bottom[0]->shape(); - const int* kernel_shape_data = kernel_shape_.cpu_data(); - const int* stride_data = stride_.cpu_data(); - const int* pad_data = pad_.cpu_data(); - const int* dilation_data = dilation_.cpu_data(); - for (int i = 0; i < num_spatial_axes_; ++i) { + vector top_shape = bottom[0]->shape(); + const int_tp* kernel_shape_data = kernel_shape_.cpu_data(); + const int_tp* stride_data = stride_.cpu_data(); + const int_tp* pad_data = pad_.cpu_data(); + const int_tp* dilation_data = dilation_.cpu_data(); + for (int_tp i = 0; i < num_spatial_axes_; ++i) { top_shape[channel_axis_] *= kernel_shape_data[i]; - const int input_dim = bottom[0]->shape(channel_axis_ + i + 1); - const int kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + 1; - const int output_dim = (input_dim + 2 * pad_data[i] - kernel_extent) + const int_tp input_dim = bottom[0]->shape(channel_axis_ + i + 1); + const int_tp kernel_extent = dilation_data[i] * (kernel_shape_data[i] - 1) + + 1; + const int_tp output_dim = (input_dim + 2 * pad_data[i] - kernel_extent) / stride_data[i] + 1; top_shape[channel_axis_ + i + 1] = output_dim; } @@ -132,7 +133,7 @@ void Im2colLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - for (int n = 0; n < num_; ++n) { + for (int_tp n = 0; n < num_; ++n) { DCHECK_EQ(bottom[0]->shape().size() - channel_axis_, num_spatial_axes_ + 1); DCHECK_EQ(top[0]->shape().size() - channel_axis_, num_spatial_axes_ + 1); DCHECK_EQ(kernel_shape_.count(), num_spatial_axes_); @@ -163,7 +164,7 @@ void Im2colLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - for (int n = 0; n < num_; ++n) { + for (int_tp n = 0; n < num_; ++n) { if (!force_nd_im2col_ && num_spatial_axes_ == 2) { col2im_cpu(top_diff + n * top_dim_, channels_, bottom[0]->shape(channel_axis_ + 1), diff --git a/src/caffe/layers/im2col_layer.cu b/src/caffe/layers/im2col_layer.cu index 792c97f70f9..a07ebb4d33b 100644 --- a/src/caffe/layers/im2col_layer.cu +++ b/src/caffe/layers/im2col_layer.cu @@ -3,60 +3,143 @@ #include "caffe/layers/im2col_layer.hpp" #include "caffe/util/im2col.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void Im2colLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int num_kernels = channels_ * top[0]->count(channel_axis_ + 1); - for (int n = 0; n < num_; ++n) { - if (!force_nd_im2col_ && num_spatial_axes_ == 2) { - im2col_gpu(bottom_data + n * bottom_dim_, channels_, - bottom[0]->shape(channel_axis_ + 1), - bottom[0]->shape(channel_axis_ + 2), - kernel_shape_.cpu_data()[0], kernel_shape_.cpu_data()[1], - pad_.cpu_data()[0], pad_.cpu_data()[1], - stride_.cpu_data()[0], stride_.cpu_data()[1], - dilation_.cpu_data()[0], dilation_.cpu_data()[1], - top_data + n * top_dim_); - } else { - im2col_nd_gpu(bottom_data + n * bottom_dim_, num_spatial_axes_, - num_kernels, bottom[0]->gpu_shape() + channel_axis_, - top[0]->gpu_shape() + channel_axis_, - kernel_shape_.gpu_data(), pad_.gpu_data(), stride_.gpu_data(), - dilation_.gpu_data(), top_data + n * top_dim_); + const int_tp num_kernels = channels_ * top[0]->count(channel_axis_ + 1); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int_tp n = 0; n < num_; ++n) { + if (!force_nd_im2col_ && num_spatial_axes_ == 2) { + im2col_gpu(bottom_data + n * bottom_dim_, channels_, + bottom[0]->shape(channel_axis_ + 1), + bottom[0]->shape(channel_axis_ + 2), + kernel_shape_.cpu_data()[0], kernel_shape_.cpu_data()[1], + pad_.cpu_data()[0], pad_.cpu_data()[1], + stride_.cpu_data()[0], stride_.cpu_data()[1], + dilation_.cpu_data()[0], dilation_.cpu_data()[1], + top_data + n * top_dim_); + } else { + im2col_nd_gpu(bottom_data + n * bottom_dim_, num_spatial_axes_, + num_kernels, bottom[0]->gpu_shape() + channel_axis_, + top[0]->gpu_shape() + channel_axis_, + kernel_shape_.gpu_data(), pad_.gpu_data(), stride_.gpu_data(), + dilation_.gpu_data(), top_data + n * top_dim_); + } + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + for (int_tp n = 0; n < num_; ++n) { + if (!force_nd_im2col_ && num_spatial_axes_ == 2) { + greentea_im2col_gpu(&program, &ctx, (cl_mem) bottom_data, + n * bottom_dim_, channels_, + bottom[0]->shape(channel_axis_ + 1), + bottom[0]->shape(channel_axis_ + 2), + kernel_shape_.cpu_data()[0], + kernel_shape_.cpu_data()[1], + pad_.cpu_data()[0], pad_.cpu_data()[1], + stride_.cpu_data()[0], stride_.cpu_data()[1], + dilation_.cpu_data()[0], + dilation_.cpu_data()[1], (cl_mem) top_data, + n * top_dim_); + } else { + greentea_im2col_nd_gpu(&program, &ctx, (cl_mem) bottom_data, + n * bottom_dim_, num_spatial_axes_, + channel_axis_, num_kernels, + (cl_mem) (bottom[0]->gpu_shape()), + (cl_mem) (top[0]->gpu_shape()), + (cl_mem) (kernel_shape_.gpu_data()), + (cl_mem) (pad_.gpu_data()), + (cl_mem) (stride_.gpu_data()), + (cl_mem) (dilation_.gpu_data()), + (cl_mem) top_data, n * top_dim_); + } } +#endif // USE_GREENTEA } } -template +template void Im2colLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - for (int n = 0; n < num_; ++n) { - if (!force_nd_im2col_ && num_spatial_axes_ == 2) { - col2im_gpu(top_diff + n * top_dim_, channels_, - bottom[0]->shape(channel_axis_ + 1), - bottom[0]->shape(channel_axis_ + 2), - kernel_shape_.cpu_data()[0], kernel_shape_.cpu_data()[1], - pad_.cpu_data()[0], pad_.cpu_data()[1], - stride_.cpu_data()[0], stride_.cpu_data()[1], - dilation_.cpu_data()[0], dilation_.cpu_data()[1], - bottom_diff + n * bottom_dim_); - } else { - col2im_nd_gpu(top_diff + n * top_dim_, num_spatial_axes_, bottom_dim_, - bottom[0]->gpu_shape() + channel_axis_, - top[0]->gpu_shape() + channel_axis_, - kernel_shape_.gpu_data(), pad_.gpu_data(), stride_.gpu_data(), - dilation_.gpu_data(), bottom_diff + n * bottom_dim_); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int n = 0; n < num_; ++n) { + if (!force_nd_im2col_ && num_spatial_axes_ == 2) { + col2im_gpu(top_diff + n * top_dim_, channels_, + bottom[0]->shape(channel_axis_ + 1), + bottom[0]->shape(channel_axis_ + 2), + kernel_shape_.cpu_data()[0], kernel_shape_.cpu_data()[1], + pad_.cpu_data()[0], pad_.cpu_data()[1], + stride_.cpu_data()[0], stride_.cpu_data()[1], + dilation_.cpu_data()[0], dilation_.cpu_data()[1], + bottom_diff + n * bottom_dim_); + } else { + col2im_nd_gpu(top_diff + n * top_dim_, num_spatial_axes_, bottom_dim_, + bottom[0]->gpu_shape() + channel_axis_, + top[0]->gpu_shape() + channel_axis_, + kernel_shape_.gpu_data(), pad_.gpu_data(), + stride_.gpu_data(), dilation_.gpu_data(), + bottom_diff + n * bottom_dim_); + } + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + for (int_tp n = 0; n < top[0]->num(); ++n) { + if (!force_nd_im2col_ && num_spatial_axes_ == 2) { + greentea_col2im_gpu(&program, &ctx, (cl_mem) top_diff, + n * top_dim_, channels_, + bottom[0]->shape(channel_axis_ + 1), + bottom[0]->shape(channel_axis_ + 2), + kernel_shape_.cpu_data()[0], + kernel_shape_.cpu_data()[1], + pad_.cpu_data()[0], pad_.cpu_data()[1], + stride_.cpu_data()[0], stride_.cpu_data()[1], + dilation_.cpu_data()[0], + dilation_.cpu_data()[1], + (cl_mem) bottom_diff, n * bottom_dim_); + } else { + greentea_col2im_nd_gpu(&program, &ctx, (cl_mem) top_diff, + n * top_dim_, num_spatial_axes_, + channel_axis_, bottom_dim_, + (cl_mem) (bottom[0]->gpu_shape()), + (cl_mem) (top[0]->gpu_shape()), + (cl_mem) (kernel_shape_.gpu_data()), + (cl_mem) (pad_.gpu_data()), + (cl_mem) (stride_.gpu_data()), + (cl_mem) (dilation_.gpu_data()), + (cl_mem) bottom_diff, n * bottom_dim_); + } } +#endif // USE_GREENTEA } } - INSTANTIATE_LAYER_GPU_FUNCS(Im2colLayer); } // namespace caffe diff --git a/src/caffe/layers/image_data_layer.cpp b/src/caffe/layers/image_data_layer.cpp index 62fda4accce..44c4c6be9dc 100644 --- a/src/caffe/layers/image_data_layer.cpp +++ b/src/caffe/layers/image_data_layer.cpp @@ -25,8 +25,8 @@ ImageDataLayer::~ImageDataLayer() { template void ImageDataLayer::DataLayerSetUp(const vector*>& bottom, const vector*>& top) { - const int new_height = this->layer_param_.image_data_param().new_height(); - const int new_width = this->layer_param_.image_data_param().new_width(); + const int_tp new_height = this->layer_param_.image_data_param().new_height(); + const int_tp new_width = this->layer_param_.image_data_param().new_width(); const bool is_color = this->layer_param_.image_data_param().is_color(); string root_folder = this->layer_param_.image_data_param().root_folder(); @@ -38,7 +38,7 @@ void ImageDataLayer::DataLayerSetUp(const vector*>& bottom, LOG(INFO) << "Opening file " << source; std::ifstream infile(source.c_str()); string filename; - int label; + int_tp label; while (infile >> filename >> label) { lines_.push_back(std::make_pair(filename, label)); } @@ -46,7 +46,7 @@ void ImageDataLayer::DataLayerSetUp(const vector*>& bottom, if (this->layer_param_.image_data_param().shuffle()) { // randomly shuffle data LOG(INFO) << "Shuffling data"; - const unsigned int prefetch_rng_seed = caffe_rng_rand(); + const uint_tp prefetch_rng_seed = caffe_rng_rand(); prefetch_rng_.reset(new Caffe::RNG(prefetch_rng_seed)); ShuffleImages(); } @@ -55,7 +55,7 @@ void ImageDataLayer::DataLayerSetUp(const vector*>& bottom, lines_id_ = 0; // Check if we would need to randomly skip a few data points if (this->layer_param_.image_data_param().rand_skip()) { - unsigned int skip = caffe_rng_rand() % + uint_tp skip = caffe_rng_rand() % this->layer_param_.image_data_param().rand_skip(); LOG(INFO) << "Skipping first " << skip << " data points."; CHECK_GT(lines_.size(), skip) << "Not enough points to skip"; @@ -66,13 +66,13 @@ void ImageDataLayer::DataLayerSetUp(const vector*>& bottom, new_height, new_width, is_color); CHECK(cv_img.data) << "Could not load " << lines_[lines_id_].first; // Use data_transformer to infer the expected blob shape from a cv_image. - vector top_shape = this->data_transformer_->InferBlobShape(cv_img); + vector top_shape = this->data_transformer_->InferBlobShape(cv_img); this->transformed_data_.Reshape(top_shape); // Reshape prefetch_data and top[0] according to the batch_size. - const int batch_size = this->layer_param_.image_data_param().batch_size(); + const int_tp batch_size = this->layer_param_.image_data_param().batch_size(); CHECK_GT(batch_size, 0) << "Positive batch size required"; top_shape[0] = batch_size; - for (int i = 0; i < this->PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < this->PREFETCH_COUNT; ++i) { this->prefetch_[i].data_.Reshape(top_shape); } top[0]->Reshape(top_shape); @@ -81,9 +81,9 @@ void ImageDataLayer::DataLayerSetUp(const vector*>& bottom, << top[0]->channels() << "," << top[0]->height() << "," << top[0]->width(); // label - vector label_shape(1, batch_size); + vector label_shape(1, batch_size); top[1]->Reshape(label_shape); - for (int i = 0; i < this->PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < this->PREFETCH_COUNT; ++i) { this->prefetch_[i].label_.Reshape(label_shape); } } @@ -106,9 +106,9 @@ void ImageDataLayer::load_batch(Batch* batch) { CHECK(batch->data_.count()); CHECK(this->transformed_data_.count()); ImageDataParameter image_data_param = this->layer_param_.image_data_param(); - const int batch_size = image_data_param.batch_size(); - const int new_height = image_data_param.new_height(); - const int new_width = image_data_param.new_width(); + const int_tp batch_size = image_data_param.batch_size(); + const int_tp new_height = image_data_param.new_height(); + const int_tp new_width = image_data_param.new_width(); const bool is_color = image_data_param.is_color(); string root_folder = image_data_param.root_folder(); @@ -118,7 +118,7 @@ void ImageDataLayer::load_batch(Batch* batch) { new_height, new_width, is_color); CHECK(cv_img.data) << "Could not load " << lines_[lines_id_].first; // Use data_transformer to infer the expected blob shape from a cv_img. - vector top_shape = this->data_transformer_->InferBlobShape(cv_img); + vector top_shape = this->data_transformer_->InferBlobShape(cv_img); this->transformed_data_.Reshape(top_shape); // Reshape batch according to the batch_size. top_shape[0] = batch_size; @@ -128,8 +128,8 @@ void ImageDataLayer::load_batch(Batch* batch) { Dtype* prefetch_label = batch->label_.mutable_cpu_data(); // datum scales - const int lines_size = lines_.size(); - for (int item_id = 0; item_id < batch_size; ++item_id) { + const int_tp lines_size = lines_.size(); + for (int_tp item_id = 0; item_id < batch_size; ++item_id) { // get a blob timer.Start(); CHECK_GT(lines_size, lines_id_); @@ -139,7 +139,7 @@ void ImageDataLayer::load_batch(Batch* batch) { read_time += timer.MicroSeconds(); timer.Start(); // Apply transformations (mirror, crop...) to the image - int offset = batch->data_.offset(item_id); + int_tp offset = batch->data_.offset(item_id); this->transformed_data_.set_cpu_data(prefetch_data + offset); this->data_transformer_->Transform(cv_img, &(this->transformed_data_)); trans_time += timer.MicroSeconds(); diff --git a/src/caffe/layers/infogain_loss_layer.cpp b/src/caffe/layers/infogain_loss_layer.cpp index 624d3118124..26dc398dd26 100644 --- a/src/caffe/layers/infogain_loss_layer.cpp +++ b/src/caffe/layers/infogain_loss_layer.cpp @@ -34,8 +34,8 @@ void InfogainLossLayer::Reshape( CHECK_EQ(bottom[1]->channels(), 1); CHECK_EQ(bottom[1]->height(), 1); CHECK_EQ(bottom[1]->width(), 1); - const int num = bottom[0]->num(); - const int dim = bottom[0]->count() / num; + const int_tp num = bottom[0]->num(); + const int_tp dim = bottom[0]->count() / num; CHECK_EQ(infogain->num(), 1); CHECK_EQ(infogain->channels(), 1); CHECK_EQ(infogain->height(), dim); @@ -54,12 +54,12 @@ void InfogainLossLayer::Forward_cpu(const vector*>& bottom, } else { infogain_mat = bottom[2]->cpu_data(); } - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); + int_tp num = bottom[0]->num(); + int_tp dim = bottom[0]->count() / bottom[0]->num(); Dtype loss = 0; - for (int i = 0; i < num; ++i) { - int label = static_cast(bottom_label[i]); - for (int j = 0; j < dim; ++j) { + for (int_tp i = 0; i < num; ++i) { + int_tp label = static_cast(bottom_label[i]); + for (int_tp j = 0; j < dim; ++j) { Dtype prob = std::max(bottom_data[i * dim + j], Dtype(kLOG_THRESHOLD)); loss -= infogain_mat[label * dim + j] * log(prob); } @@ -89,12 +89,12 @@ void InfogainLossLayer::Backward_cpu(const vector*>& top, infogain_mat = bottom[2]->cpu_data(); } Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); + int_tp num = bottom[0]->num(); + int_tp dim = bottom[0]->count() / bottom[0]->num(); const Dtype scale = - top[0]->cpu_diff()[0] / num; - for (int i = 0; i < num; ++i) { - const int label = static_cast(bottom_label[i]); - for (int j = 0; j < dim; ++j) { + for (int_tp i = 0; i < num; ++i) { + const int_tp label = static_cast(bottom_label[i]); + for (int_tp j = 0; j < dim; ++j) { Dtype prob = std::max(bottom_data[i * dim + j], Dtype(kLOG_THRESHOLD)); bottom_diff[i * dim + j] = scale * infogain_mat[label * dim + j] / prob; } diff --git a/src/caffe/layers/inner_product_layer.cpp b/src/caffe/layers/inner_product_layer.cpp index d9088805501..41059034a5a 100644 --- a/src/caffe/layers/inner_product_layer.cpp +++ b/src/caffe/layers/inner_product_layer.cpp @@ -6,13 +6,14 @@ namespace caffe { -template +template void InnerProductLayer::LayerSetUp(const vector*>& bottom, - const vector*>& top) { - const int num_output = this->layer_param_.inner_product_param().num_output(); + const vector*>& top) { + const int_tp num_output = + this->layer_param_.inner_product_param().num_output(); bias_term_ = this->layer_param_.inner_product_param().bias_term(); N_ = num_output; - const int axis = bottom[0]->CanonicalAxisIndex( + const int_tp axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), @@ -20,7 +21,7 @@ void InnerProductLayer::LayerSetUp(const vector*>& bottom, K_ = bottom[0]->count(axis); // Check if we need to set up the weights if (this->blobs_.size() > 0) { - LOG(INFO) << "Skipping parameter initialization"; + LOG(INFO)<< "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); @@ -28,33 +29,34 @@ void InnerProductLayer::LayerSetUp(const vector*>& bottom, this->blobs_.resize(1); } // Intialize the weight - vector weight_shape(2); + vector weight_shape(2); weight_shape[0] = N_; weight_shape[1] = K_; - this->blobs_[0].reset(new Blob(weight_shape)); + this->blobs_[0].reset(new Blob(weight_shape, + this->device_)); // fill the weights shared_ptr > weight_filler(GetFiller( - this->layer_param_.inner_product_param().weight_filler())); + this->layer_param_.inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, intiialize and fill the bias term if (bias_term_) { - vector bias_shape(1, N_); - this->blobs_[1].reset(new Blob(bias_shape)); + vector bias_shape(1, N_); + this->blobs_[1].reset(new Blob(bias_shape, this->device_)); shared_ptr > bias_filler(GetFiller( - this->layer_param_.inner_product_param().bias_filler())); + this->layer_param_.inner_product_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // parameter initialization this->param_propagate_down_.resize(this->blobs_.size(), true); } -template +template void InnerProductLayer::Reshape(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { // Figure out the dimensions - const int axis = bottom[0]->CanonicalAxisIndex( + const int_tp axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); - const int new_K = bottom[0]->count(axis); + const int_tp new_K = bottom[0]->count(axis); CHECK_EQ(K_, new_K) << "Input size incompatible with inner product parameters."; // The first "axis" dimensions are independent inner products; the total @@ -62,57 +64,58 @@ void InnerProductLayer::Reshape(const vector*>& bottom, M_ = bottom[0]->count(0, axis); // The top shape will be the bottom shape with the flattened axes dropped, // and replaced by a single axis with dimension num_output (N_). - vector top_shape = bottom[0]->shape(); + vector top_shape = bottom[0]->shape(); top_shape.resize(axis + 1); top_shape[axis] = N_; top[0]->Reshape(top_shape); // Set up the bias multiplier if (bias_term_) { - vector bias_shape(1, M_); + vector bias_shape(1, M_); bias_multiplier_.Reshape(bias_shape); caffe_set(M_, Dtype(1), bias_multiplier_.mutable_cpu_data()); } } -template +template void InnerProductLayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); const Dtype* weight = this->blobs_[0]->cpu_data(); - caffe_cpu_gemm(CblasNoTrans, CblasTrans, M_, N_, K_, (Dtype)1., - bottom_data, weight, (Dtype)0., top_data); + caffe_cpu_gemm(CblasNoTrans, CblasTrans, M_, N_, K_, (Dtype) 1., + bottom_data, weight, (Dtype) 0., top_data); if (bias_term_) { - caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype)1., - bias_multiplier_.cpu_data(), - this->blobs_[1]->cpu_data(), (Dtype)1., top_data); + caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype) 1., + bias_multiplier_.cpu_data(), + this->blobs_[1]->cpu_data(), (Dtype) 1., top_data); } } -template -void InnerProductLayer::Backward_cpu(const vector*>& top, - const vector& propagate_down, +template +void InnerProductLayer::Backward_cpu( + const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (this->param_propagate_down_[0]) { const Dtype* top_diff = top[0]->cpu_diff(); const Dtype* bottom_data = bottom[0]->cpu_data(); // Gradient with respect to weight - caffe_cpu_gemm(CblasTrans, CblasNoTrans, N_, K_, M_, (Dtype)1., - top_diff, bottom_data, (Dtype)1., this->blobs_[0]->mutable_cpu_diff()); + caffe_cpu_gemm(CblasTrans, CblasNoTrans, N_, K_, M_, (Dtype) 1., + top_diff, bottom_data, (Dtype) 1., + this->blobs_[0]->mutable_cpu_diff()); } if (bias_term_ && this->param_propagate_down_[1]) { const Dtype* top_diff = top[0]->cpu_diff(); // Gradient with respect to bias - caffe_cpu_gemv(CblasTrans, M_, N_, (Dtype)1., top_diff, - bias_multiplier_.cpu_data(), (Dtype)1., - this->blobs_[1]->mutable_cpu_diff()); + caffe_cpu_gemv(CblasTrans, M_, N_, (Dtype) 1., top_diff, + bias_multiplier_.cpu_data(), (Dtype) 1., + this->blobs_[1]->mutable_cpu_diff()); } if (propagate_down[0]) { const Dtype* top_diff = top[0]->cpu_diff(); // Gradient with respect to bottom data - caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype)1., - top_diff, this->blobs_[0]->cpu_data(), (Dtype)0., - bottom[0]->mutable_cpu_diff()); + caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype) 1., + top_diff, this->blobs_[0]->cpu_data(), (Dtype) 0., + bottom[0]->mutable_cpu_diff()); } } diff --git a/src/caffe/layers/inner_product_layer.cu b/src/caffe/layers/inner_product_layer.cu index dc25aa33bd1..bbe6cb01895 100644 --- a/src/caffe/layers/inner_product_layer.cu +++ b/src/caffe/layers/inner_product_layer.cu @@ -6,52 +6,123 @@ namespace caffe { -template +template void InnerProductLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); const Dtype* weight = this->blobs_[0]->gpu_data(); - if (M_ == 1) { - caffe_gpu_gemv(CblasNoTrans, N_, K_, (Dtype)1., - weight, bottom_data, (Dtype)0., top_data); - if (bias_term_) - caffe_gpu_axpy(N_, bias_multiplier_.cpu_data()[0], - this->blobs_[1]->gpu_data(), top_data); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (M_ == 1) { + caffe_gpu_gemv(CblasNoTrans, N_, K_, (Dtype) 1., weight, + bottom_data, (Dtype) 0., top_data); + if (bias_term_) + caffe_gpu_axpy(N_, bias_multiplier_.cpu_data()[0], + this->blobs_[1]->gpu_data(), top_data); + } else { + caffe_gpu_gemm(CblasNoTrans, CblasTrans, M_, N_, K_, (Dtype) 1., + bottom_data, weight, (Dtype) 0., top_data); + if (bias_term_) + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype) 1., + bias_multiplier_.gpu_data(), + this->blobs_[1]->gpu_data(), (Dtype) 1., + top_data); + } +#endif // USE CUDA } else { - caffe_gpu_gemm(CblasNoTrans, CblasTrans, M_, N_, K_, (Dtype)1., - bottom_data, weight, (Dtype)0., top_data); - if (bias_term_) - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, M_, N_, 1, (Dtype)1., - bias_multiplier_.gpu_data(), - this->blobs_[1]->gpu_data(), (Dtype)1., top_data); +#ifdef USE_GREENTEA + if (M_ == 1) { + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, N_, + K_, (Dtype) 1., (cl_mem) weight, 0, + (cl_mem) bottom_data, 0, (Dtype) 0., + (cl_mem) top_data, 0); + if (bias_term_) + greentea_gpu_axpy(this->device_->id(), N_, + bias_multiplier_.cpu_data()[0], + (cl_mem) (this->blobs_[1]->gpu_data()), 0, + (cl_mem) top_data, 0); + } else { + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasTrans, M_, N_, K_, (Dtype) 1., + (cl_mem) bottom_data, 0, (cl_mem) weight, 0, + (Dtype) 0., (cl_mem) top_data, 0); + if (bias_term_) + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, M_, N_, 1, (Dtype) 1., + (cl_mem) (bias_multiplier_.gpu_data()), 0, + (cl_mem) (this->blobs_[1]->gpu_data()), 0, + (Dtype) 1., (cl_mem) top_data, 0); + } +#endif // USE_GREENTEA } } -template -void InnerProductLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, +template +void InnerProductLayer::Backward_gpu( + const vector*>& top, const vector& propagate_down, const vector*>& bottom) { - if (this->param_propagate_down_[0]) { - const Dtype* top_diff = top[0]->gpu_diff(); - const Dtype* bottom_data = bottom[0]->gpu_data(); - // Gradient with respect to weight - caffe_gpu_gemm(CblasTrans, CblasNoTrans, N_, K_, M_, (Dtype)1., - top_diff, bottom_data, (Dtype)1., this->blobs_[0]->mutable_gpu_diff()); - } - if (bias_term_ && this->param_propagate_down_[1]) { - const Dtype* top_diff = top[0]->gpu_diff(); - // Gradient with respect to bias - caffe_gpu_gemv(CblasTrans, M_, N_, (Dtype)1., top_diff, - bias_multiplier_.gpu_data(), (Dtype)1., - this->blobs_[1]->mutable_gpu_diff()); - } - if (propagate_down[0]) { - const Dtype* top_diff = top[0]->gpu_diff(); - // Gradient with respect to bottom data - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype)1., - top_diff, this->blobs_[0]->gpu_data(), (Dtype)0., - bottom[0]->mutable_gpu_diff()); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (this->param_propagate_down_[0]) { + const Dtype* top_diff = top[0]->gpu_diff(); + const Dtype* bottom_data = bottom[0]->gpu_data(); + // Gradient with respect to weight + caffe_gpu_gemm(CblasTrans, CblasNoTrans, N_, K_, M_, (Dtype) 1., + top_diff, bottom_data, (Dtype) 1., + this->blobs_[0]->mutable_gpu_diff()); + } + if (bias_term_ && this->param_propagate_down_[1]) { + const Dtype* top_diff = top[0]->gpu_diff(); + // Gradient with respect to bias + caffe_gpu_gemv(CblasTrans, M_, N_, (Dtype) 1., top_diff, + bias_multiplier_.gpu_data(), (Dtype) 1., + this->blobs_[1]->mutable_gpu_diff()); + } + if (propagate_down[0]) { + const Dtype* top_diff = top[0]->gpu_diff(); + // Gradient with respect to bottom data + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, M_, K_, N_, (Dtype) 1., + top_diff, this->blobs_[0]->gpu_data(), (Dtype) 0., + bottom[0]->mutable_gpu_diff()); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + if (this->param_propagate_down_[0]) { + const Dtype* top_diff = top[0]->gpu_diff(); + const Dtype* bottom_data = bottom[0]->gpu_data(); + // Gradient with respect to weight + greentea_gpu_gemm(this->device_->id(), CblasTrans, + CblasNoTrans, N_, K_, M_, (Dtype) 1., + (cl_mem) top_diff, 0, (cl_mem) bottom_data, 0, + (Dtype) 1., + (cl_mem) (this->blobs_[0]->mutable_gpu_diff()), + 0); + } + if (bias_term_ && this->param_propagate_down_[1]) { + const Dtype* top_diff = top[0]->gpu_diff(); + // Gradient with respect to bias + greentea_gpu_gemv(this->device_->id(), CblasTrans, M_, N_, + (Dtype) 1., (cl_mem) top_diff, 0, + (cl_mem) (bias_multiplier_.gpu_data()), 0, + (Dtype) 1., + (cl_mem) (this->blobs_[1]->mutable_gpu_diff()), + 0); + } + if (propagate_down[0]) { + const Dtype* top_diff = top[0]->gpu_diff(); + // Gradient with respect to bottom data + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, M_, K_, N_, (Dtype) 1., + (cl_mem) top_diff, 0, + (cl_mem) (this->blobs_[0]->gpu_data()), 0, + (Dtype) 0., + (cl_mem) (bottom[0]->mutable_gpu_diff()), 0); + } +#endif // USE_GREENTEA } } diff --git a/src/caffe/layers/log_layer.cpp b/src/caffe/layers/log_layer.cpp index c70a795cf53..1ddde0e6eb1 100644 --- a/src/caffe/layers/log_layer.cpp +++ b/src/caffe/layers/log_layer.cpp @@ -33,13 +33,13 @@ void LogLayer::LayerSetUp(const vector*>& bottom, template void LogLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); if (input_scale_ == Dtype(1) && input_shift_ == Dtype(0)) { caffe_log(count, bottom_data, top_data); } else { - caffe_copy(count, bottom_data, top_data); + caffe_cpu_copy(count, bottom_data, top_data); if (input_scale_ != Dtype(1)) { caffe_scal(count, input_scale_, top_data); } @@ -57,11 +57,11 @@ template void LogLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (!propagate_down[0]) { return; } - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - caffe_copy(count, bottom_data, bottom_diff); + caffe_cpu_copy(count, bottom_data, bottom_diff); if (input_scale_ != Dtype(1)) { caffe_scal(count, input_scale_, bottom_diff); } diff --git a/src/caffe/layers/log_layer.cu b/src/caffe/layers/log_layer.cu index db466dbac29..d22a1fbf503 100644 --- a/src/caffe/layers/log_layer.cu +++ b/src/caffe/layers/log_layer.cu @@ -5,37 +5,75 @@ namespace caffe { -template +template void LogLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - const int count = bottom[0]->count(); + const vector*>& top) { + const int_tp count = bottom[0]->count(); const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - if (input_scale_ == Dtype(1) && input_shift_ == Dtype(0)) { - caffe_gpu_log(count, bottom_data, top_data); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (input_scale_ == Dtype(1) && input_shift_ == Dtype(0)) { + caffe_gpu_log(count, bottom_data, top_data); + } else { + caffe_copy(count, bottom_data, top_data); + if (input_scale_ != Dtype(1)) { + caffe_gpu_scal(count, input_scale_, top_data); + } + if (input_shift_ != Dtype(0)) { + caffe_gpu_add_scalar(count, input_shift_, top_data); + } + caffe_gpu_log(count, top_data, top_data); + } + if (base_scale_ != Dtype(1)) { + caffe_gpu_scal(count, base_scale_, top_data); + } +#endif // USE_CUDA } else { - caffe_copy(count, bottom_data, top_data); - if (input_scale_ != Dtype(1)) { - caffe_gpu_scal(count, input_scale_, top_data); +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (input_scale_ == Dtype(1) && input_shift_ == Dtype(0)) { + greentea_gpu_log(this->device_->id(), count, + (cl_mem) bottom_data, 0, (cl_mem) top_data, 0); + } else { + greentea_copy(count, (cl_mem) bottom_data, 0, (cl_mem) top_data, 0, + &ctx); + if (input_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, + input_scale_, (cl_mem) top_data, 0); + } + if (input_shift_ != Dtype(0)) { + greentea_gpu_add_scalar(this->device_->id(), count, + input_shift_, (cl_mem) top_data, 0); + } + greentea_gpu_log(this->device_->id(), count, + (cl_mem) top_data, 0, (cl_mem) top_data, 0); } - if (input_shift_ != Dtype(0)) { - caffe_gpu_add_scalar(count, input_shift_, top_data); + if (base_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, base_scale_, + (cl_mem) top_data, 0); } - caffe_gpu_log(count, top_data, top_data); - } - if (base_scale_ != Dtype(1)) { - caffe_gpu_scal(count, base_scale_, top_data); +#endif // USE_GREENTEA } } -template +template void LogLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (!propagate_down[0]) { return; } - const int count = bottom[0]->count(); - const Dtype* bottom_data = bottom[0]->gpu_data(); - const Dtype* top_diff = top[0]->gpu_diff(); - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + const vector& propagate_down, + const vector*>& bottom) { + if (!propagate_down[0]) { + return; + } + const int_tp count = bottom[0]->count(); + const Dtype* bottom_data = bottom[0]->gpu_data(); + const Dtype* top_diff = top[0]->gpu_diff(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_copy(count, bottom_data, bottom_diff); if (input_scale_ != Dtype(1)) { caffe_gpu_scal(count, input_scale_, bottom_diff); @@ -48,6 +86,34 @@ void LogLayer::Backward_gpu(const vector*>& top, caffe_gpu_scal(count, backward_num_scale_, bottom_diff); } caffe_gpu_mul(count, top_diff, bottom_diff, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + greentea_copy(count, (cl_mem) bottom_data, 0, (cl_mem) bottom_diff, + 0, &ctx); + if (input_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, input_scale_, + (cl_mem) bottom_diff, 0); + } + if (input_shift_ != Dtype(0)) { + greentea_gpu_add_scalar(this->device_->id(), count, + input_shift_, (cl_mem) bottom_diff, 0); + } + greentea_gpu_powx(this->device_->id(), count, + (cl_mem) bottom_diff, 0, Dtype(-1), + (cl_mem) bottom_diff, 0); + if (backward_num_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, + backward_num_scale_, (cl_mem) bottom_diff, 0); + } + greentea_gpu_mul(this->device_->id(), count, + (cl_mem) top_diff, 0, (cl_mem) bottom_diff, 0, + (cl_mem) bottom_diff, 0); +#endif // USE_GREENTEA + } } INSTANTIATE_LAYER_GPU_FUNCS(LogLayer); diff --git a/src/caffe/layers/loss_layer.cpp b/src/caffe/layers/loss_layer.cpp index c0b7a862181..3d58f3b5622 100644 --- a/src/caffe/layers/loss_layer.cpp +++ b/src/caffe/layers/loss_layer.cpp @@ -16,9 +16,9 @@ void LossLayer::LayerSetUp( template void LossLayer::Reshape( const vector*>& bottom, const vector*>& top) { - CHECK_EQ(bottom[0]->num(), bottom[1]->num()) + CHECK_EQ(bottom[0]->shape(0), bottom[1]->shape(0)) << "The data and label should have the same number."; - vector loss_shape(0); // Loss layers output a scalar; 0 axes. + vector loss_shape(0); // Loss layers output a scalar; 0 axes. top[0]->Reshape(loss_shape); } diff --git a/src/caffe/layers/lrn_layer.cpp b/src/caffe/layers/lrn_layer.cpp index 210525e20f3..0bd0229664d 100644 --- a/src/caffe/layers/lrn_layer.cpp +++ b/src/caffe/layers/lrn_layer.cpp @@ -5,17 +5,17 @@ namespace caffe { -template +template void LRNLayer::LayerSetUp(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { size_ = this->layer_param_.lrn_param().local_size(); - CHECK_EQ(size_ % 2, 1) << "LRN only supports odd values for local_size"; + CHECK_EQ(size_ % 2, 1)<< "LRN only supports odd values for local_size"; pre_pad_ = (size_ - 1) / 2; alpha_ = this->layer_param_.lrn_param().alpha(); beta_ = this->layer_param_.lrn_param().beta(); k_ = this->layer_param_.lrn_param().k(); - if (this->layer_param_.lrn_param().norm_region() == - LRNParameter_NormRegion_WITHIN_CHANNEL) { + if (this->layer_param_.lrn_param().norm_region() + == LRNParameter_NormRegion_WITHIN_CHANNEL) { // Set up split_layer_ to use inputs in the numerator and denominator. split_top_vec_.clear(); split_top_vec_.push_back(&product_input_); @@ -38,8 +38,8 @@ void LRNLayer::LayerSetUp(const vector*>& bottom, LayerParameter pool_param; pool_param.mutable_pooling_param()->set_pool( PoolingParameter_PoolMethod_AVE); - pool_param.mutable_pooling_param()->set_pad(pre_pad_); - pool_param.mutable_pooling_param()->set_kernel_size(size_); + pool_param.mutable_pooling_param()->add_pad(pre_pad_); + pool_param.mutable_pooling_param()->add_kernel_size(size_); pool_layer_.reset(new PoolingLayer(pool_param)); pool_layer_->SetUp(square_top_vec_, pool_top_vec_); // Set up power_layer_ to compute (1 + alpha_/N^2 s)^-beta_, where s is @@ -65,21 +65,21 @@ void LRNLayer::LayerSetUp(const vector*>& bottom, } } -template +template void LRNLayer::Reshape(const vector*>& bottom, - const vector*>& top) { - CHECK_EQ(4, bottom[0]->num_axes()) << "Input must have 4 axes, " - << "corresponding to (num, channels, height, width)"; + const vector*>& top) { + CHECK_EQ(4, bottom[0]->num_axes())<< "Input must have 4 axes, " + << "corresponding to (num, channels, height, width)"; num_ = bottom[0]->num(); channels_ = bottom[0]->channels(); height_ = bottom[0]->height(); width_ = bottom[0]->width(); switch (this->layer_param_.lrn_param().norm_region()) { - case LRNParameter_NormRegion_ACROSS_CHANNELS: + case LRNParameter_NormRegion_ACROSS_CHANNELS: top[0]->Reshape(num_, channels_, height_, width_); scale_.Reshape(num_, channels_, height_, width_); break; - case LRNParameter_NormRegion_WITHIN_CHANNEL: + case LRNParameter_NormRegion_WITHIN_CHANNEL: split_layer_->Reshape(bottom, split_top_vec_); square_layer_->Reshape(square_bottom_vec_, square_top_vec_); pool_layer_->Reshape(square_top_vec_, pool_top_vec_); @@ -89,60 +89,61 @@ void LRNLayer::Reshape(const vector*>& bottom, } } -template +template void LRNLayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { switch (this->layer_param_.lrn_param().norm_region()) { - case LRNParameter_NormRegion_ACROSS_CHANNELS: - CrossChannelForward_cpu(bottom, top); - break; - case LRNParameter_NormRegion_WITHIN_CHANNEL: - WithinChannelForward(bottom, top); - break; - default: - LOG(FATAL) << "Unknown normalization region."; + case LRNParameter_NormRegion_ACROSS_CHANNELS: + CrossChannelForward_cpu(bottom, top); + break; + case LRNParameter_NormRegion_WITHIN_CHANNEL: + WithinChannelForward(bottom, top); + break; + default: + LOG(FATAL)<< "Unknown normalization region."; + } } -} -template +template void LRNLayer::CrossChannelForward_cpu( const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); Dtype* scale_data = scale_.mutable_cpu_data(); // start with the constant value - for (int i = 0; i < scale_.count(); ++i) { + for (int_tp i = 0; i < scale_.count(); ++i) { scale_data[i] = k_; } - Blob padded_square(1, channels_ + size_ - 1, height_, width_); + Blob padded_square(1, channels_ + size_ - 1, height_, width_, + this->device_); Dtype* padded_square_data = padded_square.mutable_cpu_data(); caffe_set(padded_square.count(), Dtype(0), padded_square_data); Dtype alpha_over_size = alpha_ / size_; // go through the images - for (int n = 0; n < num_; ++n) { + for (int_tp n = 0; n < num_; ++n) { // compute the padded square - caffe_sqr(channels_ * height_ * width_, - bottom_data + bottom[0]->offset(n), - padded_square_data + padded_square.offset(0, pre_pad_)); + caffe_sqr(channels_ * height_ * width_, bottom_data + bottom[0]->offset(n), + padded_square_data + padded_square.offset(0, pre_pad_)); // Create the first channel scale - for (int c = 0; c < size_; ++c) { + for (int_tp c = 0; c < size_; ++c) { caffe_axpy(height_ * width_, alpha_over_size, - padded_square_data + padded_square.offset(0, c), - scale_data + scale_.offset(n, 0)); + padded_square_data + padded_square.offset(0, c), + scale_data + scale_.offset(n, 0)); } - for (int c = 1; c < channels_; ++c) { + for (int_tp c = 1; c < channels_; ++c) { // copy previous scale - caffe_copy(height_ * width_, - scale_data + scale_.offset(n, c - 1), - scale_data + scale_.offset(n, c)); + caffe_cpu_copy(height_ * width_, + scale_data + scale_.offset(n, c - 1), + scale_data + scale_.offset(n, c)); // add head - caffe_axpy(height_ * width_, alpha_over_size, + caffe_axpy( + height_ * width_, alpha_over_size, padded_square_data + padded_square.offset(0, c + size_ - 1), scale_data + scale_.offset(n, c)); // subtract tail caffe_axpy(height_ * width_, -alpha_over_size, - padded_square_data + padded_square.offset(0, c - 1), - scale_data + scale_.offset(n, c)); + padded_square_data + padded_square.offset(0, c - 1), + scale_data + scale_.offset(n, c)); } } @@ -151,9 +152,9 @@ void LRNLayer::CrossChannelForward_cpu( caffe_mul(scale_.count(), top_data, bottom_data, top_data); } -template -void LRNLayer::WithinChannelForward( - const vector*>& bottom, const vector*>& top) { +template +void LRNLayer::WithinChannelForward(const vector*>& bottom, + const vector*>& top) { split_layer_->Forward(bottom, split_top_vec_); square_layer_->Forward(square_bottom_vec_, square_top_vec_); pool_layer_->Forward(square_top_vec_, pool_top_vec_); @@ -161,22 +162,23 @@ void LRNLayer::WithinChannelForward( product_layer_->Forward(product_bottom_vec_, top); } -template +template void LRNLayer::Backward_cpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { switch (this->layer_param_.lrn_param().norm_region()) { - case LRNParameter_NormRegion_ACROSS_CHANNELS: - CrossChannelBackward_cpu(top, propagate_down, bottom); - break; - case LRNParameter_NormRegion_WITHIN_CHANNEL: - WithinChannelBackward(top, propagate_down, bottom); - break; - default: - LOG(FATAL) << "Unknown normalization region."; + case LRNParameter_NormRegion_ACROSS_CHANNELS: + CrossChannelBackward_cpu(top, propagate_down, bottom); + break; + case LRNParameter_NormRegion_WITHIN_CHANNEL: + WithinChannelBackward(top, propagate_down, bottom); + break; + default: + LOG(FATAL)<< "Unknown normalization region."; + } } -} -template +template void LRNLayer::CrossChannelBackward_cpu( const vector*>& top, const vector& propagate_down, const vector*>& bottom) { @@ -185,8 +187,9 @@ void LRNLayer::CrossChannelBackward_cpu( const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* scale_data = scale_.cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - Blob padded_ratio(1, channels_ + size_ - 1, height_, width_); - Blob accum_ratio(1, 1, height_, width_); + Blob padded_ratio(1, channels_ + size_ - 1, height_, width_, + this->device_); + Blob accum_ratio(1, 1, height_, width_, this->device_); Dtype* padded_ratio_data = padded_ratio.mutable_cpu_data(); Dtype* accum_ratio_data = accum_ratio.mutable_cpu_data(); // We hack a little bit by using the diff() to store an additional result @@ -198,40 +201,45 @@ void LRNLayer::CrossChannelBackward_cpu( caffe_mul(scale_.count(), top_diff, bottom_diff, bottom_diff); // go through individual data - int inverse_pre_pad = size_ - (size_ + 1) / 2; - for (int n = 0; n < num_; ++n) { - int block_offset = scale_.offset(n); + int_tp inverse_pre_pad = size_ - (size_ + 1) / 2; + for (int_tp n = 0; n < num_; ++n) { + int_tp block_offset = scale_.offset(n); // first, compute diff_i * y_i / s_i - caffe_mul(channels_ * height_ * width_, - top_diff + block_offset, top_data + block_offset, + caffe_mul( + channels_ * height_ * width_, top_diff + block_offset, + top_data + block_offset, padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad)); - caffe_div(channels_ * height_ * width_, + caffe_div( + channels_ * height_ * width_, padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad), scale_data + block_offset, padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad)); // Now, compute the accumulated ratios and the bottom diff caffe_set(accum_ratio.count(), Dtype(0), accum_ratio_data); - for (int c = 0; c < size_ - 1; ++c) { + for (int_tp c = 0; c < size_ - 1; ++c) { caffe_axpy(height_ * width_, 1., - padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data); + padded_ratio_data + padded_ratio.offset(0, c), + accum_ratio_data); } - for (int c = 0; c < channels_; ++c) { - caffe_axpy(height_ * width_, 1., + for (int_tp c = 0; c < channels_; ++c) { + caffe_axpy( + height_ * width_, 1., padded_ratio_data + padded_ratio.offset(0, c + size_ - 1), accum_ratio_data); // compute bottom diff - caffe_mul(height_ * width_, - bottom_data + top[0]->offset(n, c), - accum_ratio_data, accum_ratio_times_bottom); + caffe_mul(height_ * width_, bottom_data + top[0]->offset(n, c), + accum_ratio_data, accum_ratio_times_bottom); caffe_axpy(height_ * width_, -cache_ratio_value, - accum_ratio_times_bottom, bottom_diff + top[0]->offset(n, c)); + accum_ratio_times_bottom, + bottom_diff + top[0]->offset(n, c)); caffe_axpy(height_ * width_, -1., - padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data); + padded_ratio_data + padded_ratio.offset(0, c), + accum_ratio_data); } } } -template +template void LRNLayer::WithinChannelBackward( const vector*>& top, const vector& propagate_down, const vector*>& bottom) { diff --git a/src/caffe/layers/lrn_layer.cu b/src/caffe/layers/lrn_layer.cu index 26e619c7569..9d861434629 100644 --- a/src/caffe/layers/lrn_layer.cu +++ b/src/caffe/layers/lrn_layer.cu @@ -5,23 +5,25 @@ namespace caffe { -template -__global__ void LRNFillScale(const int nthreads, const Dtype* const in, - const int num, const int channels, const int height, - const int width, const int size, const Dtype alpha_over_size, - const Dtype k, Dtype* const scale) { +#ifdef USE_CUDA +template +__global__ void LRNFillScale(const int_tp nthreads, const Dtype* const in, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp size, const Dtype alpha_over_size, + const Dtype k, Dtype* const scale) { CUDA_KERNEL_LOOP(index, nthreads) { // find out the local offset - const int w = index % width; - const int h = (index / width) % height; - const int n = index / width / height; - const int offset = (n * channels * height + h) * width + w; - const int step = height * width; + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp n = index / width / height; + const int_tp offset = (n * channels * height + h) * width + w; + const int_tp step = height * width; const Dtype* const in_off = in + offset; Dtype* const scale_off = scale + offset; - int head = 0; - const int pre_pad = (size - 1) / 2; - const int post_pad = size - pre_pad - 1; + int_tp head = 0; + const int_tp pre_pad = (size - 1) / 2; + const int_tp post_pad = size - pre_pad - 1; Dtype accum_scale = 0; // fill the scale at [n, :, h, w] // accumulate values @@ -34,7 +36,7 @@ __global__ void LRNFillScale(const int nthreads, const Dtype* const in, accum_scale += in_off[head * step] * in_off[head * step]; if (head - size >= 0) { accum_scale -= in_off[(head - size) * step] - * in_off[(head - size) * step]; + * in_off[(head - size) * step]; } scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size; ++head; @@ -43,150 +45,215 @@ __global__ void LRNFillScale(const int nthreads, const Dtype* const in, while (head < channels + post_pad) { if (head - size >= 0) { accum_scale -= in_off[(head - size) * step] - * in_off[(head - size) * step]; + * in_off[(head - size) * step]; } scale_off[(head - post_pad) * step] = k + accum_scale * alpha_over_size; ++head; } } } +#endif // USE_CUDA - -template +template void LRNLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { switch (this->layer_param_.lrn_param().norm_region()) { - case LRNParameter_NormRegion_ACROSS_CHANNELS: - CrossChannelForward_gpu(bottom, top); - break; - case LRNParameter_NormRegion_WITHIN_CHANNEL: - WithinChannelForward(bottom, top); - break; - default: - LOG(FATAL) << "Unknown normalization region."; + case LRNParameter_NormRegion_ACROSS_CHANNELS: + CrossChannelForward_gpu(bottom, top); + break; + case LRNParameter_NormRegion_WITHIN_CHANNEL: + WithinChannelForward(bottom, top); + break; + default: + LOG(FATAL)<< "Unknown normalization region."; + } } -} // TODO: check if it would be faster to just put it into the previous kernel. -template -__global__ void LRNComputeOutput(const int nthreads, const Dtype* const in, - const Dtype* const scale, const Dtype negative_beta, Dtype* const out) { +#ifdef USE_CUDA +template +__global__ void LRNComputeOutput(const int_tp nthreads, const Dtype* const in, + const Dtype* const scale, + const Dtype negative_beta, Dtype* const out) { CUDA_KERNEL_LOOP(index, nthreads) { out[index] = in[index] * pow(scale[index], negative_beta); } } +#endif // USE_CUDA -template +template void LRNLayer::CrossChannelForward_gpu( const vector*>& bottom, const vector*>& top) { // First, compute scale const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); Dtype* scale_data = scale_.mutable_gpu_data(); - // We will launch one kernel for each pixel location, and have the kernel - // go through all the channels. - int n_threads = num_ * height_ * width_; - // NOLINT_NEXT_LINE(whitespace/operators) - LRNFillScale<<>>( - n_threads, bottom_data, num_, channels_, height_, width_, size_, - alpha_ / size_, k_, scale_data); - CUDA_POST_KERNEL_CHECK; - n_threads = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - LRNComputeOutput<<>>( - n_threads, bottom_data, scale_data, -beta_, top_data); - CUDA_POST_KERNEL_CHECK; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // We will launch one kernel for each pixel location, and have the kernel + // go through all the channels. + int_tp n_threads = num_ * height_ * width_; + // NOLINT_NEXT_LINE(whitespace/operators) + LRNFillScale CUDA_KERNEL(CAFFE_GET_BLOCKS(n_threads), + CAFFE_CUDA_NUM_THREADS)( + n_threads, bottom_data, num_, channels_, height_, + width_, size_, + alpha_ / size_, k_, scale_data); + CUDA_POST_KERNEL_CHECK; + n_threads = bottom[0]->count(); + // NOLINT_NEXT_LINE(whitespace/operators) + LRNComputeOutput CUDA_KERNEL(CAFFE_GET_BLOCKS(n_threads), + CAFFE_CUDA_NUM_THREADS)( + n_threads, bottom_data, scale_data, -beta_, top_data); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + int_tp n_threads = num_ * height_ * width_; + viennacl::ocl::kernel &oclk_lrn_fill = program.get_kernel( + CL_KERNEL_SELECT("lrn_fill_scale")); + viennacl::ocl::enqueue( + oclk_lrn_fill(n_threads, WrapHandle((cl_mem) bottom_data, &ctx), num_, + channels_, height_, width_, size_, alpha_ / size_, k_, + WrapHandle((cl_mem) scale_data, &ctx)), + ctx.get_queue()); + + n_threads = bottom[0]->count(); + viennacl::ocl::kernel &oclk_lrn_compute = program.get_kernel( + CL_KERNEL_SELECT("lrn_compute_output")); + viennacl::ocl::enqueue( + oclk_lrn_compute(n_threads, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) scale_data, &ctx), -beta_, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } template void LRNLayer::CrossChannelForward_gpu( const vector*>& bottom, const vector*>& top); template void LRNLayer::CrossChannelForward_gpu( const vector*>& bottom, const vector*>& top); - -template +template void LRNLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { switch (this->layer_param_.lrn_param().norm_region()) { - case LRNParameter_NormRegion_ACROSS_CHANNELS: - CrossChannelBackward_gpu(top, propagate_down, bottom); - break; - case LRNParameter_NormRegion_WITHIN_CHANNEL: - WithinChannelBackward(top, propagate_down, bottom); - break; - default: - LOG(FATAL) << "Unknown normalization region."; + case LRNParameter_NormRegion_ACROSS_CHANNELS: + CrossChannelBackward_gpu(top, propagate_down, bottom); + break; + case LRNParameter_NormRegion_WITHIN_CHANNEL: + WithinChannelBackward(top, propagate_down, bottom); + break; + default: + LOG(FATAL)<< "Unknown normalization region."; + } } -} -template -__global__ void LRNComputeDiff(const int nthreads, - const Dtype* const bottom_data, const Dtype* const top_data, - const Dtype* const scale, const Dtype* const top_diff, - const int num, const int channels, const int height, - const int width, const int size, const Dtype negative_beta, - const Dtype cache_ratio, Dtype* const bottom_diff) { +#ifdef USE_CUDA +template +__global__ void LRNComputeDiff(const int_tp nthreads, + const Dtype* const bottom_data, + const Dtype* const top_data, + const Dtype* const scale, + const Dtype* const top_diff, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp size, + const Dtype negative_beta, + const Dtype cache_ratio, + Dtype* const bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { // find out the local offset - const int w = index % width; - const int h = (index / width) % height; - const int n = index / width / height; - const int offset = (n * channels * height + h) * width + w; - const int step = height * width; + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp n = index / width / height; + const int_tp offset = (n * channels * height + h) * width + w; + const int_tp step = height * width; const Dtype* const bottom_off = bottom_data + offset; const Dtype* const top_off = top_data + offset; const Dtype* const scale_off = scale + offset; const Dtype* const top_diff_off = top_diff + offset; Dtype* const bottom_diff_off = bottom_diff + offset; - int head = 0; - const int pre_pad = size - (size + 1) / 2; - const int post_pad = size - pre_pad - 1; + int_tp head = 0; + const int_tp pre_pad = size - (size + 1) / 2; + const int_tp post_pad = size - pre_pad - 1; Dtype accum_ratio = 0; // accumulate values while (head < post_pad && head < channels) { - accum_ratio += top_diff_off[head * step] * top_off[head * step] / - scale_off[head * step]; + accum_ratio += top_diff_off[head * step] * top_off[head * step] + / scale_off[head * step]; ++head; } // both add and subtract while (head < channels) { - accum_ratio += top_diff_off[head * step] * top_off[head * step] / - scale_off[head * step]; + accum_ratio += top_diff_off[head * step] * top_off[head * step] + / scale_off[head * step]; if (head - size >= 0) { - accum_ratio -= top_diff_off[(head - size) * step] * - top_off[(head - size) * step] / scale_off[(head - size) * step]; + accum_ratio -= top_diff_off[(head - size) * step] + * top_off[(head - size) * step] / scale_off[(head - size) * step]; } - bottom_diff_off[(head - post_pad) * step] = - top_diff_off[(head - post_pad) * step] - * pow(scale_off[(head - post_pad) * step], negative_beta) + bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad) + * step] * pow(scale_off[(head - post_pad) * step], negative_beta) - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio; ++head; } // subtract only while (head < channels + post_pad) { if (head - size >= 0) { - accum_ratio -= top_diff_off[(head - size) * step] * - top_off[(head - size) * step] / scale_off[(head - size) * step]; + accum_ratio -= top_diff_off[(head - size) * step] + * top_off[(head - size) * step] / scale_off[(head - size) * step]; } - bottom_diff_off[(head - post_pad) * step] = - top_diff_off[(head - post_pad) * step] - * pow(scale_off[(head - post_pad) * step], negative_beta) + bottom_diff_off[(head - post_pad) * step] = top_diff_off[(head - post_pad) + * step] * pow(scale_off[(head - post_pad) * step], negative_beta) - cache_ratio * bottom_off[(head - post_pad) * step] * accum_ratio; ++head; } } } +#endif // USE_CUDA -template +template void LRNLayer::CrossChannelBackward_gpu( const vector*>& top, const vector& propagate_down, const vector*>& bottom) { - int n_threads = num_ * height_ * width_; - // NOLINT_NEXT_LINE(whitespace/operators) - LRNComputeDiff<<>>( - n_threads, bottom[0]->gpu_data(), top[0]->gpu_data(), - scale_.gpu_data(), top[0]->gpu_diff(), num_, channels_, height_, width_, - size_, -beta_, Dtype(2. * alpha_ * beta_ / size_), - bottom[0]->mutable_gpu_diff()); + int_tp n_threads = num_ * height_ * width_; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + LRNComputeDiff CUDA_KERNEL(CAFFE_GET_BLOCKS(n_threads), + CAFFE_CUDA_NUM_THREADS)( + n_threads, bottom[0]->gpu_data(), top[0]->gpu_data(), + scale_.gpu_data(), top[0]->gpu_diff(), num_, + channels_, height_, width_, + size_, -beta_, Dtype(2. * alpha_ * beta_ / size_), + bottom[0]->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_lrn = program.get_kernel( + CL_KERNEL_SELECT("lrn_compute_diff")); + viennacl::ocl::enqueue( + oclk_lrn(n_threads, WrapHandle((cl_mem) (bottom[0]->gpu_data()), &ctx), + WrapHandle((cl_mem) (top[0]->gpu_data()), &ctx), + WrapHandle((cl_mem) (scale_.gpu_data()), &ctx), + WrapHandle((cl_mem) (top[0]->gpu_diff()), &ctx), num_, + channels_, height_, width_, size_, -beta_, + Dtype(2. * alpha_ * beta_ / size_), + WrapHandle((cl_mem) (bottom[0]->mutable_gpu_diff()), &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } template void LRNLayer::CrossChannelBackward_gpu( const vector*>& top, const vector& propagate_down, @@ -195,8 +262,6 @@ template void LRNLayer::CrossChannelBackward_gpu( const vector*>& top, const vector& propagate_down, const vector*>& bottom); - - INSTANTIATE_LAYER_GPU_FUNCS(LRNLayer); } // namespace caffe diff --git a/src/caffe/layers/malis_loss_layer.cpp b/src/caffe/layers/malis_loss_layer.cpp new file mode 100644 index 00000000000..042fdd2f492 --- /dev/null +++ b/src/caffe/layers/malis_loss_layer.cpp @@ -0,0 +1,445 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/layer_factory.hpp" +#include "caffe/layers/malis_loss_layer.hpp" +#include "caffe/util/math_functions.hpp" + + +namespace caffe { + +template +class MalisAffinityGraphCompare { + private: + const Dtype * mEdgeWeightArray; + public: + explicit MalisAffinityGraphCompare(const Dtype * EdgeWeightArray) { + mEdgeWeightArray = EdgeWeightArray; + } + bool operator()(const int64_t& ind1, const int64_t& ind2) const { + return (mEdgeWeightArray[ind1] > mEdgeWeightArray[ind2]); + } +}; + +// Derived from https://github.com/srinituraga/malis/blob/master/matlab/malis_loss_mex.cpp +template +void MalisLossLayer::Malis(const Dtype* conn_data, + const int_tp conn_num_dims, + const int_tp* conn_dims, + const int_tp* nhood_data, + const int_tp* nhood_dims, + const Dtype* seg_data, const bool pos, + Dtype* dloss_data, Dtype* loss_out, + Dtype *classerr_out, Dtype *rand_index_out) { + if ((nhood_dims[1] != (conn_num_dims - 1)) + || (nhood_dims[0] != conn_dims[0])) { + LOG(FATAL) << "nhood and conn dimensions don't match" + << " (" << nhood_dims[1] << " vs. " << (conn_num_dims - 1) + << " and " << nhood_dims[0] << " vs. " + << conn_dims[conn_num_dims - 1] <<")"; + } + + /* Cache for speed to access neighbors */ + // nVert stores (x * y * z) + int64_t nVert = 1; + for (int64_t i = 1; i < conn_num_dims; ++i) { + nVert *= conn_dims[i]; + // std::cout << i << " nVert: " << nVert << std::endl; + } + + // prodDims stores x, x*y, x*y*z offsets + std::vector prodDims(conn_num_dims - 1); + prodDims[conn_num_dims - 2] = 1; + for (int64_t i = 1; i < conn_num_dims - 1; ++i) { + prodDims[conn_num_dims - 2 - i] = prodDims[conn_num_dims - 1 - i] + * conn_dims[conn_num_dims - i]; + // std::cout << conn_num_dims - 2 - i << " dims: " + // << prodDims[conn_num_dims - 2 - i] << std::endl; + } + + /* convert n-d offset vectors into linear array offset scalars */ + // nHood is a vector of size #edges + + std::vector nHood(nhood_dims[0]); + for (int64_t i = 0; i < nhood_dims[0]; ++i) { + nHood[i] = 0; + for (int64_t j = 0; j < nhood_dims[1]; ++j) { + nHood[i] += (int32_t) nhood_data[j + i * nhood_dims[1]] * prodDims[j]; + } + // std::cout << i << " nHood: " << nHood[i] << std::endl; + } + + /* Disjoint sets and sparse overlap vectors */ + std::vector > overlap(nVert); + std::vector rank(nVert); + std::vector parent(nVert); + std::map segSizes; + int64_t nLabeledVert = 0; + int64_t nPairPos = 0; + boost::disjoint_sets dsets(&rank[0], &parent[0]); + // Loop over all seg data items + for (int64_t i = 0; i < nVert; ++i) { + dsets.make_set(i); + if (0 != seg_data[i]) { + overlap[i].insert(std::pair(seg_data[i], 1)); + ++nLabeledVert; + ++segSizes[seg_data[i]]; + nPairPos += (segSizes[seg_data[i]] - 1); + } + } + + int64_t nPairTot = (nLabeledVert * (nLabeledVert - 1)) / 2; + int64_t nPairNeg = nPairTot - nPairPos; + int64_t nPairNorm; + + if (pos) { + nPairNorm = nPairPos; + } else { + nPairNorm = nPairNeg; + } + + int64_t edgeCount = 0; + // Loop over #edges + for (int64_t d = 0, i = 0; d < conn_dims[0]; ++d) { + // Loop over Z + for (int64_t z = 0; z < conn_dims[1]; ++z) { + // Loop over Y + for (int64_t y = 0; y < conn_dims[2]; ++y) { + // Loop over X + for (int64_t x = 0; x < conn_dims[3]; ++x, ++i) { + // Out-of-bounds check: + if (!((z + nhood_data[d * nhood_dims[1] + 0] < 0) + ||(z + nhood_data[d * nhood_dims[1] + 0] >= conn_dims[1]) + ||(y + nhood_data[d * nhood_dims[1] + 1] < 0) + ||(y + nhood_data[d * nhood_dims[1] + 1] >= conn_dims[2]) + ||(x + nhood_data[d * nhood_dims[1] + 2] < 0) + ||(x + nhood_data[d * nhood_dims[1] + 2] >= conn_dims[3]))) { + ++edgeCount; + } + } + } + } + } + + /* Sort all the edges in increasing order of weight */ + std::vector pqueue(edgeCount); + int64_t j = 0; + // Loop over #edges + for (int64_t d = 0, i = 0; d < conn_dims[0]; ++d) { + // Loop over Z + for (int64_t z = 0; z < conn_dims[1]; ++z) { + // Loop over Y + for (int64_t y = 0; y < conn_dims[2]; ++y) { + // Loop over X + for (int64_t x = 0; x < conn_dims[3]; ++x, ++i) { + // Out-of-bounds check: + if (!((z + nhood_data[d * nhood_dims[1] + 0] < 0) + ||(z + nhood_data[d * nhood_dims[1] + 0] >= conn_dims[1]) + ||(y + nhood_data[d * nhood_dims[1] + 1] < 0) + ||(y + nhood_data[d * nhood_dims[1] + 1] >= conn_dims[2]) + ||(x + nhood_data[d * nhood_dims[1] + 2] < 0) + ||(x + nhood_data[d * nhood_dims[1] + 2] >= conn_dims[3]))) { + pqueue[j++] = i; + } + } + } + } + } + + pqueue.resize(j); + + std::sort(pqueue.begin(), pqueue.end(), + MalisAffinityGraphCompare(conn_data)); + + /* Start MST */ + int64_t minEdge; + int64_t e, v1, v2; + int64_t set1, set2; + int64_t nPair = 0; + double loss = 0, dl = 0; + int64_t nPairIncorrect = 0; + std::map::iterator it1, it2; + + /* Start Kruskal's */ + for (int64_t i = 0; i < pqueue.size(); ++i) { + minEdge = pqueue[i]; + // nVert = x * y * z, minEdge in [0, x * y * z * #edges] + + // e: edge dimension + e = minEdge / nVert; + + // v1: node at edge beginning + v1 = minEdge % nVert; + + // v2: neighborhood node at edge e + v2 = v1 + nHood[e]; + + // std::cout << "V1: " << v1 << ", V2: " << v2 << std::endl; + + set1 = dsets.find_set(v1); + set2 = dsets.find_set(v2); + + + if (set1 != set2) { + dsets.link(set1, set2); + + /* compute the dloss for this MST edge */ + for (it1 = overlap[set1].begin(); it1 != overlap[set1].end(); ++it1) { + for (it2 = overlap[set2].begin(); it2 != overlap[set2].end(); ++it2) { + nPair = it1->second * it2->second; + + if (pos && (it1->first == it2->first)) { + // +ve example pairs + dl = (Dtype(1.0) - conn_data[minEdge]); + loss += dl * dl * nPair; + // Use hinge loss + dloss_data[minEdge] += dl * nPair; + if (conn_data[minEdge] <= Dtype(0.5)) { // an error + nPairIncorrect += nPair; + } + + } else if ((!pos) && (it1->first != it2->first)) { + // -ve example pairs + dl = (-conn_data[minEdge]); + loss += dl * dl * nPair; + // Use hinge loss + dloss_data[minEdge] += dl * nPair; + if (conn_data[minEdge] > Dtype(0.5)) { // an error + nPairIncorrect += nPair; + } + } + } + } + + if (nPairNorm > 0) { + dloss_data[minEdge] /= nPairNorm; + } else { + dloss_data[minEdge] = 0; + } + + if (dsets.find_set(set1) == set2) { + std::swap(set1, set2); + } + + for (it2 = overlap[set2].begin(); + it2 != overlap[set2].end(); ++it2) { + it1 = overlap[set1].find(it2->first); + if (it1 == overlap[set1].end()) { + overlap[set1].insert(pair + (it2->first, it2->second)); + } else { + it1->second += it2->second; + } + } + overlap[set2].clear(); + } // end link + } // end while + + /* Return items */ + double classerr, randIndex; + if (nPairNorm > 0) { + loss /= nPairNorm; + } else { + loss = 0; + } + + // std::cout << "nPairIncorrect: " << nPairIncorrect << std::endl; + // std::cout << "nPairNorm: " << nPairNorm << std::endl; + + *loss_out = loss; + classerr = static_cast(nPairIncorrect) + / static_cast(nPairNorm); + *classerr_out = classerr; + randIndex = 1.0 - static_cast(nPairIncorrect) + / static_cast(nPairNorm); + *rand_index_out = randIndex; +} + + +template +void MalisLossLayer::LayerSetUp(const vector*>& bottom, + const vector*>& top) { + LossLayer::LayerSetUp(bottom, top); + + // Expected inputs: + // Required (bottom 0 to 2): + // Bottom 0: Predicted affinity, shaped (batch size, #edges, (Z), (Y), X) + // Bottom 1: Ground truth affinity, shaped (batch size, #edges, (Z), (Y), X) + // Bottom 2: Segmented ground truth, shaped (batch size, 1, (Z), (Y), X) + + // Optional (bottom 3): + // Bottom 3: Edge connectivity, size #edges * 3, shaped (Z,Y,X);(Z,Y,X);... + // (this means pairs of 3 per edge) +} + +template +void MalisLossLayer::Reshape(const vector*>& bottom, + const vector*>& top) { + LossLayer::Reshape(bottom, top); + + if (top.size() >= 2) { + top[1]->ReshapeLike(*bottom[0]); + } + + // Up to 5 dimensional; supported modes: + // batch, channels (edges), Z, Y, X => 3D affinity + // batch, channels (edges), Y, X => 2D affinity + // batch, channels (edges), X => 1D affinity + vector shape = bottom[0]->shape(); + + conn_dims_.clear(); + nhood_dims_.clear(); + + // #edges, Z, Y, X specification (4 dimensions) + conn_num_dims_ = 4; + + // Channel axis equals number of edges + nedges_ = shape[1]; + + // #edges + conn_dims_.push_back(nedges_); + // Z-axis + conn_dims_.push_back(shape.size() >= 5 ? shape[shape.size() - 3] : 1); + // Y-axis + conn_dims_.push_back(shape.size() >= 4 ? shape[shape.size() - 2] : 1); + // X-axis + conn_dims_.push_back(shape.size() >= 3 ? shape[shape.size() - 1] : 1); + + // #edges + nhood_dims_.push_back(nedges_); + // 3 dimensional (always, to simplify things; + // can just set unused spatials to 0) + nhood_dims_.push_back(3); + + affinity_pos_.Reshape(shape); + affinity_neg_.Reshape(shape); + dloss_pos_.Reshape(shape); + dloss_neg_.Reshape(shape); +} + +template +void MalisLossLayer::Forward_cpu(const vector*>& bottom, + const vector*>& top) { + // Set up the neighborhood + nhood_data_.clear(); + if (bottom.size() == 4) { + // Custom edges + for (int_tp i = 0; i < nedges_; ++i) { + // Z edge direction + nhood_data_.push_back(bottom[3]->cpu_data()[i * 3 + 0]); + // Y edge direction + nhood_data_.push_back(bottom[3]->cpu_data()[i * 3 + 1]); + // X edge direction + nhood_data_.push_back(bottom[3]->cpu_data()[i * 3 + 2]); + } + } else { + // Dimension primary edges (+Z, +Y, +X) only: + // 1 edge: +X (0,0,1) + // 2 edges: +Y, +X (0,1,0); (0,0,1) + // 3 edges: +Z, +Y, +X (1,0,0); (0,1,0); (0,0,1) + for (int_tp i = 3 - nedges_; i < 3; ++i) { + nhood_data_.push_back((i + 3) % 3 == 0 ? 1 : 0); + nhood_data_.push_back((i + 2) % 3 == 0 ? 1 : 0); + nhood_data_.push_back((i + 1) % 3 == 0 ? 1 : 0); + } + } + + // Predicted affinity + const Dtype* affinity_prob = bottom[0]->cpu_data(); + + // Effective affinity + const Dtype* affinity = bottom[1]->cpu_data(); + + Dtype* affinity_data_pos = affinity_pos_.mutable_cpu_data(); + Dtype* affinity_data_neg = affinity_neg_.mutable_cpu_data(); + +// Affinity graph must be in the range (0,1) +// square loss (euclidean) is used by MALIS +#pragma omp parallel for + for (int_tp i = 0; i < bottom[0]->count(); ++i) { + affinity_data_pos[i] = std::min(affinity_prob[i], affinity[i]); + affinity_data_neg[i] = std::max(affinity_prob[i], affinity[i]); + } + + uint_tp batch_offset = 1; + for (int_tp i = 1; i < bottom[0]->shape().size(); ++i) { + batch_offset *= bottom[0]->shape()[i]; + } + + Dtype loss = 0; + +#pragma omp parallel for reduction(+:loss) + for (int_tp batch = 0; batch < bottom[0]->shape()[0]; ++batch) { + Dtype loss_out = 0; + Dtype classerr_out = 0; + Dtype rand_index_out = 0; + + caffe_set(dloss_neg_.count(), Dtype(0.0), dloss_neg_.mutable_cpu_data()); + caffe_set(dloss_pos_.count(), Dtype(0.0), dloss_pos_.mutable_cpu_data()); + + Malis(&affinity_data_neg[batch_offset * batch], conn_num_dims_, + &conn_dims_[0], &nhood_data_[0], &nhood_dims_[0], + bottom[2]->cpu_data() + batch_offset * batch, false, + dloss_neg_.mutable_cpu_data() + batch_offset * batch, &loss_out, + &classerr_out, &rand_index_out); + + loss += 0.5 * loss_out; + // std::cout << "NEG: " << loss_out << std::endl; + + Malis(&affinity_data_pos[batch_offset * batch], conn_num_dims_, + &conn_dims_[0], &nhood_data_[0], &nhood_dims_[0], + bottom[2]->cpu_data() + batch_offset * batch, true, + dloss_pos_.mutable_cpu_data() + batch_offset * batch, &loss_out, + &classerr_out, &rand_index_out); + + loss += 0.5 * loss_out; + // std::cout << "POS: " << loss_out << std::endl; + } + + // Normalized loss over batch size + top[0]->mutable_cpu_data()[0] = loss + / (static_cast(bottom[0]->shape()[0])); + + if (top.size() == 2) { + top[1]->ShareData(*(bottom[0])); + } +} + +template +void MalisLossLayer::Backward_cpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom) { + if (propagate_down[0]) { + Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); + const Dtype* dloss_pos_data = dloss_pos_.cpu_data(); + const Dtype* dloss_neg_data = dloss_neg_.cpu_data(); + + // Clear the diff + caffe_set(bottom[0]->count(), Dtype(0.0), bottom_diff); + +#pragma omp parallel for + for (int_tp i = 0; i < bottom[0]->count(); ++i) { + bottom_diff[i] = -(dloss_neg_data[i] + dloss_pos_data[i]) / 2.0; + } + } +} + +INSTANTIATE_CLASS(MalisLossLayer); +REGISTER_LAYER_CLASS(MalisLoss); + +} // namespace caffe diff --git a/src/caffe/layers/memory_data_layer.cpp b/src/caffe/layers/memory_data_layer.cpp index 82909874054..00161d25fc8 100644 --- a/src/caffe/layers/memory_data_layer.cpp +++ b/src/caffe/layers/memory_data_layer.cpp @@ -8,43 +8,64 @@ namespace caffe { -template +template void MemoryDataLayer::DataLayerSetUp(const vector*>& bottom, - const vector*>& top) { - batch_size_ = this->layer_param_.memory_data_param().batch_size(); - channels_ = this->layer_param_.memory_data_param().channels(); - height_ = this->layer_param_.memory_data_param().height(); - width_ = this->layer_param_.memory_data_param().width(); - size_ = channels_ * height_ * width_; - CHECK_GT(batch_size_ * size_, 0) << - "batch_size, channels, height, and width must be specified and" - " positive in memory_data_param"; - vector label_shape(1, batch_size_); - top[0]->Reshape(batch_size_, channels_, height_, width_); - top[1]->Reshape(label_shape); - added_data_.Reshape(batch_size_, channels_, height_, width_); - added_label_.Reshape(label_shape); + const vector*>& top) { + MemoryDataParameter mem_param = this->layer_param_.memory_data_param(); + + // Old 4D (2D spatial) parameters + shape_.clear(); + shape_.push_back(mem_param.batch_size()); + shape_.push_back(mem_param.channels()); + shape_.push_back(mem_param.height()); + shape_.push_back(mem_param.width()); + + // New ND parameters + if (mem_param.dim_size() > 0) { + shape_.clear(); + for (int_tp i = 0; i < mem_param.dim_size(); ++i) { + shape_.push_back(mem_param.dim(i)); + } + } + + // Labels have shape batch_size, 1, 1, ..., 1 + label_shape_.push_back(shape_[0]); + size_ = 1; + // All sizes except the batch index + for (int_tp i = 1; i < shape_.size(); ++i) { + size_ *= shape_[i]; + label_shape_.push_back(1); + } + + top[0]->Reshape(shape_); + top[1]->Reshape(label_shape_); + added_data_.Reshape(shape_); + added_label_.Reshape(label_shape_); data_ = NULL; labels_ = NULL; added_data_.cpu_data(); added_label_.cpu_data(); } -template +template void MemoryDataLayer::AddDatumVector(const vector& datum_vector) { CHECK(!has_new_data_) << - "Can't add data until current data has been consumed."; - size_t num = datum_vector.size(); - CHECK_GT(num, 0) << "There is no datum to add."; - CHECK_EQ(num % batch_size_, 0) << - "The added data must be a multiple of the batch size."; - added_data_.Reshape(num, channels_, height_, width_); - added_label_.Reshape(num, 1, 1, 1); + "Can't add data until current data has been consumed."; + uint_tp num = datum_vector.size(); + CHECK_GT(num, 0)<< "There is no datum to add."; + CHECK_EQ(num % shape_[0], 0)<< + "The added data must be a multiple of the batch size."; + vector added_shape = shape_; + added_shape[0] = num; + added_data_.Reshape(added_shape); + vector added_label_shape = label_shape_; + added_label_shape[0] = num; + added_label_.Reshape(added_label_shape); // Apply data transformations (mirror, scale, crop...) this->data_transformer_->Transform(datum_vector, &added_data_); // Copy Labels Dtype* top_label = added_label_.mutable_cpu_data(); - for (int item_id = 0; item_id < num; ++item_id) { + for (int_tp item_id = 0; item_id < num; ++item_id) { top_label[item_id] = datum_vector[item_id].label(); } // num_images == batch_size_ @@ -56,20 +77,24 @@ void MemoryDataLayer::AddDatumVector(const vector& datum_vector) { #ifdef USE_OPENCV template void MemoryDataLayer::AddMatVector(const vector& mat_vector, - const vector& labels) { - size_t num = mat_vector.size(); + const vector& labels) { + uint_tp num = mat_vector.size(); CHECK(!has_new_data_) << - "Can't add mat until current data has been consumed."; + "Can't add mat until current data has been consumed."; CHECK_GT(num, 0) << "There is no mat to add"; - CHECK_EQ(num % batch_size_, 0) << - "The added data must be a multiple of the batch size."; - added_data_.Reshape(num, channels_, height_, width_); - added_label_.Reshape(num, 1, 1, 1); + CHECK_EQ(num % shape_[0], 0) << + "The added data must be a multiple of the batch size."; + vector added_shape = shape_; + added_shape[0] = num; + added_data_.Reshape(added_shape); + vector added_label_shape = label_shape_; + added_label_shape[0] = num; + added_label_.Reshape(added_label_shape); // Apply data transformations (mirror, scale, crop...) this->data_transformer_->Transform(mat_vector, &added_data_); // Copy Labels Dtype* top_label = added_label_.mutable_cpu_data(); - for (int item_id = 0; item_id < num; ++item_id) { + for (int_tp item_id = 0; item_id < num; ++item_id) { top_label[item_id] = labels[item_id]; } // num_images == batch_size_ @@ -79,15 +104,15 @@ void MemoryDataLayer::AddMatVector(const vector& mat_vector, } #endif // USE_OPENCV -template -void MemoryDataLayer::Reset(Dtype* data, Dtype* labels, int n) { +template +void MemoryDataLayer::Reset(Dtype* data, Dtype* labels, int_tp n) { CHECK(data); CHECK(labels); - CHECK_EQ(n % batch_size_, 0) << "n must be a multiple of batch size"; + CHECK_EQ(n % shape_[0], 0)<< "n must be a multiple of batch size"; // Warn with transformation parameters since a memory array is meant to // be generic and no transformations are done with Reset(). if (this->layer_param_.has_transform_param()) { - LOG(WARNING) << this->type() << " does not transform array data on Reset()"; + LOG(WARNING)<< this->type() << " does not transform array data on Reset()"; } data_ = data; labels_ = labels; @@ -95,26 +120,28 @@ void MemoryDataLayer::Reset(Dtype* data, Dtype* labels, int n) { pos_ = 0; } -template -void MemoryDataLayer::set_batch_size(int new_size) { +template +void MemoryDataLayer::set_batch_size(int_tp new_size) { CHECK(!has_new_data_) << - "Can't change batch_size until current data has been consumed."; - batch_size_ = new_size; - added_data_.Reshape(batch_size_, channels_, height_, width_); - added_label_.Reshape(batch_size_, 1, 1, 1); + "Can't change batch_size until current data has been consumed."; + shape_[0] = new_size; + label_shape_[0] = new_size; + added_data_.Reshape(shape_); + added_label_.Reshape(label_shape_); } -template +template void MemoryDataLayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { CHECK(data_) << "MemoryDataLayer needs to be initalized by calling Reset"; - top[0]->Reshape(batch_size_, channels_, height_, width_); - top[1]->Reshape(batch_size_, 1, 1, 1); + top[0]->Reshape(shape_); + top[1]->Reshape(label_shape_); top[0]->set_cpu_data(data_ + pos_ * size_); top[1]->set_cpu_data(labels_ + pos_); - pos_ = (pos_ + batch_size_) % n_; - if (pos_ == 0) + pos_ = (pos_ + shape_[0]) % n_; + if (pos_ == 0) { has_new_data_ = false; + } } INSTANTIATE_CLASS(MemoryDataLayer); diff --git a/src/caffe/layers/mergecrop_layer.cpp b/src/caffe/layers/mergecrop_layer.cpp new file mode 100644 index 00000000000..a0426b444d7 --- /dev/null +++ b/src/caffe/layers/mergecrop_layer.cpp @@ -0,0 +1,81 @@ +#include + +#include "caffe/layer.hpp" +#include "caffe/layers/mergecrop_layer.hpp" +#include "caffe/util/math_functions.hpp" + +namespace caffe { + +template +void MergeCropLayer::LayerSetUp(const vector*>& bottom, + const vector*>& top) { + // By default, forward both a and b + forward_.push_back(1); + forward_.push_back(1); + + // By default, backward a and do not backward b + backward_.push_back(1); + backward_.push_back(0); + + + if (this->layer_param_.has_mergecrop_param()) { + MergeCropParameter mergecrop_param = this->layer_param_.mergecrop_param(); + for (int_tp i = 0; i < mergecrop_param.forward_size(); ++i) { + forward_[i] = mergecrop_param.forward(i); + } + for (int_tp i = 0; i < mergecrop_param.backward_size(); ++i) { + backward_[i] = mergecrop_param.backward(i); + } + } + + Reshape(bottom, top); +} + +template +void MergeCropLayer::Reshape(const vector*>& bottom, + const vector*>& top) { + // Same number of batches requires + CHECK_EQ(bottom[0]->shape(0), bottom[1]->shape(0)); + + // All channels of both inputs are copied + int_tp channels = bottom[0]->shape(1) + bottom[1]->shape(1); + + // Spatial of the smaller input, which should be input 0 + vector top_shape = bottom[0]->shape(); + top_shape[1] = channels; + + top[0]->Reshape(top_shape); + + shape_a_.Reshape(1, 1, 1, top_shape.size() - 2); + shape_b_.Reshape(1, 1, 1, top_shape.size() - 2); + + int_tp* shape_a_data = shape_a_.mutable_cpu_data(); + int_tp* shape_b_data = shape_b_.mutable_cpu_data(); + + for (int_tp i = 0; i < top_shape.size() - 2; ++i) { + shape_a_data[i] = bottom[0]->shape()[i + 2]; + shape_b_data[i] = bottom[1]->shape()[i + 2]; + } +} + +template +void MergeCropLayer::Forward_cpu(const vector*>& bottom, + const vector*>& top) { + LOG(FATAL)<< "Foward_cpu() not implemented for MergeCropLayer."; +} + +template +void MergeCropLayer::Backward_cpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom) { + LOG(FATAL)<< "Backward_cpu() not implemented for MergeCropLayer."; +} + +#ifdef CPU_ONLY +STUB_GPU(MergeCropLayer); +#endif + +INSTANTIATE_CLASS(MergeCropLayer); +REGISTER_LAYER_CLASS(MergeCrop); + +} // namespace caffe diff --git a/src/caffe/layers/mergecrop_layer.cu b/src/caffe/layers/mergecrop_layer.cu new file mode 100644 index 00000000000..0f1e349733e --- /dev/null +++ b/src/caffe/layers/mergecrop_layer.cu @@ -0,0 +1,218 @@ +#include + +#include "caffe/layer.hpp" +#include "caffe/layers/mergecrop_layer.hpp" +#include "caffe/util/math_functions.hpp" + +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + +namespace caffe { + +#ifdef USE_CUDA +template +__global__ void CopyForward(const int_tp nthreads, const int_tp dims, + const Dtype* bottom_a, const bool forward_a, + const Dtype* bottom_b, const bool forward_b, + Dtype* top, const int_tp num, + const int_tp channels_a, const int_tp channels_b, + const int_tp* shape_a, const int_tp* shape_b) { + int_tp pad[6]; // NOLINT(runtime/arrays) + int_tp tmp_idx[6]; // NOLINT(runtime/arrays) + int_tp size_a = 1; + int_tp size_b = 1; + + for (int_tp i = 0; i < dims; ++i) { + pad[i] = (shape_b[i] - shape_a[i]) / 2; + size_a *= shape_a[i]; + size_b *= shape_b[i]; + } + + CUDA_KERNEL_LOOP(index, nthreads) { + int_tp batch_id = index / ((channels_a + channels_b) * size_a); + int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a) + / (channels_a * size_a)) % 2; + int_tp counter = index; + for (int_tp i = dims - 1; i >= 0; --i) { + tmp_idx[i] = counter % shape_a[i]; + counter /= shape_a[i]; + } + + if (bottom_id == 0) { + int_tp channel_id = (index / size_a) % channels_a; + int_tp aidx = batch_id * channels_a + channel_id; + for (int_tp i = 0; i < dims; ++i) { + aidx *= shape_a[i]; + aidx += tmp_idx[i]; + } + top[index] = forward_a ? bottom_a[aidx] : 0; + } else { + int_tp channel_id = (index / size_a) % channels_b; + int_tp bidx = (batch_id * channels_b + channel_id) * size_b; + int_tp btemp = 1; + for (int_tp i = dims - 1; i >= 0; --i) { + bidx += btemp * (tmp_idx[i] + pad[i]); + btemp *= shape_b[i]; + } + top[index] = forward_b ? bottom_b[bidx] : 0; + } + } +} + +template +__global__ void CopyBackward(const int_tp nthreads, const int_tp dims, + Dtype* bottom_a, const bool backward_a, + Dtype* bottom_b, const bool backward_b, + const Dtype* top, const int_tp num, + const int_tp channels_a, const int_tp channels_b, + const int_tp* shape_a, const int_tp* shape_b) { + int_tp pad[6]; // NOLINT(runtime/arrays) + int_tp tmp_idx[6]; // NOLINT(runtime/arrays) + int_tp size_a = 1; + int_tp size_b = 1; + + for (int_tp i = 0; i < dims; ++i) { + pad[i] = (shape_b[i] - shape_a[i]) / 2; + size_a *= shape_a[i]; + size_b *= shape_b[i]; + } + + CUDA_KERNEL_LOOP(index, nthreads) { + int_tp batch_id = index / ((channels_a + channels_b) * size_a); + int_tp bottom_id = ((index - batch_id * (channels_a + channels_b) * size_a) + / (channels_a * size_a)) % 2; + int_tp counter = index; + for (int_tp i = dims - 1; i >= 0; --i) { + tmp_idx[i] = counter % shape_a[i]; + counter /= shape_a[i]; + } + + if (bottom_id == 0) { + int_tp channel_id = (index / size_a) % channels_a; + int_tp aidx = batch_id * channels_a + channel_id; + for (int_tp i = 0; i < dims; ++i) { + aidx *= shape_a[i]; + aidx += tmp_idx[i]; + } + bottom_a[aidx] = backward_a ? top[index] : 0; + } else { + int_tp channel_id = (index / size_a) % channels_b; + int_tp bidx = (batch_id * channels_b + channel_id) * size_b; + int_tp btemp = 1; + for (int_tp i = dims - 1; i >= 0; --i) { + bidx += btemp * (tmp_idx[i] + pad[i]); + btemp *= shape_b[i]; + } + bottom_b[bidx] = backward_b ? top[index] : 0; + } + } +} +#endif // USE_CUDA + +template +void MergeCropLayer::Forward_gpu(const vector*>& bottom, + const vector*>& top) { + int_tp count = top[0]->count(); + + const Dtype* bottom_data_a = bottom[0]->gpu_data(); + const Dtype* bottom_data_b = bottom[1]->gpu_data(); + Dtype* top_data = top[0]->mutable_gpu_data(); + + int_tp num = bottom[0]->shape(0); + int_tp spatial_dims = bottom[0]->shape().size() - 2; + + // All channels of both inputs are copied + int_tp channels_a = bottom[0]->shape(1); + int_tp channels_b = bottom[1]->shape(1); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + CopyForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS) ( + count, spatial_dims, bottom_data_a, + forward_[0], bottom_data_b, + forward_[1], top_data, num, channels_a, + channels_b, shape_a_.gpu_data(), shape_b_.gpu_data()); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_copy_forward = program.get_kernel( + CL_KERNEL_SELECT("merge_copy_forward")); + viennacl::ocl::enqueue( + oclk_copy_forward(count, spatial_dims, + WrapHandle((cl_mem) bottom_data_a, &ctx), forward_[0], + WrapHandle((cl_mem) bottom_data_b, &ctx), forward_[1], + WrapHandle((cl_mem) top_data, &ctx), num, channels_a, + channels_b, + WrapHandle((cl_mem) (shape_a_.gpu_data()), &ctx), + WrapHandle((cl_mem) (shape_b_.gpu_data()), &ctx)), + ctx.get_queue()); + ctx.get_queue().finish(); +#endif // USE_GREENTEA + } +} + +template +void MergeCropLayer::Backward_gpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom) { + if (!propagate_down[0]) { + return; + } + + int_tp count = top[0]->count(); + + Dtype* bottom_diff_a = bottom[0]->mutable_gpu_diff(); + Dtype* bottom_diff_b = bottom[1]->mutable_gpu_diff(); + const Dtype* top_diff = top[0]->gpu_diff(); + + int_tp num = bottom[0]->shape(0); + int_tp spatial_dims = bottom[0]->shape().size() - 2; + + // All channels of both inputs are copied + int_tp channels_a = bottom[0]->shape(1); + int_tp channels_b = bottom[1]->shape(1); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + CopyBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS) ( + count, spatial_dims, bottom_diff_a, backward_[0], + bottom_diff_b, backward_[1], top_diff, num, + channels_a, channels_b, shape_a_.gpu_data(), shape_b_.gpu_data()); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_copy_backward = program.get_kernel( + CL_KERNEL_SELECT("merge_copy_backward")); + viennacl::ocl::enqueue( + oclk_copy_backward(count, spatial_dims, + WrapHandle((cl_mem) bottom_diff_a, &ctx), + backward_[0], + WrapHandle((cl_mem) bottom_diff_b, &ctx), + backward_[1], WrapHandle((cl_mem) top_diff, &ctx), + num, channels_a, channels_b, + WrapHandle((cl_mem) (shape_a_.gpu_data()), &ctx), + WrapHandle((cl_mem) (shape_b_.gpu_data()), &ctx)), + ctx.get_queue()); + ctx.get_queue().finish(); + +#endif // USE_GREENTEA + } +} + +INSTANTIATE_LAYER_GPU_FUNCS(MergeCropLayer); + +} // namespace caffe diff --git a/src/caffe/layers/multinomial_logistic_loss_layer.cpp b/src/caffe/layers/multinomial_logistic_loss_layer.cpp index 65664998d2c..e37561d8a88 100644 --- a/src/caffe/layers/multinomial_logistic_loss_layer.cpp +++ b/src/caffe/layers/multinomial_logistic_loss_layer.cpp @@ -21,11 +21,11 @@ void MultinomialLogisticLossLayer::Forward_cpu( const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* bottom_label = bottom[1]->cpu_data(); - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); + int_tp num = bottom[0]->num(); + int_tp dim = bottom[0]->count() / bottom[0]->num(); Dtype loss = 0; - for (int i = 0; i < num; ++i) { - int label = static_cast(bottom_label[i]); + for (int_tp i = 0; i < num; ++i) { + int_tp label = static_cast(bottom_label[i]); Dtype prob = std::max( bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD)); loss -= log(prob); @@ -45,12 +45,12 @@ void MultinomialLogisticLossLayer::Backward_cpu( const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* bottom_label = bottom[1]->cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - int num = bottom[0]->num(); - int dim = bottom[0]->count() / bottom[0]->num(); + int_tp num = bottom[0]->num(); + int_tp dim = bottom[0]->count() / bottom[0]->num(); caffe_set(bottom[0]->count(), Dtype(0), bottom_diff); const Dtype scale = - top[0]->cpu_diff()[0] / num; - for (int i = 0; i < num; ++i) { - int label = static_cast(bottom_label[i]); + for (int_tp i = 0; i < num; ++i) { + int_tp label = static_cast(bottom_label[i]); Dtype prob = std::max( bottom_data[i * dim + label], Dtype(kLOG_THRESHOLD)); bottom_diff[i * dim + label] = scale / prob; diff --git a/src/caffe/layers/mvn_layer.cpp b/src/caffe/layers/mvn_layer.cpp index 8fe4ef8c0a8..b8ee3ea2df9 100644 --- a/src/caffe/layers/mvn_layer.cpp +++ b/src/caffe/layers/mvn_layer.cpp @@ -32,13 +32,13 @@ void MVNLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - int num; + int_tp num; if (this->layer_param_.mvn_param().across_channels()) num = bottom[0]->num(); else num = bottom[0]->num() * bottom[0]->channels(); - int dim = bottom[0]->count() / num; + int_tp dim = bottom[0]->count() / num; // subtract mean caffe_cpu_gemv(CblasNoTrans, num, dim, 1. / dim, bottom_data, @@ -79,13 +79,13 @@ void MVNLayer::Backward_cpu(const vector*>& top, const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - int num; + int_tp num; if (this->layer_param_.mvn_param().across_channels()) num = bottom[0]->num(); else num = bottom[0]->num() * bottom[0]->channels(); - int dim = bottom[0]->count() / num; + int_tp dim = bottom[0]->count() / num; if (this->layer_param_.mvn_param().normalize_variance()) { caffe_mul(temp_.count(), top_data, top_diff, bottom_diff); diff --git a/src/caffe/layers/mvn_layer.cu b/src/caffe/layers/mvn_layer.cu index 739293be00e..f3efa0cfbf7 100644 --- a/src/caffe/layers/mvn_layer.cu +++ b/src/caffe/layers/mvn_layer.cu @@ -5,106 +5,233 @@ namespace caffe { -template +template void MVNLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - int num; + int_tp num; if (this->layer_param_.mvn_param().across_channels()) num = bottom[0]->num(); else num = bottom[0]->num() * bottom[0]->channels(); - int dim = bottom[0]->count() / num; + int_tp dim = bottom[0]->count() / num; - // subtract mean - caffe_gpu_gemv(CblasNoTrans, num, dim, 1. / dim, bottom_data, - sum_multiplier_.gpu_data(), 0., mean_.mutable_gpu_data()); // EX - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, -1., - mean_.gpu_data(), sum_multiplier_.gpu_data(), 0., - temp_.mutable_gpu_data()); - caffe_gpu_add(temp_.count(), bottom_data, temp_.gpu_data(), - top_data); // X-EX - - if (this->layer_param_.mvn_param().normalize_variance()) { - // compute variance using var(X) = E((X-EX)^2) - caffe_gpu_powx(bottom[0]->count(), top_data, Dtype(2), - temp_.mutable_gpu_data()); // (X-EX)^2 - caffe_gpu_gemv(CblasNoTrans, num, dim, 1. / dim, temp_.gpu_data(), - sum_multiplier_.gpu_data(), 0., - variance_.mutable_gpu_data()); // E((X-EX)^2) - - // normalize variance - caffe_gpu_powx(variance_.count(), variance_.gpu_data(), Dtype(0.5), - variance_.mutable_gpu_data()); - - caffe_gpu_add_scalar(variance_.count(), eps_, variance_.mutable_gpu_data()); - - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., - variance_.gpu_data(), sum_multiplier_.gpu_data(), 0., - temp_.mutable_gpu_data()); - - caffe_gpu_div(temp_.count(), top_data, temp_.gpu_data(), top_data); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // subtract mean + caffe_gpu_gemv(CblasNoTrans, num, dim, 1. / dim, bottom_data, + sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); // EX + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, -1., + mean_.gpu_data(), sum_multiplier_.gpu_data(), 0., + temp_.mutable_gpu_data()); + // X-EX + caffe_gpu_add(temp_.count(), bottom_data, temp_.gpu_data(), top_data); + + if (this->layer_param_.mvn_param().normalize_variance()) { + // compute variance using var(X) = E((X-EX)^2) + caffe_gpu_powx(bottom[0]->count(), top_data, Dtype(2), + temp_.mutable_gpu_data()); // (X-EX)^2 + caffe_gpu_gemv(CblasNoTrans, num, dim, 1. / dim, temp_.gpu_data(), + sum_multiplier_.gpu_data(), 0., + variance_.mutable_gpu_data()); // E((X-EX)^2) + + // normalize variance + caffe_gpu_powx(variance_.count(), variance_.gpu_data(), Dtype(0.5), + variance_.mutable_gpu_data()); + + caffe_gpu_add_scalar(variance_.count(), eps_, + variance_.mutable_gpu_data()); + + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., + variance_.gpu_data(), sum_multiplier_.gpu_data(), + 0., temp_.mutable_gpu_data()); + + caffe_gpu_div(temp_.count(), top_data, temp_.gpu_data(), top_data); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + // subtract mean + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, num, dim, + 1. / dim, (cl_mem) (bottom_data), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (mean_.mutable_gpu_data()), 0); // EX + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num, dim, 1, -1., (cl_mem) (mean_.gpu_data()), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (temp_.mutable_gpu_data()), 0); + greentea_gpu_add(this->device_->id(), temp_.count(), + (cl_mem) (bottom_data), 0, + (cl_mem) (temp_.gpu_data()), 0, (cl_mem) (top_data), + 0); // X-EX + + if (this->layer_param_.mvn_param().normalize_variance()) { + // compute variance using var(X) = E((X-EX)^2) + // (X-EX)^2 + greentea_gpu_powx(this->device_->id(), bottom[0]->count(), + (cl_mem) (top_data), 0, Dtype(2), + (cl_mem) (temp_.mutable_gpu_data()), 0); + // E((X-EX)^2) + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, num, dim, + 1. / dim, (cl_mem) (temp_.gpu_data()), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (variance_.mutable_gpu_data()), 0); + + // normalize variance + greentea_gpu_powx(this->device_->id(), variance_.count(), + (cl_mem) (variance_.gpu_data()), 0, Dtype(0.5), + (cl_mem) (variance_.mutable_gpu_data()), 0); + + greentea_gpu_add_scalar(this->device_->id(), variance_.count(), + eps_, + (cl_mem) (variance_.mutable_gpu_data()), + 0); + + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, CblasNoTrans, + num, dim, 1, 1., (cl_mem) (variance_.gpu_data()), + 0, (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (temp_.mutable_gpu_data()), 0); + + greentea_gpu_div(this->device_->id(), temp_.count(), + (cl_mem) (top_data), 0, + (cl_mem) (temp_.gpu_data()), 0, + (cl_mem) (top_data), 0); + } +#endif // USE_GREENTEA } } -template +template void MVNLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* top_diff = top[0]->gpu_diff(); const Dtype* top_data = top[0]->gpu_data(); const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - int num; + int_tp num; if (this->layer_param_.mvn_param().across_channels()) num = bottom[0]->num(); else num = bottom[0]->num() * bottom[0]->channels(); - int dim = bottom[0]->count() / num; - - if (this->layer_param_.mvn_param().normalize_variance()) { - caffe_gpu_mul(temp_.count(), top_data, top_diff, bottom_diff); - caffe_gpu_gemv(CblasNoTrans, num, dim, 1., bottom_diff, - sum_multiplier_.gpu_data(), 0., mean_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., - mean_.gpu_data(), sum_multiplier_.gpu_data(), 0., - bottom_diff); - caffe_gpu_mul(temp_.count(), top_data, bottom_diff, bottom_diff); - - caffe_gpu_gemv(CblasNoTrans, num, dim, 1., top_diff, - sum_multiplier_.gpu_data(), 0., mean_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., - mean_.gpu_data(), sum_multiplier_.gpu_data(), 1., - bottom_diff); - - caffe_gpu_axpby(temp_.count(), Dtype(1), top_diff, Dtype(-1. / dim), - bottom_diff); - - // put the squares of bottom into temp_ - caffe_gpu_powx(temp_.count(), bottom_data, Dtype(2), - temp_.mutable_gpu_data()); - - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., - variance_.gpu_data(), sum_multiplier_.gpu_data(), 0., - temp_.mutable_gpu_data()); - - caffe_gpu_div(temp_.count(), bottom_diff, temp_.gpu_data(), bottom_diff); + int_tp dim = bottom[0]->count() / num; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (this->layer_param_.mvn_param().normalize_variance()) { + caffe_gpu_mul(temp_.count(), top_data, top_diff, bottom_diff); + caffe_gpu_gemv(CblasNoTrans, num, dim, 1., bottom_diff, + sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., + mean_.gpu_data(), sum_multiplier_.gpu_data(), 0., + bottom_diff); + caffe_gpu_mul(temp_.count(), top_data, bottom_diff, bottom_diff); + + caffe_gpu_gemv(CblasNoTrans, num, dim, 1., top_diff, + sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., + mean_.gpu_data(), sum_multiplier_.gpu_data(), 1., + bottom_diff); + + caffe_gpu_axpby(temp_.count(), Dtype(1), top_diff, Dtype(-1. / dim), + bottom_diff); + + // put the squares of bottom into temp_ + caffe_gpu_powx(temp_.count(), bottom_data, Dtype(2), + temp_.mutable_gpu_data()); + + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, 1., + variance_.gpu_data(), sum_multiplier_.gpu_data(), + 0., temp_.mutable_gpu_data()); + + caffe_gpu_div(temp_.count(), bottom_diff, temp_.gpu_data(), bottom_diff); + } else { + caffe_gpu_gemv(CblasNoTrans, num, dim, 1. / dim, top_diff, + sum_multiplier_.gpu_data(), 0., + mean_.mutable_gpu_data()); + caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, -1., + mean_.gpu_data(), sum_multiplier_.gpu_data(), 0., + temp_.mutable_gpu_data()); + caffe_gpu_add(temp_.count(), top_diff, temp_.gpu_data(), + bottom_diff); + } +#endif // USE_CUDA } else { - caffe_gpu_gemv(CblasNoTrans, num, dim, 1. / dim, top_diff, - sum_multiplier_.gpu_data(), 0., mean_.mutable_gpu_data()); - caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, num, dim, 1, -1., - mean_.gpu_data(), sum_multiplier_.gpu_data(), 0., - temp_.mutable_gpu_data()); - caffe_gpu_add(temp_.count(), top_diff, temp_.gpu_data(), bottom_diff); +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (this->layer_param_.mvn_param().normalize_variance()) { + greentea_gpu_mul(this->device_->id(), temp_.count(), + (cl_mem) top_data, 0, (cl_mem) top_diff, 0, + (cl_mem) bottom_diff, 0); + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, num, + dim, 1., (cl_mem) bottom_diff, 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (mean_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, num, dim, 1, 1., + (cl_mem) (mean_.gpu_data()), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) bottom_diff, 0); + greentea_gpu_mul(this->device_->id(), temp_.count(), + (cl_mem) top_data, 0, (cl_mem) bottom_diff, 0, + (cl_mem) bottom_diff, 0); + + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, num, + dim, 1., (cl_mem) top_diff, 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (mean_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, num, dim, 1, 1., + (cl_mem) (mean_.gpu_data()), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 1., + (cl_mem) bottom_diff, 0); + + greentea_gpu_axpby(this->device_->id(), temp_.count(), + Dtype(1), (cl_mem) top_diff, 0, + Dtype(-1. / dim), (cl_mem) bottom_diff, 0); + + // put the squares of bottom into temp_ + greentea_gpu_powx(this->device_->id(), temp_.count(), + (cl_mem) bottom_data, 0, Dtype(2), + (cl_mem) (temp_.mutable_gpu_data()), 0); + + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, num, dim, 1, 1., + (cl_mem) (variance_.gpu_data()), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (temp_.mutable_gpu_data()), 0); + + greentea_gpu_div(this->device_->id(), temp_.count(), + (cl_mem) bottom_diff, 0, + (cl_mem) (temp_.gpu_data()), 0, + (cl_mem) bottom_diff, 0); + } else { + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, num, + dim, 1. / dim, (cl_mem) top_diff, 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (mean_.mutable_gpu_data()), 0); + greentea_gpu_gemm(this->device_->id(), CblasNoTrans, + CblasNoTrans, num, dim, 1, -1., + (cl_mem) (mean_.gpu_data()), 0, + (cl_mem) (sum_multiplier_.gpu_data()), 0, 0., + (cl_mem) (temp_.mutable_gpu_data()), 0); + greentea_gpu_add(this->device_->id(), temp_.count(), + (cl_mem) top_diff, 0, (cl_mem) (temp_.gpu_data()), + 0, (cl_mem) (bottom_diff), 0); + } +#endif // USE_GREENTEA } } - INSTANTIATE_LAYER_GPU_FUNCS(MVNLayer); - } // namespace caffe diff --git a/src/caffe/layers/pooling_layer.cpp b/src/caffe/layers/pooling_layer.cpp index 90897db0f45..71a37737066 100644 --- a/src/caffe/layers/pooling_layer.cpp +++ b/src/caffe/layers/pooling_layer.cpp @@ -10,129 +10,241 @@ namespace caffe { using std::min; using std::max; -template +template void PoolingLayer::LayerSetUp(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { PoolingParameter pool_param = this->layer_param_.pooling_param(); + + // Set the max number of top blobs before calling base Layer::SetUp. + // If doing MAX pooling, we can optionally output an extra top Blob + // for the mask. Otherwise, we only have one top Blob. + if (pool_param.pool() == PoolingParameter_PoolMethod_MAX) { + max_top_blobs_ = 2; + } else { + max_top_blobs_ = 1; + } + + channel_axis_ = bottom[0]->CanonicalAxisIndex(pool_param.axis()); + channels_ = bottom[0]->shape(channel_axis_); + + const int_tp first_spatial_axis = channel_axis_ + 1; + const int_tp num_axes = bottom[0]->num_axes(); + num_spatial_axes_ = num_axes - first_spatial_axis; + CHECK_GE(num_spatial_axes_, 0); + + vector bottom_dim_blob_shape(1, num_spatial_axes_ + 1); + vector spatial_dim_blob_shape( + 1, std::max(num_spatial_axes_, (int_tp) 1)); + + kernel_shape_.Reshape(spatial_dim_blob_shape); + int_tp* kernel_shape_data = kernel_shape_.mutable_cpu_data(); + if (pool_param.global_pooling()) { - CHECK(!(pool_param.has_kernel_size() || + global_pooling_ = true; + CHECK(!((pool_param.kernel_size_size() > 0) || pool_param.has_kernel_h() || pool_param.has_kernel_w())) << "With Global_pooling: true Filter size cannot specified"; } else { - CHECK(!pool_param.has_kernel_size() != - !(pool_param.has_kernel_h() && pool_param.has_kernel_w())) - << "Filter size is kernel_size OR kernel_h and kernel_w; not both"; - CHECK(pool_param.has_kernel_size() || - (pool_param.has_kernel_h() && pool_param.has_kernel_w())) - << "For non-square filters both kernel_h and kernel_w are required."; + global_pooling_ = false; + CHECK(!(pool_param.kernel_size_size() > 0) != + !(pool_param.has_kernel_h() && pool_param.has_kernel_w())) + << "Filter size is kernel_size OR kernel_h and kernel_w; not both"; + CHECK((pool_param.kernel_size_size() > 0) || + (pool_param.has_kernel_h() && pool_param.has_kernel_w())) + << "For non-square filters both kernel_h and kernel_w are required."; + if (pool_param.has_kernel_h() && pool_param.has_kernel_w()) { + kernel_shape_data[0] = pool_param.kernel_h(); + kernel_shape_data[1] = pool_param.kernel_w(); + } else { + const int_tp num_kernel_dims = pool_param.kernel_size_size(); + CHECK(num_kernel_dims == 1 || num_kernel_dims == num_spatial_axes_); + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + kernel_shape_data[i] = pool_param.kernel_size( + (num_kernel_dims == 1) ? 0 : i); + CHECK_GT(kernel_shape_data[i], 0) + << "Filter dimensions must be nonzero."; + } + } + } + + size_.Reshape(spatial_dim_blob_shape); + int_tp* size_data = size_.mutable_cpu_data(); + + vector top_shape = bottom[0]->shape(); + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + size_data[i] = bottom[0]->shape(channel_axis_ + 1 + i); } - CHECK((!pool_param.has_pad() && pool_param.has_pad_h() - && pool_param.has_pad_w()) - || (!pool_param.has_pad_h() && !pool_param.has_pad_w())) - << "pad is pad OR pad_h and pad_w are required."; - CHECK((!pool_param.has_stride() && pool_param.has_stride_h() - && pool_param.has_stride_w()) - || (!pool_param.has_stride_h() && !pool_param.has_stride_w())) - << "Stride is stride OR stride_h and stride_w are required."; - global_pooling_ = pool_param.global_pooling(); + top[0]->Reshape(top_shape); + if (top.size() > 1) { + top[1]->ReshapeLike(*top[0]); + } + if (global_pooling_) { - kernel_h_ = bottom[0]->height(); - kernel_w_ = bottom[0]->width(); - } else { - if (pool_param.has_kernel_size()) { - kernel_h_ = kernel_w_ = pool_param.kernel_size(); - } else { - kernel_h_ = pool_param.kernel_h(); - kernel_w_ = pool_param.kernel_w(); + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + kernel_shape_data[i] = size_data[i]; } } - CHECK_GT(kernel_h_, 0) << "Filter dimensions cannot be zero."; - CHECK_GT(kernel_w_, 0) << "Filter dimensions cannot be zero."; - if (!pool_param.has_pad_h()) { - pad_h_ = pad_w_ = pool_param.pad(); + + // Setup stride dimensions (stride_). + stride_.Reshape(spatial_dim_blob_shape); + int_tp* stride_data = stride_.mutable_cpu_data(); + if (pool_param.has_stride_h() || pool_param.has_stride_w()) { + CHECK_EQ(num_spatial_axes_, 2) + << "stride_h & stride_w can only be used for 2D convolution."; + CHECK_EQ(0, pool_param.stride_size()) + << "Either stride or stride_h/w should be specified; not both."; + stride_data[0] = pool_param.stride_h(); + stride_data[1] = pool_param.stride_w(); } else { - pad_h_ = pool_param.pad_h(); - pad_w_ = pool_param.pad_w(); + const int_tp num_stride_dims = pool_param.stride_size(); + CHECK(num_stride_dims == 0 || num_stride_dims == 1 || + num_stride_dims == num_spatial_axes_) + << "stride must be specified once, or once per spatial dimension " + << "(stride specified " << num_stride_dims << " times; " + << num_spatial_axes_ << " spatial dims);"; + const int_tp kDefaultStride = 1; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + stride_data[i] = (num_stride_dims == 0) ? kDefaultStride : + pool_param.stride((num_stride_dims == 1) ? 0 : i); + CHECK_GT(stride_data[i], 0) << "Stride dimensions must be nonzero."; + } } - if (!pool_param.has_stride_h()) { - stride_h_ = stride_w_ = pool_param.stride(); + + // Setup pad dimensions (pad_). + pad_.Reshape(spatial_dim_blob_shape); + int_tp* pad_data = pad_.mutable_cpu_data(); + if (pool_param.has_pad_h() || pool_param.has_pad_w()) { + CHECK_EQ(num_spatial_axes_, 2) + << "pad_h & pad_w can only be used for 2D convolution."; + CHECK_EQ(0, pool_param.pad_size()) + << "Either pad or pad_h/w should be specified; not both."; + pad_data[0] = pool_param.pad_h(); + pad_data[1] = pool_param.pad_w(); } else { - stride_h_ = pool_param.stride_h(); - stride_w_ = pool_param.stride_w(); + const int_tp num_pad_dims = pool_param.pad_size(); + CHECK(num_pad_dims == 0 || num_pad_dims == 1 || + num_pad_dims == num_spatial_axes_) + << "pad must be specified once, or once per spatial dimension " + << "(pad specified " << num_pad_dims << " times; " + << num_spatial_axes_ << " spatial dims);"; + const int_tp kDefaultPad = 0; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + pad_data[i] = (num_pad_dims == 0) ? kDefaultPad : + pool_param.pad((num_pad_dims == 1) ? 0 : i); + } } - if (global_pooling_) { - CHECK(pad_h_ == 0 && pad_w_ == 0 && stride_h_ == 1 && stride_w_ == 1) - << "With Global_pooling: true; only pad = 0 and stride = 1"; + + // Setup kernel stride dimensions + dilation_.Reshape(spatial_dim_blob_shape); + int_tp* dilation_data = dilation_.mutable_cpu_data(); + const int_tp num_dilation_dims = pool_param.dilation_size(); + CHECK(num_dilation_dims == 0 || num_dilation_dims == 1 || + num_dilation_dims == num_spatial_axes_) + << "dilation must be specified once, or once per spatial dimension " + << "(dilation specified " << num_dilation_dims << " times; " + << num_spatial_axes_ << " spatial dims);"; + const int_tp kDefaultdilation = 1; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + dilation_data[i] = + (num_dilation_dims == 0) ? + kDefaultdilation : + pool_param.dilation((num_dilation_dims == 1) ? 0 : i); } - if (pad_h_ != 0 || pad_w_ != 0) { - CHECK(this->layer_param_.pooling_param().pool() - == PoolingParameter_PoolMethod_AVE - || this->layer_param_.pooling_param().pool() - == PoolingParameter_PoolMethod_MAX) - << "Padding implemented only for average and max pooling."; - CHECK_LT(pad_h_, kernel_h_); - CHECK_LT(pad_w_, kernel_w_); + + // Different 2D and ND im2col/col2im kernels for strided kernels + use_skernel_ = false; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + use_skernel_ |= (dilation_data[i] != 1); + if (use_skernel_) { + break; + } } + + Reshape(bottom, top); } + template void PoolingLayer::Reshape(const vector*>& bottom, const vector*>& top) { - CHECK_EQ(4, bottom[0]->num_axes()) << "Input must have 4 axes, " - << "corresponding to (num, channels, height, width)"; - channels_ = bottom[0]->channels(); - height_ = bottom[0]->height(); - width_ = bottom[0]->width(); + vector size_shape(1, num_spatial_axes_); + + size_.Reshape(size_shape); + pooled_size_.Reshape(size_shape); + ext_kernel_shape_.Reshape(size_shape); + int_tp* size_data = size_.mutable_cpu_data(); + int_tp* pooled_size_data = pooled_size_.mutable_cpu_data(); + int_tp* ext_kernel_shape_data = ext_kernel_shape_.mutable_cpu_data(); + int_tp* dilation_data = dilation_.mutable_cpu_data(); + int_tp* kernel_shape_data = kernel_shape_.mutable_cpu_data(); + int_tp* pad_data = pad_.mutable_cpu_data(); + int_tp* stride_data = stride_.mutable_cpu_data(); + if (global_pooling_) { - kernel_h_ = bottom[0]->height(); - kernel_w_ = bottom[0]->width(); - } - pooled_height_ = static_cast(ceil(static_cast( - height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1; - pooled_width_ = static_cast(ceil(static_cast( - width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1; - if (pad_h_ || pad_w_) { - // If we have padding, ensure that the last pooling starts strictly - // inside the image (instead of at the padding); otherwise clip the last. - if ((pooled_height_ - 1) * stride_h_ >= height_ + pad_h_) { - --pooled_height_; + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + kernel_shape_data[i] = size_data[i]; } - if ((pooled_width_ - 1) * stride_w_ >= width_ + pad_w_) { - --pooled_width_; + } + + vector top_shape = bottom[0]->shape(); + for (int_tp i = 0; i < num_spatial_axes_; ++i) { + size_data[i] = bottom[0]->shape(channel_axis_ + 1 + i); + ext_kernel_shape_data[i] = (kernel_shape_data[i] - 1) * dilation_data[i] + + 1; + pooled_size_data[i] = static_cast(ceil( + static_cast(size_data[i] + 2 * pad_data[i] + - ext_kernel_shape_data[i]) / stride_data[i])) + 1; + if (pad_data[i] > 0) { + // If we have padding, ensure that the last pooling starts strictly + // inside the image (instead of at the padding); otherwise clip the last. + if ((pooled_size_data[i] - 1) * stride_data[i] + >= size_data[i] + pad_data[i]) { + --pooled_size_data[i]; + } + CHECK_LT((pooled_size_data[i] - 1) * stride_data[i], + size_data[i] + pad_data[i]); } - CHECK_LT((pooled_height_ - 1) * stride_h_, height_ + pad_h_); - CHECK_LT((pooled_width_ - 1) * stride_w_, width_ + pad_w_); + top_shape[channel_axis_ + 1 + i] = pooled_size_data[i]; } - top[0]->Reshape(bottom[0]->num(), channels_, pooled_height_, - pooled_width_); + top[0]->Reshape(top_shape); if (top.size() > 1) { top[1]->ReshapeLike(*top[0]); } + // If max pooling, we will initialize the vector index part. - if (this->layer_param_.pooling_param().pool() == - PoolingParameter_PoolMethod_MAX && top.size() == 1) { - max_idx_.Reshape(bottom[0]->num(), channels_, pooled_height_, - pooled_width_); + if (this->layer_param_.pooling_param().pool() + == PoolingParameter_PoolMethod_MAX && top.size() == 1) { + max_idx_.Reshape(top_shape); } + // If stochastic pooling, we will initialize the random index part. if (this->layer_param_.pooling_param().pool() == PoolingParameter_PoolMethod_STOCHASTIC) { - rand_idx_.Reshape(bottom[0]->num(), channels_, pooled_height_, - pooled_width_); + rand_idx_.Reshape(top_shape); } } -// TODO(Yangqing): Is there a faster way to do pooling in the channel-first -// case? template void PoolingLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { + int_tp kernel_h_ = kernel_shape_.cpu_data()[0]; + int_tp kernel_w_ = kernel_shape_.cpu_data()[1]; + int_tp stride_h_ = stride_.cpu_data()[0]; + int_tp stride_w_ = stride_.cpu_data()[1]; + int_tp pad_h_ = pad_.cpu_data()[0]; + int_tp pad_w_ = pad_.cpu_data()[1]; + int_tp height_ = size_.cpu_data()[0]; + int_tp width_ = size_.cpu_data()[1]; + int_tp pooled_height_ = pooled_size_.cpu_data()[0]; + int_tp pooled_width_ = pooled_size_.cpu_data()[1]; + + const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int top_count = top[0]->count(); + const int_tp top_count = top[0]->count(); // We'll output the mask to top[1] if it's of size >1. const bool use_top_mask = top.size() > 1; - int* mask = NULL; // suppress warnings about uninitalized variables + int_tp* mask = NULL; // suppress warnings about uninitalized variables Dtype* top_mask = NULL; // Different pooling methods. We explicitly do the switch outside the for // loop to save time, although this results in more code. @@ -144,24 +256,24 @@ void PoolingLayer::Forward_cpu(const vector*>& bottom, caffe_set(top_count, Dtype(-1), top_mask); } else { mask = max_idx_.mutable_cpu_data(); - caffe_set(top_count, -1, mask); + caffe_set(top_count, (int_tp)-1, mask); } caffe_set(top_count, Dtype(-FLT_MAX), top_data); // The main loop - for (int n = 0; n < bottom[0]->num(); ++n) { - for (int c = 0; c < channels_; ++c) { - for (int ph = 0; ph < pooled_height_; ++ph) { - for (int pw = 0; pw < pooled_width_; ++pw) { - int hstart = ph * stride_h_ - pad_h_; - int wstart = pw * stride_w_ - pad_w_; - int hend = min(hstart + kernel_h_, height_); - int wend = min(wstart + kernel_w_, width_); - hstart = max(hstart, 0); - wstart = max(wstart, 0); - const int pool_index = ph * pooled_width_ + pw; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { - const int index = h * width_ + w; + for (int_tp n = 0; n < bottom[0]->num(); ++n) { + for (int_tp c = 0; c < channels_; ++c) { + for (int_tp ph = 0; ph < pooled_height_; ++ph) { + for (int_tp pw = 0; pw < pooled_width_; ++pw) { + int_tp hstart = ph * stride_h_ - pad_h_; + int_tp wstart = pw * stride_w_ - pad_w_; + int_tp hend = min(hstart + kernel_h_, height_); + int_tp wend = min(wstart + kernel_w_, width_); + hstart = max(hstart, (int_tp)0); + wstart = max(wstart, (int_tp)0); + const int_tp pool_index = ph * pooled_width_ + pw; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + const int_tp index = h * width_ + w; if (bottom_data[index] > top_data[pool_index]) { top_data[pool_index] = bottom_data[index]; if (use_top_mask) { @@ -186,25 +298,25 @@ void PoolingLayer::Forward_cpu(const vector*>& bottom, } break; case PoolingParameter_PoolMethod_AVE: - for (int i = 0; i < top_count; ++i) { + for (int_tp i = 0; i < top_count; ++i) { top_data[i] = 0; } // The main loop - for (int n = 0; n < bottom[0]->num(); ++n) { - for (int c = 0; c < channels_; ++c) { - for (int ph = 0; ph < pooled_height_; ++ph) { - for (int pw = 0; pw < pooled_width_; ++pw) { - int hstart = ph * stride_h_ - pad_h_; - int wstart = pw * stride_w_ - pad_w_; - int hend = min(hstart + kernel_h_, height_ + pad_h_); - int wend = min(wstart + kernel_w_, width_ + pad_w_); - int pool_size = (hend - hstart) * (wend - wstart); - hstart = max(hstart, 0); - wstart = max(wstart, 0); + for (int_tp n = 0; n < bottom[0]->num(); ++n) { + for (int_tp c = 0; c < channels_; ++c) { + for (int_tp ph = 0; ph < pooled_height_; ++ph) { + for (int_tp pw = 0; pw < pooled_width_; ++pw) { + int_tp hstart = ph * stride_h_ - pad_h_; + int_tp wstart = pw * stride_w_ - pad_w_; + int_tp hend = min(hstart + kernel_h_, height_ + pad_h_); + int_tp wend = min(wstart + kernel_w_, width_ + pad_w_); + int_tp pool_size = (hend - hstart) * (wend - wstart); + hstart = max(hstart, (int_tp)0); + wstart = max(wstart, (int_tp)0); hend = min(hend, height_); wend = min(wend, width_); - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { top_data[ph * pooled_width_ + pw] += bottom_data[h * width_ + w]; } @@ -229,6 +341,17 @@ void PoolingLayer::Forward_cpu(const vector*>& bottom, template void PoolingLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { + int_tp kernel_h_ = kernel_shape_.cpu_data()[0]; + int_tp kernel_w_ = kernel_shape_.cpu_data()[1]; + int_tp stride_h_ = stride_.cpu_data()[0]; + int_tp stride_w_ = stride_.cpu_data()[1]; + int_tp pad_h_ = pad_.cpu_data()[0]; + int_tp pad_w_ = pad_.cpu_data()[1]; + int_tp height_ = size_.cpu_data()[0]; + int_tp width_ = size_.cpu_data()[1]; + int_tp pooled_height_ = pooled_size_.cpu_data()[0]; + int_tp pooled_width_ = pooled_size_.cpu_data()[1]; + if (!propagate_down[0]) { return; } @@ -239,7 +362,7 @@ void PoolingLayer::Backward_cpu(const vector*>& top, caffe_set(bottom[0]->count(), Dtype(0), bottom_diff); // We'll output the mask to top[1] if it's of size >1. const bool use_top_mask = top.size() > 1; - const int* mask = NULL; // suppress warnings about uninitialized variables + const int_tp* mask = NULL; // suppress warnings about uninitialized variables const Dtype* top_mask = NULL; switch (this->layer_param_.pooling_param().pool()) { case PoolingParameter_PoolMethod_MAX: @@ -249,12 +372,12 @@ void PoolingLayer::Backward_cpu(const vector*>& top, } else { mask = max_idx_.cpu_data(); } - for (int n = 0; n < top[0]->num(); ++n) { - for (int c = 0; c < channels_; ++c) { - for (int ph = 0; ph < pooled_height_; ++ph) { - for (int pw = 0; pw < pooled_width_; ++pw) { - const int index = ph * pooled_width_ + pw; - const int bottom_index = + for (int_tp n = 0; n < top[0]->num(); ++n) { + for (int_tp c = 0; c < channels_; ++c) { + for (int_tp ph = 0; ph < pooled_height_; ++ph) { + for (int_tp pw = 0; pw < pooled_width_; ++pw) { + const int_tp index = ph * pooled_width_ + pw; + const int_tp bottom_index = use_top_mask ? top_mask[index] : mask[index]; bottom_diff[bottom_index] += top_diff[index]; } @@ -271,21 +394,21 @@ void PoolingLayer::Backward_cpu(const vector*>& top, break; case PoolingParameter_PoolMethod_AVE: // The main loop - for (int n = 0; n < top[0]->num(); ++n) { - for (int c = 0; c < channels_; ++c) { - for (int ph = 0; ph < pooled_height_; ++ph) { - for (int pw = 0; pw < pooled_width_; ++pw) { - int hstart = ph * stride_h_ - pad_h_; - int wstart = pw * stride_w_ - pad_w_; - int hend = min(hstart + kernel_h_, height_ + pad_h_); - int wend = min(wstart + kernel_w_, width_ + pad_w_); - int pool_size = (hend - hstart) * (wend - wstart); - hstart = max(hstart, 0); - wstart = max(wstart, 0); + for (int_tp n = 0; n < top[0]->num(); ++n) { + for (int_tp c = 0; c < channels_; ++c) { + for (int_tp ph = 0; ph < pooled_height_; ++ph) { + for (int_tp pw = 0; pw < pooled_width_; ++pw) { + int_tp hstart = ph * stride_h_ - pad_h_; + int_tp wstart = pw * stride_w_ - pad_w_; + int_tp hend = min(hstart + kernel_h_, height_ + pad_h_); + int_tp wend = min(wstart + kernel_w_, width_ + pad_w_); + int_tp pool_size = (hend - hstart) * (wend - wstart); + hstart = max(hstart, (int_tp)0); + wstart = max(wstart, (int_tp)0); hend = min(hend, height_); wend = min(wend, width_); - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { bottom_diff[h * width_ + w] += top_diff[ph * pooled_width_ + pw] / pool_size; } @@ -306,11 +429,10 @@ void PoolingLayer::Backward_cpu(const vector*>& top, } } - #ifdef CPU_ONLY STUB_GPU(PoolingLayer); #endif INSTANTIATE_CLASS(PoolingLayer); -} // namespace caffe +} // namespace caffe diff --git a/src/caffe/layers/pooling_layer.cu b/src/caffe/layers/pooling_layer.cu index 1ea46cc81b1..bc8bf677871 100644 --- a/src/caffe/layers/pooling_layer.cu +++ b/src/caffe/layers/pooling_layer.cu @@ -5,32 +5,42 @@ #include "caffe/layers/pooling_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif // USE_GREENTEA + namespace caffe { -template -__global__ void MaxPoolForward(const int nthreads, - const Dtype* const bottom_data, const int num, const int channels, - const int height, const int width, const int pooled_height, - const int pooled_width, const int kernel_h, const int kernel_w, - const int stride_h, const int stride_w, const int pad_h, const int pad_w, - Dtype* const top_data, int* mask, Dtype* top_mask) { +#ifdef USE_CUDA +template +__global__ void MaxPoolForward(const int_tp nthreads, + const Dtype* const bottom_data, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp pooled_height, + const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp stride_h, + const int_tp stride_w, const int_tp pad_h, + const int_tp pad_w, Dtype* const top_data, + int_tp* mask, + Dtype* top_mask) { CUDA_KERNEL_LOOP(index, nthreads) { - const int pw = index % pooled_width; - const int ph = (index / pooled_width) % pooled_height; - const int c = (index / pooled_width / pooled_height) % channels; - const int n = index / pooled_width / pooled_height / channels; - int hstart = ph * stride_h - pad_h; - int wstart = pw * stride_w - pad_w; - const int hend = min(hstart + kernel_h, height); - const int wend = min(wstart + kernel_w, width); - hstart = max(hstart, 0); - wstart = max(wstart, 0); + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + const int_tp hend = min((int_tpc) (hstart + kernel_h), (int_tpc) height); + const int_tp wend = min((int_tpc) (wstart + kernel_w), (int_tpc) width); + hstart = max((int_tpc) (hstart), (int_tpc) (0)); + wstart = max((int_tpc) (wstart), (int_tpc) (0)); Dtype maxval = -FLT_MAX; - int maxidx = -1; - const Dtype* const bottom_slice = - bottom_data + (n * channels + c) * height * width; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + int_tp maxidx = -1; + const Dtype* const bottom_slice = bottom_data + + (n * channels + c) * height * width; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { if (bottom_slice[h * width + w] > maxval) { maxidx = h * width + w; maxval = bottom_slice[maxidx]; @@ -46,32 +56,35 @@ __global__ void MaxPoolForward(const int nthreads, } } -template -__global__ void AvePoolForward(const int nthreads, - const Dtype* const bottom_data, const int num, const int channels, - const int height, const int width, const int pooled_height, - const int pooled_width, const int kernel_h, const int kernel_w, - const int stride_h, const int stride_w, const int pad_h, const int pad_w, - Dtype* const top_data) { +template +__global__ void AvePoolForward(const int_tp nthreads, + const Dtype* const bottom_data, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp pooled_height, + const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp stride_h, + const int_tp stride_w, const int_tp pad_h, + const int_tp pad_w, Dtype* const top_data) { CUDA_KERNEL_LOOP(index, nthreads) { - const int pw = index % pooled_width; - const int ph = (index / pooled_width) % pooled_height; - const int c = (index / pooled_width / pooled_height) % channels; - const int n = index / pooled_width / pooled_height / channels; - int hstart = ph * stride_h - pad_h; - int wstart = pw * stride_w - pad_w; - int hend = min(hstart + kernel_h, height + pad_h); - int wend = min(wstart + kernel_w, width + pad_w); - const int pool_size = (hend - hstart) * (wend - wstart); - hstart = max(hstart, 0); - wstart = max(wstart, 0); - hend = min(hend, height); - wend = min(wend, width); + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min((int_tpc) (hstart + kernel_h), + (int_tpc) (height + pad_h)); + int_tp wend = min((int_tpc) (wstart + kernel_w), (int_tpc) (width + pad_w)); + const int_tp pool_size = (hend - hstart) * (wend - wstart); + hstart = max((int_tpc) (hstart), (int_tpc) (0)); + wstart = max((int_tpc) (wstart), (int_tpc) (0)); + hend = min((int_tpc) (hend), (int_tpc) (height)); + wend = min((int_tpc) (wend), (int_tpc) (width)); Dtype aveval = 0; - const Dtype* const bottom_slice = - bottom_data + (n * channels + c) * height * width; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + const Dtype* const bottom_slice = bottom_data + + (n * channels + c) * height * width; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { aveval += bottom_slice[h * width + w]; } } @@ -79,36 +92,42 @@ __global__ void AvePoolForward(const int nthreads, } } -template -__global__ void StoPoolForwardTrain(const int nthreads, - const Dtype* const bottom_data, - const int num, const int channels, const int height, - const int width, const int pooled_height, const int pooled_width, - const int kernel_h, const int kernel_w, const int stride_h, - const int stride_w, Dtype* const rand_idx, Dtype* const top_data) { +template +__global__ void StoPoolForwardTrain(const int_tp nthreads, + const Dtype* const bottom_data, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp stride_h, + const int_tp stride_w, + Dtype* const rand_idx, + Dtype* const top_data) { CUDA_KERNEL_LOOP(index, nthreads) { - const int pw = index % pooled_width; - const int ph = (index / pooled_width) % pooled_height; - const int c = (index / pooled_width / pooled_height) % channels; - const int n = index / pooled_width / pooled_height / channels; - const int hstart = ph * stride_h; - const int hend = min(hstart + kernel_h, height); - const int wstart = pw * stride_w; - const int wend = min(wstart + kernel_w, width); + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + const int_tp hstart = ph * stride_h; + const int_tp hend = min((int_tpc) (hstart + kernel_h), (int_tpc) height); + const int_tp wstart = pw * stride_w; + const int_tp wend = min((int_tpc) (wstart + kernel_w), (int_tpc) width); Dtype cumsum = 0.; - const Dtype* const bottom_slice = - bottom_data + (n * channels + c) * height * width; + const Dtype* const bottom_slice = bottom_data + + (n * channels + c) * height * width; // First pass: get sum - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { cumsum += bottom_slice[h * width + w]; } } const float thres = rand_idx[index] * cumsum; // Second pass: get value, and set index. cumsum = 0; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { cumsum += bottom_slice[h * width + w]; if (cumsum >= thres) { rand_idx[index] = ((n * channels + c) * height + h) * width + w; @@ -120,31 +139,33 @@ __global__ void StoPoolForwardTrain(const int nthreads, } } - -template -__global__ void StoPoolForwardTest(const int nthreads, - const Dtype* const bottom_data, - const int num, const int channels, const int height, - const int width, const int pooled_height, const int pooled_width, - const int kernel_h, const int kernel_w, const int stride_h, - const int stride_w, Dtype* const top_data) { +template +__global__ void StoPoolForwardTest(const int_tp nthreads, + const Dtype* const bottom_data, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp stride_h, const int_tp stride_w, + Dtype* const top_data) { CUDA_KERNEL_LOOP(index, nthreads) { - const int pw = index % pooled_width; - const int ph = (index / pooled_width) % pooled_height; - const int c = (index / pooled_width / pooled_height) % channels; - const int n = index / pooled_width / pooled_height / channels; - const int hstart = ph * stride_h; - const int hend = min(hstart + kernel_h, height); - const int wstart = pw * stride_w; - const int wend = min(wstart + kernel_w, width); + const int_tp pw = index % pooled_width; + const int_tp ph = (index / pooled_width) % pooled_height; + const int_tp c = (index / pooled_width / pooled_height) % channels; + const int_tp n = index / pooled_width / pooled_height / channels; + const int_tp hstart = ph * stride_h; + const int_tp hend = min((int_tpc) (hstart + kernel_h), (int_tpc) height); + const int_tp wstart = pw * stride_w; + const int_tp wend = min((int_tpc) (wstart + kernel_w), (int_tpc) width); // We set cumsum to be 0 to avoid divide-by-zero problems Dtype cumsum = FLT_MIN; Dtype cumvalues = 0.; - const Dtype* const bottom_slice = - bottom_data + (n * channels + c) * height * width; + const Dtype* const bottom_slice = bottom_data + + (n * channels + c) * height * width; // First pass: get sum - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { cumsum += bottom_slice[h * width + w]; cumvalues += bottom_slice[h * width + w] * bottom_slice[h * width + w]; } @@ -153,93 +174,40 @@ __global__ void StoPoolForwardTest(const int nthreads, } } - -template -void PoolingLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - const Dtype* bottom_data = bottom[0]->gpu_data(); - Dtype* top_data = top[0]->mutable_gpu_data(); - int count = top[0]->count(); - // We'll output the mask to top[1] if it's of size >1. - const bool use_top_mask = top.size() > 1; - int* mask = NULL; - Dtype* top_mask = NULL; - switch (this->layer_param_.pooling_param().pool()) { - case PoolingParameter_PoolMethod_MAX: - if (use_top_mask) { - top_mask = top[1]->mutable_gpu_data(); - } else { - mask = max_idx_.mutable_gpu_data(); - } - // NOLINT_NEXT_LINE(whitespace/operators) - MaxPoolForward<<>>( - count, bottom_data, bottom[0]->num(), channels_, - height_, width_, pooled_height_, pooled_width_, kernel_h_, - kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, top_data, - mask, top_mask); - break; - case PoolingParameter_PoolMethod_AVE: - // NOLINT_NEXT_LINE(whitespace/operators) - AvePoolForward<<>>( - count, bottom_data, bottom[0]->num(), channels_, - height_, width_, pooled_height_, pooled_width_, kernel_h_, - kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, top_data); - break; - case PoolingParameter_PoolMethod_STOCHASTIC: - if (this->phase_ == TRAIN) { - // We need to create the random index as well. - caffe_gpu_rng_uniform(count, Dtype(0), Dtype(1), - rand_idx_.mutable_gpu_data()); - // NOLINT_NEXT_LINE(whitespace/operators) - StoPoolForwardTrain<<>>( - count, bottom_data, bottom[0]->num(), channels_, - height_, width_, pooled_height_, pooled_width_, kernel_h_, - kernel_w_, stride_h_, stride_w_, - rand_idx_.mutable_gpu_data(), top_data); - } else { - // NOLINT_NEXT_LINE(whitespace/operators) - StoPoolForwardTest<<>>( - count, bottom_data, bottom[0]->num(), channels_, - height_, width_, pooled_height_, pooled_width_, kernel_h_, - kernel_w_, stride_h_, stride_w_, top_data); - } - break; - default: - LOG(FATAL) << "Unknown pooling method."; - } - CUDA_POST_KERNEL_CHECK; -} - - -template -__global__ void MaxPoolBackward(const int nthreads, const Dtype* const top_diff, - const int* const mask, const Dtype* const top_mask, const int num, - const int channels, const int height, const int width, - const int pooled_height, const int pooled_width, const int kernel_h, - const int kernel_w, const int stride_h, const int stride_w, const int pad_h, - const int pad_w, Dtype* const bottom_diff) { +template +__global__ void MaxPoolBackward(const int_tp nthreads, + const Dtype* const top_diff, + const int_tp* const mask, + const Dtype* const top_mask, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp pad_h, const int_tp pad_w, + Dtype* const bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { // find out the local index // find out the local offset - const int w = index % width; - const int h = (index / width) % height; - const int c = (index / width / height) % channels; - const int n = index / width / height / channels; - const int phstart = - (h + pad_h < kernel_h) ? 0 : (h + pad_h - kernel_h) / stride_h + 1; - const int phend = min((h + pad_h) / stride_h + 1, pooled_height); - const int pwstart = - (w + pad_w < kernel_w) ? 0 : (w + pad_w - kernel_w) / stride_w + 1; - const int pwend = min((w + pad_w) / stride_w + 1, pooled_width); + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp c = (index / width / height) % channels; + const int_tp n = index / width / height / channels; + const int_tp phstart = + (h + pad_h < kernel_h) ? 0 : (h + pad_h - kernel_h) / stride_h + 1; + const int_tp phend = min((int_tpc) ((h + pad_h) / stride_h + 1L), + (int_tpc) pooled_height); + const int_tp pwstart = + (w + pad_w < kernel_w) ? 0 : (w + pad_w - kernel_w) / stride_w + 1; + const int_tp pwend = min((int_tpc) ((w + pad_w) / stride_w + 1L), + (int_tpc) pooled_width); Dtype gradient = 0; - const int offset = (n * channels + c) * pooled_height * pooled_width; + const int_tp offset = (n * channels + c) * pooled_height * pooled_width; const Dtype* const top_diff_slice = top_diff + offset; if (mask) { - const int* const mask_slice = mask + offset; - for (int ph = phstart; ph < phend; ++ph) { - for (int pw = pwstart; pw < pwend; ++pw) { + const int_tp* const mask_slice = mask + offset; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { if (mask_slice[ph * pooled_width + pw] == h * width + w) { gradient += top_diff_slice[ph * pooled_width + pw]; } @@ -247,8 +215,8 @@ __global__ void MaxPoolBackward(const int nthreads, const Dtype* const top_diff, } } else { const Dtype* const top_mask_slice = top_mask + offset; - for (int ph = phstart; ph < phend; ++ph) { - for (int pw = pwstart; pw < pwend; ++pw) { + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { if (top_mask_slice[ph * pooled_width + pw] == h * width + w) { gradient += top_diff_slice[ph * pooled_width + pw]; } @@ -259,35 +227,42 @@ __global__ void MaxPoolBackward(const int nthreads, const Dtype* const top_diff, } } -template -__global__ void AvePoolBackward(const int nthreads, const Dtype* const top_diff, - const int num, const int channels, const int height, - const int width, const int pooled_height, const int pooled_width, - const int kernel_h, const int kernel_w, const int stride_h, - const int stride_w, const int pad_h, const int pad_w, - Dtype* const bottom_diff) { +template +__global__ void AvePoolBackward(const int_tp nthreads, + const Dtype* const top_diff, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp pad_h, const int_tp pad_w, + Dtype* const bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { // find out the local index // find out the local offset - const int w = index % width + pad_w; - const int h = (index / width) % height + pad_h; - const int c = (index / width / height) % channels; - const int n = index / width / height / channels; - const int phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1; - const int phend = min(h / stride_h + 1, pooled_height); - const int pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1; - const int pwend = min(w / stride_w + 1, pooled_width); + const int_tp w = index % width + pad_w; + const int_tp h = (index / width) % height + pad_h; + const int_tp c = (index / width / height) % channels; + const int_tp n = index / width / height / channels; + const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1; + const int_tp phend = min((int_tpc) (h / stride_h + 1), + (int_tpc) (pooled_height)); + const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1; + const int_tp pwend = min((int_tpc) (w / stride_w + 1), + (int_tpc) (pooled_width)); Dtype gradient = 0; - const Dtype* const top_diff_slice = - top_diff + (n * channels + c) * pooled_height * pooled_width; - for (int ph = phstart; ph < phend; ++ph) { - for (int pw = pwstart; pw < pwend; ++pw) { + const Dtype* const top_diff_slice = top_diff + + (n * channels + c) * pooled_height * pooled_width; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { // figure out the pooling size - int hstart = ph * stride_h - pad_h; - int wstart = pw * stride_w - pad_w; - int hend = min(hstart + kernel_h, height + pad_h); - int wend = min(wstart + kernel_w, width + pad_w); - int pool_size = (hend - hstart) * (wend - wstart); + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min((int_tpc) (hstart + kernel_h), + (int_tpc) (height + pad_h)); + int_tp wend = min((int_tpc) (wstart + kernel_w), + (int_tpc) (width + pad_w)); + int_tp pool_size = (hend - hstart) * (wend - wstart); gradient += top_diff_slice[ph * pooled_width + pw] / pool_size; } } @@ -295,92 +270,1099 @@ __global__ void AvePoolBackward(const int nthreads, const Dtype* const top_diff, } } +template +__global__ void StoPoolBackward(const int_tp nthreads, + const Dtype* const rand_idx, + const Dtype* const top_diff, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp stride_h, const int_tp stride_w, + Dtype* const bottom_diff) { + CUDA_KERNEL_LOOP(index, nthreads) { + // find out the local index + // find out the local offset + const int_tp w = index % width; + const int_tp h = (index / width) % height; + const int_tp c = (index / width / height) % channels; + const int_tp n = index / width / height / channels; + const int_tp phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1; + const int_tp phend = min((int_tpc) (h / stride_h + 1), + (int_tpc) pooled_height); + const int_tp pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1; + const int_tp pwend = min((int_tpc) (w / stride_w + 1), + (int_tpc) pooled_width); + Dtype gradient = 0; + const Dtype* const rand_idx_slice = rand_idx + + (n * channels + c) * pooled_height * pooled_width; + const Dtype* const top_diff_slice = top_diff + + (n * channels + c) * pooled_height * pooled_width; + for (int_tp ph = phstart; ph < phend; ++ph) { + for (int_tp pw = pwstart; pw < pwend; ++pw) { + gradient += top_diff_slice[ph * pooled_width + pw] + * (index + == static_cast(rand_idx_slice[ph * pooled_width + pw])); + } + } + bottom_diff[index] = gradient; + } +} + +template +__global__ void MaxPoolForward(const int_tp nthreads, const Dtype* bottom_data, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp ext_kernel_h, + const int_tp ext_kernel_w, const int_tp stride_h, + const int_tp stride_w, const int_tp dilation_h, + const int_tp dilation_w, const int_tp pad_h, + const int_tp pad_w, Dtype* top_data, + int_tp* mask, Dtype* top_mask) { + CUDA_KERNEL_LOOP(index, nthreads) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min((int_tpc) (hstart + ext_kernel_h), (int_tpc) height); + int_tp wend = min((int_tpc) (wstart + ext_kernel_w), (int_tpc) width); + hstart = max((int_tpc) hstart, (int_tpc) (0)); + wstart = max((int_tpc) wstart, (int_tpc) (0)); + Dtype maxval = -FLT_MAX; + int_tp maxidx = -1; + bottom_data += (n * channels + c) * height * width; + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + if (bottom_data[h * width + w] > maxval) { + maxidx = h * width + w; + maxval = bottom_data[maxidx]; + } + } + } + top_data[index] = maxval; + if (mask) { + mask[index] = maxidx; + } else { + top_mask[index] = maxidx; + } + } +} + +template +__global__ void AvePoolForward(const int_tp nthreads, const Dtype* bottom_data, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp ext_kernel_h, + const int_tp ext_kernel_w, const int_tp stride_h, + const int_tp stride_w, const int_tp dilation_h, + const int_tp dilation_w, const int_tp pad_h, + const int_tp pad_w, Dtype* top_data) { + CUDA_KERNEL_LOOP(index, nthreads) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h - pad_h; + int_tp wstart = pw * stride_w - pad_w; + int_tp hend = min((int_tpc) (hstart + ext_kernel_h), + (int_tpc) (height + pad_h)); + int_tp wend = min((int_tpc) (wstart + ext_kernel_w), + (int_tpc) (width + pad_w)); + hstart = max((int_tpc) hstart, (int_tpc) (0)); + wstart = max((int_tpc) wstart, (int_tpc) (0)); + hend = min((int_tpc) hend, (int_tpc) height); + wend = min((int_tpc) wend, (int_tpc) width); + Dtype aveval = 0; + bottom_data += (n * channels + c) * height * width; + int_tp pool_size = 0; + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { + aveval += bottom_data[h * width + w]; + ++pool_size; + } + } + top_data[index] = aveval / pool_size; + } +} + +template +__global__ void StoPoolForwardTrain(const int_tp nthreads, + const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, + const int_tp kernel_w, + const int_tp ext_kernel_h, + const int_tp ext_kernel_w, + const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, Dtype* rand_idx, + Dtype* top_data) { + CUDA_KERNEL_LOOP(index, nthreads) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h; + int_tp hend = min((int_tpc) (hstart + ext_kernel_h), (int_tpc) height); + int_tp wstart = pw * stride_w; + int_tp wend = min((int_tpc) (wstart + ext_kernel_w), (int_tpc) width); + Dtype cumsum = 0.; + bottom_data += (n * channels + c) * height * width; + // First pass: get sum + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + cumsum += bottom_data[h * width + w]; + } + } + float thres = rand_idx[index] * cumsum; + // Second pass: get value, and set index. + cumsum = 0; + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + cumsum += bottom_data[h * width + w]; + if (cumsum >= thres) { + rand_idx[index] = ((n * channels + c) * height + h) * width + w; + top_data[index] = bottom_data[h * width + w]; + return; + } + } + } + } +} + +template +__global__ void StoPoolForwardTest(const int_tp nthreads, + const Dtype* bottom_data, const int_tp num, + const int_tp channels, const int_tp height, + const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp ext_kernel_h, + const int_tp ext_kernel_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, Dtype* top_data) { + CUDA_KERNEL_LOOP(index, nthreads) { + int_tp pw = index % pooled_width; + int_tp ph = (index / pooled_width) % pooled_height; + int_tp c = (index / pooled_width / pooled_height) % channels; + int_tp n = index / pooled_width / pooled_height / channels; + int_tp hstart = ph * stride_h; + int_tp hend = min((int_tpc) (hstart + ext_kernel_h), (int_tpc) height); + int_tp wstart = pw * stride_w; + int_tp wend = min((int_tpc) (wstart + ext_kernel_w), (int_tpc) width); + // We set cumsum to be 0 to avoid divide-by-zero problems + Dtype cumsum = FLT_MIN; + Dtype cumvalues = 0.; + bottom_data += (n * channels + c) * height * width; + // First pass: get sum + for (int_tp h = hstart; h < hend; h += dilation_h) { + for (int_tp w = wstart; w < wend; w += dilation_w) { + cumsum += bottom_data[h * width + w]; + cumvalues += bottom_data[h * width + w] * bottom_data[h * width + w]; + } + } + top_data[index] = cumvalues / cumsum; + } +} -template -__global__ void StoPoolBackward(const int nthreads, - const Dtype* const rand_idx, const Dtype* const top_diff, - const int num, const int channels, const int height, - const int width, const int pooled_height, const int pooled_width, - const int kernel_h, const int kernel_w, const int stride_h, - const int stride_w, Dtype* const bottom_diff) { +template +__global__ void MaxPoolBackward(const int_tp nthreads, const Dtype* top_diff, + const int_tp* mask, const Dtype* top_mask, + const int_tp num, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp pooled_height, + const int_tp pooled_width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp ext_kernel_h, + const int_tp ext_kernel_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, const int_tp pad_h, + const int_tp pad_w, + Dtype* bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { // find out the local index // find out the local offset - const int w = index % width; - const int h = (index / width) % height; - const int c = (index / width / height) % channels; - const int n = index / width / height / channels; - const int phstart = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1; - const int phend = min(h / stride_h + 1, pooled_height); - const int pwstart = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1; - const int pwend = min(w / stride_w + 1, pooled_width); + int_tp w = index % width; + int_tp h = (index / width) % height; + int_tp c = (index / width / height) % channels; + int_tp n = index / width / height / channels; + + int_tp pooled_height_1 = pooled_height - 1; + int_tp pooled_width_1 = pooled_width - 1; + int_tp phstart = + (h < ext_kernel_h) ? h % dilation_h : (h - ext_kernel_h) + 1; + int_tp phend = + (h >= pooled_height) ? + pooled_height_1 - (pooled_height_1 - phstart) % dilation_h : h; + int_tp pwstart = + (w < ext_kernel_w) ? w % dilation_w : (w - ext_kernel_w) + 1; + int_tp pwend = + (w >= pooled_width) ? + pooled_width_1 - (pooled_width_1 - pwstart) % dilation_w : w; + Dtype gradient = 0; - const Dtype* const rand_idx_slice = - rand_idx + (n * channels + c) * pooled_height * pooled_width; - const Dtype* const top_diff_slice = - top_diff + (n * channels + c) * pooled_height * pooled_width; - for (int ph = phstart; ph < phend; ++ph) { - for (int pw = pwstart; pw < pwend; ++pw) { - gradient += top_diff_slice[ph * pooled_width + pw] * - (index == static_cast(rand_idx_slice[ph * pooled_width + pw])); + int_tp offset = (n * channels + c) * pooled_height * pooled_width; + top_diff += offset; + if (mask) { + mask += offset; + for (int_tp ph = phstart; ph <= phend; ph += dilation_h) { + for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) { + if (mask[ph * pooled_width + pw] == h * width + w) { + gradient += top_diff[ph * pooled_width + pw]; + } + } + } + } else { + top_mask += offset; + for (int_tp ph = phstart; ph <= phend; ph += dilation_h) { + for (int_tp pw = pwstart; pw <= pwend; pw += dilation_w) { + if (top_mask[ph * pooled_width + pw] == h * width + w) { + gradient += top_diff[ph * pooled_width + pw]; + } + } } } bottom_diff[index] = gradient; } } +template +__global__ void MaxPoolNDForward(const int_tp n, const int_tp num_axes, + const Dtype* bottom_data, + const int_tp channels, const int_tp* size, + const int_tp* pooled_size, + const int_tp* kernel_size, + const int_tp* ext_kernel_size, + const int_tp* stride, const int_tp* dilation, + const int_tp* pad, Dtype* top_data, + int_tp* mask, Dtype* top_mask) { + int_tp d_idx[6]; // NOLINT(runtime/arrays) + int_tp d_start[6]; // NOLINT(runtime/arrays) + int_tp d_end[6]; // NOLINT(runtime/arrays) + int_tp d_iter[6]; // NOLINT(runtime/arrays) + int_tp i; -template -void PoolingLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (!propagate_down[0]) { - return; + CUDA_KERNEL_LOOP(index, n) { + int_tp offset = 1; + int_tp num = index; + for (i = num_axes - 1; i >= 0; --i) { + d_idx[i] = num % pooled_size[i]; + d_start[i] = d_idx[i] * stride[i] - pad[i]; + d_end[i] = min((int_tpc) (d_start[i] + ext_kernel_size[i]), + (int_tpc) (size[i])); + d_start[i] = max((int_tpc) (d_start[i]), (int_tpc) (0)); + num /= pooled_size[i]; + offset *= size[i]; + d_iter[i] = d_start[i]; + + if (d_start[i] >= d_end[i]) { + top_data[index] = -FLT_MAX; + if (mask) { + mask[index] = -1; + } else { + top_mask[index] = -1; + } + return; + } + } + int_tp chan = num % channels; + num /= channels; + offset *= (num * channels + chan); + + Dtype maxval = -FLT_MAX; + int_tp maxidx = -1; + int_tp final_offset = 0; + + bool incremented; + do { + final_offset = offset; + int_tp size_prod = 1; + for (i = num_axes - 1; i >= 0; --i) { + final_offset += d_iter[i] * size_prod; + size_prod *= size[i]; + } + + if (bottom_data[final_offset] > maxval) { + maxidx = final_offset; + maxval = bottom_data[maxidx]; + } + + incremented = false; + for (i = num_axes - 1; i >= 0; --i) { + if (d_iter[i] >= d_end[i] - dilation[i]) { + d_iter[i] = d_start[i]; + } else { + d_iter[i] += dilation[i]; + incremented = true; + break; + } + } + } while (incremented); + + top_data[index] = maxval; + if (mask) { + mask[index] = maxidx; + } else { + top_mask[index] = maxidx; + } + } +} + +template +__global__ void MaxPoolNDBackward(const int_tp n, const int_tp num_axes, + const Dtype* top_diff, const int_tp* mask, + const Dtype* top_mask, const int_tp channels, + const int_tp* size, const int_tp* pooled_size, + const int_tp* kernel_size, + const int_tp* ext_kernel_size, + const int_tp* stride, const int_tp* dilation, + const int_tp* pad, Dtype* bottom_diff) { + int_tp d_idx[6]; // NOLINT(runtime/arrays) + int_tp d_start[6]; // NOLINT(runtime/arrays) + int_tp d_end[6]; // NOLINT(runtime/arrays) + int_tp d_iter[6]; // NOLINT(runtime/arrays) + int_tp i; + + CUDA_KERNEL_LOOP(index, n) { + // find out the local index + // find out the local offset + int_tp offset = 1; + int_tp num = index; + for (i = num_axes - 1; i >= 0; --i) { + d_idx[i] = num % size[i]; + if (dilation[i] > 1) { + d_start[i] = + (d_idx[i] < ext_kernel_size[i]) ? + d_idx[i] % dilation[i] : (d_idx[i] - ext_kernel_size[i]) + 1; + d_end[i] = + (d_idx[i] >= pooled_size[i]) ? + (pooled_size[i] - 1) + - (pooled_size[i] - 1 - d_start[i]) % dilation[i] : + d_idx[i]; + } else { + d_start[i] = + (d_idx[i] + pad[i] < kernel_size[i]) ? + 0 : (d_idx[i] + pad[i] - kernel_size[i]) / stride[i] + 1; + d_end[i] = min((int_tpc) ((d_idx[i] + pad[i]) / stride[i] + 1), + (int_tpc) (pooled_size[i])); + } + num /= size[i]; + offset *= pooled_size[i]; + d_iter[i] = d_start[i]; + + if (d_start[i] > d_end[i]) { + bottom_diff[index] = 0; + return; + } + } + + int_tp chan = num % channels; + num /= channels; + offset *= (num * channels + chan); + + Dtype gradient = 0; + int_tp final_offset = 0; + int_tp im_offset = 0; + + bool incremented; + do { + final_offset = offset; + im_offset = 0; + int_tp size_prod = 1; + int_tp pooled_size_prod = 1; + for (i = num_axes - 1; i >= 0; --i) { + final_offset += d_iter[i] * pooled_size_prod; + im_offset += d_idx[i] * size_prod; + size_prod *= size[i]; + pooled_size_prod *= pooled_size[i]; + } + if (mask) { + if (mask[final_offset] == im_offset) { + gradient += top_diff[final_offset]; + } + } else { + if (top_mask[final_offset] == im_offset) { + gradient += top_diff[final_offset]; + } + } + + incremented = false; + for (i = num_axes - 1; i >= 0; --i) { + if (d_iter[i] > d_end[i] - dilation[i]) { + d_iter[i] = d_start[i]; + } else { + d_iter[i] += dilation[i]; + incremented = true; + break; + } + } + } while (incremented); + bottom_diff[index] = gradient; } +} +#endif // USE_CUDA + +template +void PoolingLayer::Forward_gpu(const vector*>& bottom, + const vector*>& top) { + const Dtype* bottom_data = bottom[0]->gpu_data(); + Dtype* top_data = top[0]->mutable_gpu_data(); + int_tp count = top[0]->count(); + // We'll output the mask to top[1] if it's of size >1. + const bool use_top_mask = top.size() > 1; + int_tp* mask = NULL; + Dtype* top_mask = NULL; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + + if (num_spatial_axes_ == 2) { + int_tp kernel_h_ = kernel_shape_.cpu_data()[0]; + int_tp kernel_w_ = kernel_shape_.cpu_data()[1]; + int_tp stride_h_ = stride_.cpu_data()[0]; + int_tp stride_w_ = stride_.cpu_data()[1]; + int_tp pad_h_ = pad_.cpu_data()[0]; + int_tp pad_w_ = pad_.cpu_data()[1]; + int_tp dilation_h_ = dilation_.cpu_data()[0]; + int_tp dilation_w_ = dilation_.cpu_data()[1]; + int_tp height_ = size_.cpu_data()[0]; + int_tp width_ = size_.cpu_data()[1]; + int_tp pooled_height_ = pooled_size_.cpu_data()[0]; + int_tp pooled_width_ = pooled_size_.cpu_data()[1]; + int_tp ext_kernel_h = ext_kernel_shape_.cpu_data()[0]; + int_tp ext_kernel_w = ext_kernel_shape_.cpu_data()[0]; + + // 2D case + if (use_skernel_) { + // 2D-SK case + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: + if (use_top_mask) { + top_mask = top[1]->mutable_gpu_data(); + } else { + mask = max_idx_.mutable_gpu_data(); + } + // NOLINT_NEXT_LINE(whitespace/operators) + MaxPoolForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + pad_h_, pad_w_, top_data, + mask, top_mask); + break; + case PoolingParameter_PoolMethod_AVE: + // NOLINT_NEXT_LINE(whitespace/operators) + AvePoolForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + pad_h_, pad_w_, top_data); + break; + case PoolingParameter_PoolMethod_STOCHASTIC: + if (this->phase_ == caffe::TRAIN) { + // We need to create the random index as well. + caffe_gpu_rng_uniform(count, Dtype(0), Dtype(1), + rand_idx_.mutable_gpu_data()); + // NOLINT_NEXT_LINE(whitespace/operators) + StoPoolForwardTrain CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + rand_idx_.mutable_gpu_data(), top_data); + } else { + // NOLINT_NEXT_LINE(whitespace/operators) + StoPoolForwardTest CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, top_data); + } + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + CUDA_POST_KERNEL_CHECK; + } else { + // 2D case + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: + if (use_top_mask) { + top_mask = top[1]->mutable_gpu_data(); + } else { + mask = max_idx_.mutable_gpu_data(); + } + // NOLINT_NEXT_LINE(whitespace/operators) + MaxPoolForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, top_data, + mask, top_mask); + break; + case PoolingParameter_PoolMethod_AVE: + // NOLINT_NEXT_LINE(whitespace/operators) + AvePoolForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, top_data); + break; + case PoolingParameter_PoolMethod_STOCHASTIC: + if (this->phase_ == TRAIN) { + // We need to create the random index as well. + caffe_gpu_rng_uniform(count, Dtype(0), Dtype(1), + rand_idx_.mutable_gpu_data()); + // NOLINT_NEXT_LINE(whitespace/operators) + StoPoolForwardTrain CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, + rand_idx_.mutable_gpu_data(), top_data); + } else { + // NOLINT_NEXT_LINE(whitespace/operators) + StoPoolForwardTest CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, top_data); + } + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + CUDA_POST_KERNEL_CHECK; + } + } else { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: + if (use_top_mask) { + top_mask = top[1]->mutable_gpu_data(); + } else { + mask = max_idx_.mutable_gpu_data(); + } + // NOLINT_NEXT_LINE(whitespace/operators) + MaxPoolNDForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, num_spatial_axes_, bottom_data, + channels_, size_.gpu_data(), pooled_size_.gpu_data(), + kernel_shape_.gpu_data(), ext_kernel_shape_.gpu_data(), + stride_.gpu_data(), dilation_.gpu_data(), pad_.gpu_data(), + top_data, mask, top_mask); + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + } + CUDA_POST_KERNEL_CHECK; + +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if (num_spatial_axes_ == 2) { + int_tp kernel_h_ = kernel_shape_.cpu_data()[0]; + int_tp kernel_w_ = kernel_shape_.cpu_data()[1]; + int_tp stride_h_ = stride_.cpu_data()[0]; + int_tp stride_w_ = stride_.cpu_data()[1]; + int_tp pad_h_ = pad_.cpu_data()[0]; + int_tp pad_w_ = pad_.cpu_data()[1]; + int_tp dilation_h_ = dilation_.cpu_data()[0]; + int_tp dilation_w_ = dilation_.cpu_data()[1]; + int_tp height_ = size_.cpu_data()[0]; + int_tp width_ = size_.cpu_data()[1]; + int_tp pooled_height_ = pooled_size_.cpu_data()[0]; + int_tp pooled_width_ = pooled_size_.cpu_data()[1]; + int_tp ext_kernel_h = ext_kernel_shape_.cpu_data()[0]; + int_tp ext_kernel_w = ext_kernel_shape_.cpu_data()[0]; + + // 2D case + if (use_skernel_) { + // 2D-SK case + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: { + if (use_top_mask) { + top_mask = top[1]->mutable_gpu_data(); + } else { + mask = max_idx_.mutable_gpu_data(); + } + viennacl::ocl::kernel &oclk_max_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("max_pool_forward_sk")); + viennacl::ocl::enqueue( + oclk_max_pool_forward(count, + WrapHandle((cl_mem) bottom_data, &ctx), + bottom[0]->shape(0), channels_, height_, width_, + pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + pad_h_, pad_w_, + WrapHandle((cl_mem) top_data, &ctx), + mask == NULL ? 0 : 1, + WrapHandle((cl_mem) mask, &ctx), + WrapHandle((cl_mem) top_mask, &ctx)), + ctx.get_queue()); + } + break; + case PoolingParameter_PoolMethod_AVE: { + viennacl::ocl::kernel &oclk_ave_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("ave_pool_forward_sk")); + viennacl::ocl::enqueue( + oclk_ave_pool_forward(count, + WrapHandle((cl_mem) bottom_data, &ctx), + bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + pad_h_, pad_w_, WrapHandle((cl_mem)top_data, &ctx)), + ctx.get_queue()); + } + break; + case PoolingParameter_PoolMethod_STOCHASTIC: { + if (this->phase_ == caffe::TRAIN) { + // We need to create the random index as well. + greentea_gpu_rng_uniform(this->device_->id(), count, + Dtype(0), Dtype(1), + (cl_mem)(rand_idx_.mutable_gpu_data()), 0); + + viennacl::ocl::kernel &oclk_sto_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("sto_pool_forward_train_sk")); + viennacl::ocl::enqueue( + oclk_sto_pool_forward(count, + WrapHandle((cl_mem)bottom_data, &ctx), + bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + WrapHandle((cl_mem)(rand_idx_.mutable_gpu_data()), &ctx), + WrapHandle((cl_mem)(top_data), &ctx)), + ctx.get_queue()); + } else { + viennacl::ocl::kernel &oclk_sto_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("sto_pool_forward_test_sk")); + viennacl::ocl::enqueue( + oclk_sto_pool_forward(count, + WrapHandle((cl_mem)bottom_data, &ctx), + bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + WrapHandle((cl_mem)top_data, &ctx)), + ctx.get_queue()); + } + } + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + } else { + // 2D case + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: { + if (use_top_mask) { + top_mask = top[1]->mutable_gpu_data(); + } else { + mask = max_idx_.mutable_gpu_data(); + } + viennacl::ocl::kernel &oclk_max_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("max_pool_forward")); + viennacl::ocl::enqueue( + oclk_max_pool_forward(count, + WrapHandle((cl_mem) bottom_data, &ctx), + bottom[0]->shape(0), channels_, height_, width_, + pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, + WrapHandle((cl_mem) top_data, &ctx), + mask == NULL ? 0 : 1, + WrapHandle((cl_mem) mask, &ctx), + WrapHandle((cl_mem) top_mask, &ctx)), + ctx.get_queue()); + } + break; + case PoolingParameter_PoolMethod_AVE: { + viennacl::ocl::kernel &oclk_ave_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("ave_pool_forward")); + viennacl::ocl::enqueue( + oclk_ave_pool_forward(count, + WrapHandle((cl_mem) bottom_data, &ctx), + bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, + WrapHandle((cl_mem)top_data, &ctx)), + ctx.get_queue()); + } + break; + case PoolingParameter_PoolMethod_STOCHASTIC: { + if (this->phase_ == caffe::TRAIN) { + // We need to create the random index as well. + greentea_gpu_rng_uniform(this->device_->id(), count, + Dtype(0), Dtype(1), + (cl_mem)(rand_idx_.mutable_gpu_data()), 0); + + viennacl::ocl::kernel &oclk_sto_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("sto_pool_forward_train")); + viennacl::ocl::enqueue( + oclk_sto_pool_forward(count, + WrapHandle((cl_mem)bottom_data, &ctx), + bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, + kernel_h_, kernel_w_, + stride_h_, stride_w_, + WrapHandle((cl_mem)(rand_idx_.mutable_gpu_data()), &ctx), + WrapHandle((cl_mem)top_data, &ctx)), + ctx.get_queue()); + } else { + viennacl::ocl::kernel &oclk_sto_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("sto_pool_forward_test")); + viennacl::ocl::enqueue( + oclk_sto_pool_forward(count, + WrapHandle((cl_mem)bottom_data, &ctx), + bottom[0]->shape(0), channels_, + height_, width_, pooled_height_, + pooled_width_, kernel_h_, kernel_w_, + stride_h_, stride_w_, WrapHandle((cl_mem)top_data, &ctx)), + ctx.get_queue()); + } + } + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + } + } else { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: { + if (use_top_mask) { + top_mask = top[1]->mutable_gpu_data(); + } else { + mask = max_idx_.mutable_gpu_data(); + } + viennacl::ocl::kernel &oclk_max_pool_forward = program.get_kernel( + CL_KERNEL_SELECT("max_pool_forward_nd")); + viennacl::ocl::enqueue( + oclk_max_pool_forward(count, num_spatial_axes_, + WrapHandle((cl_mem)bottom_data, &ctx), + channels_, + WrapHandle((cl_mem)(size_.gpu_data()), &ctx), + WrapHandle((cl_mem)(pooled_size_.gpu_data()), &ctx), + WrapHandle((cl_mem)(kernel_shape_.gpu_data()), &ctx), + WrapHandle((cl_mem)(ext_kernel_shape_.gpu_data()), &ctx), + WrapHandle((cl_mem)(stride_.gpu_data()), &ctx), + WrapHandle((cl_mem)(dilation_.gpu_data()), &ctx), + WrapHandle((cl_mem)(pad_.gpu_data()), &ctx), + WrapHandle((cl_mem)top_data, &ctx), + mask == NULL ? 0 : 1, + WrapHandle((cl_mem)mask, &ctx), + WrapHandle((cl_mem)top_mask, &ctx)), + ctx.get_queue()); + } + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + } + +#endif // USE_GREENTEA + } +} + +template +void PoolingLayer::Backward_gpu(const vector*>& top, + const vector& propagate_down, + const vector*>& bottom) { const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int count = bottom[0]->count(); - caffe_gpu_set(count, Dtype(0.), bottom_diff); + const int_tp count = bottom[0]->count(); // We'll output the mask to top[1] if it's of size >1. const bool use_top_mask = top.size() > 1; - const int* mask = NULL; + const int_tp* mask = NULL; const Dtype* top_mask = NULL; - switch (this->layer_param_.pooling_param().pool()) { - case PoolingParameter_PoolMethod_MAX: - if (use_top_mask) { - top_mask = top[1]->gpu_data(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_set(count, Dtype(0.), bottom_diff); + + if (num_spatial_axes_ == 2) { + int_tp kernel_h_ = kernel_shape_.cpu_data()[0]; + int_tp kernel_w_ = kernel_shape_.cpu_data()[1]; + int_tp stride_h_ = stride_.cpu_data()[0]; + int_tp stride_w_ = stride_.cpu_data()[1]; + int_tp pad_h_ = pad_.cpu_data()[0]; + int_tp pad_w_ = pad_.cpu_data()[1]; + int_tp dilation_h_ = dilation_.cpu_data()[0]; + int_tp dilation_w_ = dilation_.cpu_data()[1]; + int_tp height_ = size_.cpu_data()[0]; + int_tp width_ = size_.cpu_data()[1]; + int_tp pooled_height_ = pooled_size_.cpu_data()[0]; + int_tp pooled_width_ = pooled_size_.cpu_data()[1]; + int_tp ext_kernel_h = ext_kernel_shape_.cpu_data()[0]; + int_tp ext_kernel_w = ext_kernel_shape_.cpu_data()[0]; + + if (use_skernel_) { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: + if (use_top_mask) { + top_mask = top[1]->gpu_data(); + } else { + mask = max_idx_.gpu_data(); + } + // NOLINT_NEXT_LINE(whitespace/operators) + MaxPoolBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, mask, top_mask, top[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, + kernel_h_, kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + pad_h_, pad_w_, + bottom_diff); + break; + default: + LOG(FATAL)<< + "Unknown or unsupported pooling method in Backward_gpu()."; + } + CUDA_POST_KERNEL_CHECK; + } else { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: + if (use_top_mask) { + top_mask = top[1]->gpu_data(); + } else { + mask = max_idx_.gpu_data(); + } + // NOLINT_NEXT_LINE(whitespace/operators) + MaxPoolBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, mask, top_mask, top[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, + kernel_h_, kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, + bottom_diff); + break; + case PoolingParameter_PoolMethod_AVE: + // NOLINT_NEXT_LINE(whitespace/operators) + AvePoolBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, top[0]->shape(0), channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, bottom_diff); + break; + case PoolingParameter_PoolMethod_STOCHASTIC: + // NOLINT_NEXT_LINE(whitespace/operators) + StoPoolBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, rand_idx_.gpu_data(), top_diff, + top[0]->shape(0), channels_, height_, width_, pooled_height_, + pooled_width_, kernel_h_, kernel_w_, stride_h_, stride_w_, + bottom_diff); + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + CUDA_POST_KERNEL_CHECK; + } + } else { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: + if (use_top_mask) { + top_mask = top[1]->gpu_data(); + } else { + mask = max_idx_.gpu_data(); + } + // NOLINT_NEXT_LINE(whitespace/operators) + MaxPoolNDBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, num_spatial_axes_, top_diff, mask, top_mask, + channels_, size_.gpu_data(), pooled_size_.gpu_data(), + kernel_shape_.gpu_data(), ext_kernel_shape_.gpu_data(), + stride_.gpu_data(), dilation_.gpu_data(), pad_.gpu_data(), + bottom_diff); + break; + default: + LOG(FATAL)<< + "Unknown or unsupported pooling method in Backward_gpu()."; + } + CUDA_POST_KERNEL_CHECK; + } +#endif // USE_CUDA } else { - mask = max_idx_.gpu_data(); +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + greentea_gpu_set(this->device_->id(), count, Dtype(0.), + (cl_mem) bottom_diff, 0); + + if (num_spatial_axes_ == 2) { + int_tp kernel_h_ = kernel_shape_.cpu_data()[0]; + int_tp kernel_w_ = kernel_shape_.cpu_data()[1]; + int_tp stride_h_ = stride_.cpu_data()[0]; + int_tp stride_w_ = stride_.cpu_data()[1]; + int_tp pad_h_ = pad_.cpu_data()[0]; + int_tp pad_w_ = pad_.cpu_data()[1]; + int_tp dilation_h_ = dilation_.cpu_data()[0]; + int_tp dilation_w_ = dilation_.cpu_data()[1]; + int_tp height_ = size_.cpu_data()[0]; + int_tp width_ = size_.cpu_data()[1]; + int_tp pooled_height_ = pooled_size_.cpu_data()[0]; + int_tp pooled_width_ = pooled_size_.cpu_data()[1]; + int_tp ext_kernel_h = ext_kernel_shape_.cpu_data()[0]; + int_tp ext_kernel_w = ext_kernel_shape_.cpu_data()[0]; + + if (use_skernel_) { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: { + if (use_top_mask) { + top_mask = top[1]->gpu_data(); + } else { + mask = max_idx_.gpu_data(); + } + viennacl::ocl::kernel &oclk_max_pool_backward = + program.get_kernel( + CL_KERNEL_SELECT("max_pool_backward_sk")); + viennacl::ocl::enqueue( + oclk_max_pool_backward(count, + WrapHandle((cl_mem) top_diff, &ctx), + mask == NULL ? 0 : 1, + WrapHandle((cl_mem) mask, &ctx), + WrapHandle((cl_mem) top_mask, &ctx), + top[0]->shape(0), channels_, height_, width_, + pooled_height_, pooled_width_, kernel_h_, + kernel_w_, ext_kernel_h, ext_kernel_w, + stride_h_, stride_w_, dilation_h_, dilation_w_, + pad_h_, pad_w_, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } + break; + default: + LOG(FATAL)<< + "Unknown or unsupported pooling method in Backward_gpu()."; + } + } else { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: { + if (use_top_mask) { + top_mask = top[1]->gpu_data(); + } else { + mask = max_idx_.gpu_data(); + } + viennacl::ocl::kernel &oclk_max_pool_backward = + program.get_kernel( + CL_KERNEL_SELECT("max_pool_backward")); + viennacl::ocl::enqueue( + oclk_max_pool_backward(count, + WrapHandle((cl_mem) top_diff, &ctx), + mask == NULL ? 0 : 1, + WrapHandle((cl_mem) mask, &ctx), + WrapHandle((cl_mem) top_mask, &ctx), + top[0]->shape(0), channels_, height_, width_, + pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, + pad_w_, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } + break; + case PoolingParameter_PoolMethod_AVE: { + viennacl::ocl::kernel &oclk_ave_pool_backward = + program.get_kernel( + CL_KERNEL_SELECT("ave_pool_backward")); + viennacl::ocl::enqueue( + oclk_ave_pool_backward(count, + WrapHandle((cl_mem) top_diff, &ctx), + top[0]->shape(0), channels_, height_, width_, + pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, pad_h_, + pad_w_, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } + break; + case PoolingParameter_PoolMethod_STOCHASTIC: { + viennacl::ocl::kernel &oclk_sto_pool_backward = + program.get_kernel( + CL_KERNEL_SELECT("sto_pool_backward")); + viennacl::ocl::enqueue( + oclk_sto_pool_backward( + count, WrapHandle((cl_mem) (rand_idx_.gpu_data()), &ctx), + WrapHandle((cl_mem) top_diff, &ctx), top[0]->shape(0), + channels_, + height_, width_, pooled_height_, pooled_width_, kernel_h_, + kernel_w_, stride_h_, stride_w_, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } + break; + default: { + LOG(FATAL)<< "Unknown pooling method."; + } + } + } + } else { + switch (this->layer_param_.pooling_param().pool()) { + case PoolingParameter_PoolMethod_MAX: { + if (use_top_mask) { + top_mask = top[1]->gpu_data(); + } else { + mask = max_idx_.gpu_data(); + } + viennacl::ocl::kernel &oclk_max_pool_backward = program.get_kernel( + CL_KERNEL_SELECT("max_pool_backward_nd")); + viennacl::ocl::enqueue( + oclk_max_pool_backward( + count, num_spatial_axes_, + WrapHandle((cl_mem) top_diff, &ctx), + mask == NULL ? 0 : 1, WrapHandle((cl_mem) mask, &ctx), + WrapHandle((cl_mem) top_mask, &ctx), channels_, + WrapHandle((cl_mem) (size_.gpu_data()), &ctx), + WrapHandle((cl_mem) (pooled_size_.gpu_data()), &ctx), + WrapHandle((cl_mem) (kernel_shape_.gpu_data()), &ctx), + WrapHandle((cl_mem) (ext_kernel_shape_.gpu_data()), &ctx), + WrapHandle((cl_mem) (stride_.gpu_data()), &ctx), + WrapHandle((cl_mem) (dilation_.gpu_data()), &ctx), + WrapHandle((cl_mem) (pad_.gpu_data()), &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } + break; + default: + LOG(FATAL) + << "Unknown or unsupported pooling method in Backward_gpu()."; + } + } +#endif // USE_GREENTEA } - // NOLINT_NEXT_LINE(whitespace/operators) - MaxPoolBackward<<>>( - count, top_diff, mask, top_mask, top[0]->num(), channels_, - height_, width_, pooled_height_, pooled_width_, - kernel_h_, kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, - bottom_diff); - break; - case PoolingParameter_PoolMethod_AVE: - // NOLINT_NEXT_LINE(whitespace/operators) - AvePoolBackward<<>>( - count, top_diff, top[0]->num(), channels_, - height_, width_, pooled_height_, pooled_width_, kernel_h_, - kernel_w_, stride_h_, stride_w_, pad_h_, pad_w_, bottom_diff); - break; - case PoolingParameter_PoolMethod_STOCHASTIC: - // NOLINT_NEXT_LINE(whitespace/operators) - StoPoolBackward<<>>( - count, rand_idx_.gpu_data(), top_diff, - top[0]->num(), channels_, height_, width_, pooled_height_, - pooled_width_, kernel_h_, kernel_w_, stride_h_, stride_w_, - bottom_diff); - break; - default: - LOG(FATAL) << "Unknown pooling method."; } - CUDA_POST_KERNEL_CHECK; -} - INSTANTIATE_LAYER_GPU_FUNCS(PoolingLayer); - } // namespace caffe diff --git a/src/caffe/layers/power_layer.cpp b/src/caffe/layers/power_layer.cpp index d99b77ca839..605661dae51 100644 --- a/src/caffe/layers/power_layer.cpp +++ b/src/caffe/layers/power_layer.cpp @@ -20,7 +20,7 @@ template void PowerLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); // Special case where we can ignore the input: scale or power is 0. if (diff_scale_ == Dtype(0)) { Dtype value = (power_ == 0) ? Dtype(1) : pow(shift_, power_); @@ -28,7 +28,7 @@ void PowerLayer::Forward_cpu(const vector*>& bottom, return; } const Dtype* bottom_data = bottom[0]->cpu_data(); - caffe_copy(count, bottom_data, top_data); + caffe_cpu_copy(count, bottom_data, top_data); if (scale_ != Dtype(1)) { caffe_scal(count, scale_, top_data); } @@ -46,7 +46,7 @@ void PowerLayer::Backward_cpu(const vector*>& top, const vector*>& bottom) { if (propagate_down[0]) { Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); const Dtype* top_diff = top[0]->cpu_diff(); if (diff_scale_ == Dtype(0) || power_ == Dtype(1)) { caffe_set(count, diff_scale_, bottom_diff); @@ -72,7 +72,7 @@ void PowerLayer::Backward_cpu(const vector*>& top, caffe_div(count, top_data, bottom_data, bottom_diff); caffe_scal(count, power_, bottom_diff); } else { - caffe_copy(count, bottom_data, bottom_diff); + caffe_cpu_copy(count, bottom_data, bottom_diff); if (scale_ != Dtype(1)) { caffe_scal(count, scale_, bottom_diff); } diff --git a/src/caffe/layers/power_layer.cu b/src/caffe/layers/power_layer.cu index 07711c4213d..73396ac8096 100644 --- a/src/caffe/layers/power_layer.cu +++ b/src/caffe/layers/power_layer.cu @@ -3,83 +3,185 @@ #include "caffe/layers/power_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void PowerLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - // Special case where we can ignore the input: scale or power is 0. - if (diff_scale_ == Dtype(0)) { - Dtype value = (power_ == 0) ? Dtype(1) : pow(shift_, power_); - caffe_gpu_set(count, value, top_data); - return; - } - const Dtype* bottom_data = bottom[0]->gpu_data(); - caffe_copy(count, bottom_data, top_data); - if (scale_ != Dtype(1)) { - caffe_gpu_scal(count, scale_, top_data); - } - if (shift_ != Dtype(0)) { - caffe_gpu_add_scalar(count, shift_, top_data); - } - if (power_ != Dtype(1)) { - caffe_gpu_powx(count, top_data, power_, top_data); + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // Special case where we can ignore the input: scale or power is 0. + if (diff_scale_ == Dtype(0)) { + Dtype value = (power_ == 0) ? Dtype(1) : pow(shift_, power_); + caffe_gpu_set(count, value, top_data); + return; + } + const Dtype* bottom_data = bottom[0]->gpu_data(); + caffe_copy(count, bottom_data, top_data); + if (scale_ != Dtype(1)) { + caffe_gpu_scal(count, scale_, top_data); + } + if (shift_ != Dtype(0)) { + caffe_gpu_add_scalar(count, shift_, top_data); + } + if (power_ != Dtype(1)) { + caffe_gpu_powx(count, top_data, power_, top_data); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (diff_scale_ == Dtype(0)) { + Dtype value = (power_ == 0) ? Dtype(1) : pow(shift_, power_); + greentea_gpu_set(this->device_->id(), count, value, + (cl_mem) top_data, 0); + return; + } + const Dtype* bottom_data = bottom[0]->gpu_data(); + greentea_copy(count, (cl_mem) bottom_data, 0, (cl_mem) top_data, 0, + &ctx); + if (scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, scale_, + (cl_mem) top_data, 0); + } + if (shift_ != Dtype(0)) { + greentea_gpu_add_scalar(this->device_->id(), count, shift_, + (cl_mem) top_data, 0); + } + if (power_ != Dtype(1)) { + greentea_gpu_powx(this->device_->id(), count, + (cl_mem) top_data, 0, power_, (cl_mem) top_data, + 0); + } +#endif // USE_GREENTEA } } -template +template void PowerLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[0]) { Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); const Dtype* top_diff = top[0]->gpu_diff(); - if (diff_scale_ == Dtype(0) || power_ == Dtype(1)) { - caffe_gpu_set(count, diff_scale_, bottom_diff); - } else { - const Dtype* bottom_data = bottom[0]->gpu_data(); - // Compute dy/dx = scale * power * (shift + scale * x)^(power - 1) - // = diff_scale * y / (shift + scale * x) - if (power_ == Dtype(2)) { - // Special case for y = (shift + scale * x)^2 - // -> dy/dx = 2 * scale * (shift + scale * x) - // = diff_scale * shift + diff_scale * scale * x - caffe_gpu_axpby(count, diff_scale_ * scale_, bottom_data, - Dtype(0), bottom_diff); - if (shift_ != Dtype(0)) { - caffe_gpu_add_scalar(count, diff_scale_ * shift_, bottom_diff); - } - } else if (shift_ == Dtype(0)) { - // Special case for y = (scale * x)^power - // -> dy/dx = scale * power * (scale * x)^(power - 1) - // = scale * power * (scale * x)^power * (scale * x)^(-1) - // = power * y / x - const Dtype* top_data = top[0]->gpu_data(); - caffe_gpu_div(count, top_data, bottom_data, bottom_diff); - caffe_gpu_scal(count, power_, bottom_diff); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (diff_scale_ == Dtype(0) || power_ == Dtype(1)) { + caffe_gpu_set(count, diff_scale_, bottom_diff); } else { - caffe_copy(count, bottom_data, bottom_diff); - if (scale_ != Dtype(1)) { - caffe_gpu_scal(count, scale_, bottom_diff); - } - if (shift_ != Dtype(0)) { - caffe_gpu_add_scalar(count, shift_, bottom_diff); + const Dtype* bottom_data = bottom[0]->gpu_data(); + // Compute dy/dx = scale * power * (shift + scale * x)^(power - 1) + // = diff_scale * y / (shift + scale * x) + if (power_ == Dtype(2)) { + // Special case for y = (shift + scale * x)^2 + // -> dy/dx = 2 * scale * (shift + scale * x) + // = diff_scale * shift + diff_scale * scale * x + caffe_gpu_axpby(count, diff_scale_ * scale_, bottom_data, Dtype(0), + bottom_diff); + if (shift_ != Dtype(0)) { + caffe_gpu_add_scalar(count, diff_scale_ * shift_, bottom_diff); + } + } else if (shift_ == Dtype(0)) { + // Special case for y = (scale * x)^power + // -> dy/dx = scale * power * (scale * x)^(power - 1) + // = scale * power * (scale * x)^power * (scale * x)^(-1) + // = power * y / x + const Dtype* top_data = top[0]->gpu_data(); + caffe_gpu_div(count, top_data, bottom_data, bottom_diff); + caffe_gpu_scal(count, power_, bottom_diff); + } else { + caffe_copy(count, bottom_data, bottom_diff); + if (scale_ != Dtype(1)) { + caffe_gpu_scal(count, scale_, bottom_diff); + } + if (shift_ != Dtype(0)) { + caffe_gpu_add_scalar(count, shift_, bottom_diff); + } + const Dtype* top_data = top[0]->gpu_data(); + caffe_gpu_div(count, top_data, bottom_diff, bottom_diff); + if (diff_scale_ != Dtype(1)) { + caffe_gpu_scal(count, diff_scale_, bottom_diff); + } } - const Dtype* top_data = top[0]->gpu_data(); - caffe_gpu_div(count, top_data, bottom_diff, bottom_diff); - if (diff_scale_ != Dtype(1)) { - caffe_gpu_scal(count, diff_scale_, bottom_diff); + } + caffe_gpu_mul(count, top_diff, bottom_diff, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (diff_scale_ == Dtype(0) || power_ == Dtype(1)) { + greentea_gpu_set(this->device_->id(), count, diff_scale_, + (cl_mem) bottom_diff, 0); + } else { + const Dtype* bottom_data = bottom[0]->gpu_data(); + // Compute dy/dx = scale * power * (shift + scale * x)^(power - 1) + // = diff_scale * y / (shift + scale * x) + if (power_ == Dtype(2)) { + // Special case for y = (shift + scale * x)^2 + // -> dy/dx = 2 * scale * (shift + scale * x) + // = diff_scale * shift + diff_scale * scale * x + greentea_gpu_axpby(this->device_->id(), count, + diff_scale_ * scale_, (cl_mem) bottom_data, 0, + Dtype(0), (cl_mem) bottom_diff, 0); + if (shift_ != Dtype(0)) { + greentea_gpu_add_scalar(this->device_->id(), count, + diff_scale_ * shift_, (cl_mem) bottom_diff, + 0); + } + } else if (shift_ == Dtype(0)) { + // Special case for y = (scale * x)^power + // -> dy/dx = scale * power * (scale * x)^(power - 1) + // = scale * power * (scale * x)^power * (scale * x)^(-1) + // = power * y / x + const Dtype* top_data = top[0]->gpu_data(); + greentea_gpu_div(this->device_->id(), count, + (cl_mem) top_data, 0, (cl_mem) bottom_data, 0, + (cl_mem) bottom_diff, 0); + greentea_gpu_scal(this->device_->id(), count, power_, + (cl_mem) bottom_diff, 0); + } else { + greentea_copy(count, (cl_mem) bottom_data, 0, + (cl_mem) bottom_diff, 0, &ctx); + if (scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, scale_, + (cl_mem) bottom_diff, 0); + } + if (shift_ != Dtype(0)) { + greentea_gpu_add_scalar(this->device_->id(), count, shift_, + (cl_mem) bottom_diff, 0); + } + const Dtype* top_data = top[0]->gpu_data(); + greentea_gpu_div(this->device_->id(), count, + (cl_mem) top_data, 0, (cl_mem) bottom_diff, 0, + (cl_mem) bottom_diff, 0); + if (diff_scale_ != Dtype(1)) { + greentea_gpu_scal(this->device_->id(), count, diff_scale_, + (cl_mem) bottom_diff, 0); + } } } + greentea_gpu_mul(this->device_->id(), count, + (cl_mem) top_diff, 0, (cl_mem) bottom_diff, 0, + (cl_mem) bottom_diff, 0); +#endif // USE_GREENTEA } - caffe_gpu_mul(count, top_diff, bottom_diff, bottom_diff); } } INSTANTIATE_LAYER_GPU_FUNCS(PowerLayer); - } // namespace caffe diff --git a/src/caffe/layers/prelu_layer.cpp b/src/caffe/layers/prelu_layer.cpp index 853181bd5a2..3590dfba173 100644 --- a/src/caffe/layers/prelu_layer.cpp +++ b/src/caffe/layers/prelu_layer.cpp @@ -8,22 +8,24 @@ namespace caffe { -template +template void PReLULayer::LayerSetUp(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { CHECK_GE(bottom[0]->num_axes(), 2) << "Number of axes of bottom blob must be >=2."; PReLUParameter prelu_param = this->layer_param().prelu_param(); - int channels = bottom[0]->channels(); + int_tp channels = bottom[0]->channels(); channel_shared_ = prelu_param.channel_shared(); if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { this->blobs_.resize(1); if (channel_shared_) { - this->blobs_[0].reset(new Blob(vector(0))); + this->blobs_[0].reset(new Blob(vector(0), + this->device_)); } else { - this->blobs_[0].reset(new Blob(vector(1, channels))); + this->blobs_[0].reset(new Blob(vector(1, channels), + this->device_)); } shared_ptr > filler; if (prelu_param.has_filler()) { @@ -38,22 +40,22 @@ void PReLULayer::LayerSetUp(const vector*>& bottom, } if (channel_shared_) { CHECK_EQ(this->blobs_[0]->count(), 1) - << "Negative slope size is inconsistent with prototxt config"; + << "Negative slope size is inconsistent with prototxt config"; } else { CHECK_EQ(this->blobs_[0]->count(), channels) - << "Negative slope size is inconsistent with prototxt config"; + << "Negative slope size is inconsistent with prototxt config"; } // Propagate gradients to the parameters (as directed by backward pass). this->param_propagate_down_.resize(this->blobs_.size(), true); - multiplier_.Reshape(vector(1, bottom[0]->count(1))); - backward_buff_.Reshape(vector(1, bottom[0]->count(1))); + multiplier_.Reshape(vector(1, bottom[0]->count(1))); + backward_buff_.Reshape(vector(1, bottom[0]->count(1))); caffe_set(multiplier_.count(), Dtype(1), multiplier_.mutable_cpu_data()); } -template +template void PReLULayer::Reshape(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { CHECK_GE(bottom[0]->num_axes(), 2) << "Number of axes of bottom blob must be >=2."; top[0]->ReshapeLike(*bottom[0]); @@ -63,41 +65,41 @@ void PReLULayer::Reshape(const vector*>& bottom, } } -template +template void PReLULayer::Forward_cpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); - const int dim = bottom[0]->count(2); - const int channels = bottom[0]->channels(); + const int_tp count = bottom[0]->count(); + const int_tp dim = bottom[0]->count(2); + const int_tp channels = bottom[0]->channels(); const Dtype* slope_data = this->blobs_[0]->cpu_data(); // For in-place computation if (bottom[0] == top[0]) { - caffe_copy(count, bottom_data, bottom_memory_.mutable_cpu_data()); + caffe_cpu_copy(count, bottom_data, bottom_memory_.mutable_cpu_data()); } // if channel_shared, channel index in the following computation becomes // always zero. - const int div_factor = channel_shared_ ? channels : 1; - for (int i = 0; i < count; ++i) { - int c = (i / dim) % channels / div_factor; + const int_tp div_factor = channel_shared_ ? channels : 1; + for (int_tp i = 0; i < count; ++i) { + int_tp c = (i / dim) % channels / div_factor; top_data[i] = std::max(bottom_data[i], Dtype(0)) + slope_data[c] * std::min(bottom_data[i], Dtype(0)); } } -template +template void PReLULayer::Backward_cpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* slope_data = this->blobs_[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); - const int count = bottom[0]->count(); - const int dim = bottom[0]->count(2); - const int channels = bottom[0]->channels(); + const int_tp count = bottom[0]->count(); + const int_tp dim = bottom[0]->count(2); + const int_tp channels = bottom[0]->channels(); // For in-place computation if (top[0] == bottom[0]) { @@ -106,7 +108,7 @@ void PReLULayer::Backward_cpu(const vector*>& top, // if channel_shared, channel index in the following computation becomes // always zero. - const int div_factor = channel_shared_ ? channels : 1; + const int_tp div_factor = channel_shared_ ? channels : 1; // Propagte to param // Since to write bottom diff will affect top diff if top and bottom blobs @@ -114,23 +116,22 @@ void PReLULayer::Backward_cpu(const vector*>& top, // keep top_diff unchanged. if (this->param_propagate_down_[0]) { Dtype* slope_diff = this->blobs_[0]->mutable_cpu_diff(); - for (int i = 0; i < count; ++i) { - int c = (i / dim) % channels / div_factor; + for (int_tp i = 0; i < count; ++i) { + int_tp c = (i / dim) % channels / div_factor; slope_diff[c] += top_diff[i] * bottom_data[i] * (bottom_data[i] <= 0); } } // Propagate to bottom if (propagate_down[0]) { Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - for (int i = 0; i < count; ++i) { - int c = (i / dim) % channels / div_factor; - bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0) - + slope_data[c] * (bottom_data[i] <= 0)); + for (int_tp i = 0; i < count; ++i) { + int_tp c = (i / dim) % channels / div_factor; + bottom_diff[i] = top_diff[i] + * ((bottom_data[i] > 0) + slope_data[c] * (bottom_data[i] <= 0)); } } } - #ifdef CPU_ONLY STUB_GPU(PReLULayer); #endif diff --git a/src/caffe/layers/prelu_layer.cu b/src/caffe/layers/prelu_layer.cu index aeb80eacd03..2ddec5574bd 100644 --- a/src/caffe/layers/prelu_layer.cu +++ b/src/caffe/layers/prelu_layer.cu @@ -4,125 +4,218 @@ #include "caffe/layers/neuron_layer.hpp" #include "caffe/layers/prelu_layer.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { +#ifdef USE_CUDA // CUDA kernele for forward -template -__global__ void PReLUForward(const int n, const int channels, const int dim, - const Dtype* in, Dtype* out, const Dtype* slope_data, - const int div_factor) { +template +__global__ void PReLUForward(const int_tp n, const int_tp channels, + const int_tp dim, const Dtype* in, Dtype* out, + const Dtype* slope_data, const int_tp div_factor) { CUDA_KERNEL_LOOP(index, n) { - int c = (index / dim) % channels / div_factor; + int_tp c = (index / dim) % channels / div_factor; out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[c]; } } // CUDA kernel for bottom backward -template -__global__ void PReLUBackward(const int n, const int channels, const int dim, - const Dtype* in_diff, const Dtype* in_data, Dtype* out_diff, - const Dtype* slope_data, const int div_factor) { +template +__global__ void PReLUBackward(const int_tp n, const int_tp channels, + const int_tp dim, const Dtype* in_diff, + const Dtype* in_data, Dtype* out_diff, + const Dtype* slope_data, + const int_tp div_factor) { CUDA_KERNEL_LOOP(index, n) { - int c = (index / dim) % channels / div_factor; - out_diff[index] = in_diff[index] * ((in_data[index] > 0) - + (in_data[index] <= 0) * slope_data[c]); + int_tp c = (index / dim) % channels / div_factor; + out_diff[index] = in_diff[index] + * ((in_data[index] > 0) + (in_data[index] <= 0) * slope_data[c]); } } // CUDA kernel for element-wise parameter backward -template -__global__ void PReLUParamBackward(const int n, - const int rows, const int rowPitch, const Dtype* in_diff, - const Dtype* in_data, Dtype* out_diff) { +template +__global__ void PReLUParamBackward(const int_tp n, const int_tp rows, + const int_tp rowPitch, const Dtype* in_diff, + const Dtype* in_data, Dtype* out_diff) { CUDA_KERNEL_LOOP(index, n) { out_diff[index] = in_diff[index] * in_data[index] * (in_data[index] <= 0); - for ( int k = 1; k < rows; k++ ) { - out_diff[index] += in_diff[index + k*rowPitch] - * in_data[index + k*rowPitch] * (in_data[index + k*rowPitch] <= 0); + for (int k = 1; k < rows; k++) { + out_diff[index] += in_diff[index + k * rowPitch] + * in_data[index + k * rowPitch] + * (in_data[index + k * rowPitch] <= 0); } } } +#endif // USE_CUDA -template +template void PReLULayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - const int dim = bottom[0]->count(2); - const int channels = bottom[0]->channels(); + const int_tp count = bottom[0]->count(); + const int_tp dim = bottom[0]->count(2); + const int_tp channels = bottom[0]->channels(); const Dtype* slope_data = this->blobs_[0]->gpu_data(); - const int div_factor = channel_shared_ ? channels : 1; + const int_tp div_factor = channel_shared_ ? channels : 1; - // For in-place computation - if (top[0] == bottom[0]) { - caffe_copy(count, bottom_data, bottom_memory_.mutable_gpu_data()); - } + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // For in-place computation + if (top[0] == bottom[0]) { + caffe_copy(count, bottom_data, bottom_memory_.mutable_gpu_data()); + } - // NOLINT_NEXT_LINE(whitespace/operators) - PReLUForward<<>>( - count, channels, dim, bottom_data, top_data, slope_data, div_factor); - CUDA_POST_KERNEL_CHECK; + // NOLINT_NEXT_LINE(whitespace/operators) + PReLUForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, channels, dim, bottom_data, top_data, slope_data, div_factor); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if (top[0] == bottom[0]) { + greentea_copy(count, (cl_mem) bottom_data, 0, + (cl_mem) (bottom_memory_.mutable_gpu_data()), 0, + &ctx); + } + + viennacl::ocl::kernel &oclk_prelu = program.get_kernel( + CL_KERNEL_SELECT("prelu_forward")); + viennacl::ocl::enqueue( + oclk_prelu(count, channels, dim, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) slope_data, &ctx), div_factor), + ctx.get_queue()); + +#endif // USE_GREENTEA + } } -template +template void PReLULayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* bottom_data = bottom[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); - const int count = bottom[0]->count(); - const int dim = bottom[0]->count(2); - const int channels = bottom[0]->channels(); + const int_tp count = bottom[0]->count(); + const int_tp dim = bottom[0]->count(2); + const int_tp channels = bottom[0]->channels(); // For in-place computation if (top[0] == bottom[0]) { bottom_data = bottom_memory_.gpu_data(); } - // Propagate to param - // Since to write bottom diff will affect top diff if top and bottom blobs - // are identical (in-place computaion), we first compute param backward to - // keep top_diff unchanged. - if (this->param_propagate_down_[0]) { - Dtype* slope_diff = this->blobs_[0]->mutable_gpu_diff(); - int cdim = channels * dim; - - // compute element-wise diff - // NOLINT_NEXT_LINE(whitespace/operators) - PReLUParamBackward<<>>( - cdim, bottom[0]->num(), top[0]->offset(1), top_diff , - bottom_data , - backward_buff_.mutable_gpu_diff()); - CUDA_POST_KERNEL_CHECK; - if (channel_shared_) { - Dtype dsum; - caffe_gpu_dot(channels * dim, backward_buff_.gpu_diff(), - multiplier_.gpu_data(), &dsum); - caffe_gpu_add_scalar(this->blobs_[0]->count(), Dtype(dsum), slope_diff); - } else { - caffe_gpu_gemv(CblasNoTrans, channels, dim, 1., - backward_buff_.gpu_diff(), multiplier_.gpu_data(), 1., - slope_diff); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // Propagate to param + // Since to write bottom diff will affect top diff if top and bottom blobs + // are identical (in-place computaion), we first compute param backward to + // keep top_diff unchanged. + if (this->param_propagate_down_[0]) { + Dtype* slope_diff = this->blobs_[0]->mutable_gpu_diff(); + int_tp cdim = channels * dim; + + // compute element-wise diff + // NOLINT_NEXT_LINE(whitespace/operators) + PReLUParamBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(cdim), + CAFFE_CUDA_NUM_THREADS)( + cdim, bottom[0]->num(), top[0]->offset(1), top_diff , + bottom_data , + backward_buff_.mutable_gpu_diff()); + CUDA_POST_KERNEL_CHECK; + if (channel_shared_) { + Dtype dsum; + caffe_gpu_dot(channels * dim, backward_buff_.gpu_diff(), + multiplier_.gpu_data(), &dsum); + caffe_gpu_add_scalar(this->blobs_[0]->count(), Dtype(dsum), slope_diff); + } else { + caffe_gpu_gemv(CblasNoTrans, channels, dim, 1., + backward_buff_.gpu_diff(), multiplier_.gpu_data(), 1., + slope_diff); + } } - } - // Propagate to bottom - if (propagate_down[0]) { - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const Dtype* slope_data = this->blobs_[0]->gpu_data(); - int div_factor = channel_shared_ ? channels : 1; - // NOLINT_NEXT_LINE(whitespace/operators) - PReLUBackward<<>>( - count, channels, dim, top_diff, bottom_data, bottom_diff, slope_data, - div_factor); - CUDA_POST_KERNEL_CHECK; + // Propagate to bottom + if (propagate_down[0]) { + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + const Dtype* slope_data = this->blobs_[0]->gpu_data(); + int_tp div_factor = channel_shared_ ? channels : 1; + // NOLINT_NEXT_LINE(whitespace/operators) + PReLUBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, channels, dim, top_diff, bottom_data, bottom_diff, slope_data, + div_factor); + CUDA_POST_KERNEL_CHECK; + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + // Propagate to param + // Since to write bottom diff will affect top diff if top and bottom blobs + // are identical (in-place computaion), we first compute param backward to + // keep top_diff unchanged. + if (this->param_propagate_down_[0]) { + Dtype* slope_diff = this->blobs_[0]->mutable_gpu_diff(); + int_tp cdim = channels * dim; + + // compute element-wise diff + + viennacl::ocl::kernel &oclk_prelu = program.get_kernel( + CL_KERNEL_SELECT("prelu_param_backward")); + viennacl::ocl::enqueue( + oclk_prelu(cdim, bottom[0]->num(), top[0]->offset(1), + WrapHandle((cl_mem)top_diff, &ctx), + WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) (backward_buff_.mutable_gpu_diff()), &ctx)), + ctx.get_queue()); + + if (channel_shared_) { + Dtype dsum; + greentea_gpu_dot(this->device_->id(), channels * dim, + (cl_mem) (backward_buff_.gpu_diff()), 0, + (cl_mem) (multiplier_.gpu_data()), 0, &dsum); + greentea_gpu_add_scalar(this->device_->id(), + this->blobs_[0]->count(), Dtype(dsum), + (cl_mem) slope_diff, 0); + } else { + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, channels, + dim, 1., (cl_mem) (backward_buff_.gpu_diff()), + 0, (cl_mem) (multiplier_.gpu_data()), 0, 1., + (cl_mem) slope_diff, 0); + } + } + // Propagate to bottom + if (propagate_down[0]) { + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + const Dtype* slope_data = this->blobs_[0]->gpu_data(); + int_tp div_factor = channel_shared_ ? channels : 1; + viennacl::ocl::kernel &oclk_prelu = program.get_kernel( + CL_KERNEL_SELECT("prelu_backward")); + viennacl::ocl::enqueue( + oclk_prelu(count, channels, dim, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx), + WrapHandle((cl_mem) slope_data, &ctx), div_factor), + ctx.get_queue()); + } +#endif // USE_GREENTEA } } - INSTANTIATE_LAYER_GPU_FUNCS(PReLULayer); - } // namespace caffe diff --git a/src/caffe/layers/reduction_layer.cpp b/src/caffe/layers/reduction_layer.cpp index fa46487e6a3..efd5a0b08e1 100644 --- a/src/caffe/layers/reduction_layer.cpp +++ b/src/caffe/layers/reduction_layer.cpp @@ -20,7 +20,7 @@ void ReductionLayer::Reshape(const vector*>& bottom, // throw away any after that. // Note: currently reducing along non-tail axes is not supported; otherwise, // we'd need to also copy any axes following an "end_axis". - vector top_shape(bottom[0]->shape().begin(), + vector top_shape(bottom[0]->shape().begin(), bottom[0]->shape().begin() + axis_); top[0]->Reshape(top_shape); num_ = bottom[0]->count(0, axis_); @@ -28,7 +28,7 @@ void ReductionLayer::Reshape(const vector*>& bottom, CHECK_EQ(num_, top[0]->count()); if (op_ == ReductionParameter_ReductionOp_SUM || op_ == ReductionParameter_ReductionOp_MEAN) { - vector sum_mult_shape(1, dim_); + vector sum_mult_shape(1, dim_); sum_multiplier_.Reshape(sum_mult_shape); caffe_set(dim_, Dtype(1), sum_multiplier_.mutable_cpu_data()); } @@ -47,7 +47,7 @@ void ReductionLayer::Forward_cpu( mult_data = sum_multiplier_.cpu_data(); } Dtype* top_data = top[0]->mutable_cpu_data(); - for (int i = 0; i < num_; ++i) { + for (int_tp i = 0; i < num_; ++i) { switch (op_) { case ReductionParameter_ReductionOp_SUM: case ReductionParameter_ReductionOp_MEAN: @@ -95,7 +95,7 @@ void ReductionLayer::Backward_cpu(const vector*>& top, } const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - for (int i = 0; i < num_; ++i) { + for (int_tp i = 0; i < num_; ++i) { const Dtype bottom_coeff = (*top_diff) * coeff_; switch (op_) { case ReductionParameter_ReductionOp_SUM: diff --git a/src/caffe/layers/reduction_layer.cu b/src/caffe/layers/reduction_layer.cu index 4a6b2b73fc7..d3376ef0aa5 100644 --- a/src/caffe/layers/reduction_layer.cu +++ b/src/caffe/layers/reduction_layer.cu @@ -5,84 +5,182 @@ namespace caffe { -template -void ReductionLayer::Forward_gpu( - const vector*>& bottom, const vector*>& top) { +template +void ReductionLayer::Forward_gpu(const vector*>& bottom, + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); const Dtype* mult_data = NULL; - if (sum_multiplier_.count() > 0) { - mult_data = sum_multiplier_.gpu_data(); - } - Dtype* top_data = top[0]->mutable_cpu_data(); - for (int i = 0; i < num_; ++i) { - switch (op_) { - case ReductionParameter_ReductionOp_SUM: - case ReductionParameter_ReductionOp_MEAN: - caffe_gpu_dot(dim_, mult_data, bottom_data, top_data); - break; - case ReductionParameter_ReductionOp_ASUM: - caffe_gpu_asum(dim_, bottom_data, top_data); - break; - case ReductionParameter_ReductionOp_SUMSQ: - caffe_gpu_dot(dim_, bottom_data, bottom_data, top_data); - break; - default: - LOG(FATAL) << "Unknown reduction op: " + + int_tp bottom_data_off = 0; + int_tp top_data_off = 0; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (sum_multiplier_.count() > 0) { + mult_data = sum_multiplier_.gpu_data(); + } + Dtype* top_data = top[0]->mutable_cpu_data(); + for (int_tp i = 0; i < num_; ++i) { + switch (op_) { + case ReductionParameter_ReductionOp_SUM: + case ReductionParameter_ReductionOp_MEAN: + caffe_gpu_dot(dim_, mult_data, bottom_data + bottom_data_off, + top_data + top_data_off); + break; + case ReductionParameter_ReductionOp_ASUM: + caffe_gpu_asum(dim_, bottom_data + bottom_data_off, + top_data + top_data_off); + break; + case ReductionParameter_ReductionOp_SUMSQ: + caffe_gpu_dot(dim_, bottom_data + bottom_data_off, + bottom_data + bottom_data_off, top_data + top_data_off); + break; + default: + LOG(FATAL)<< "Unknown reduction op: " << ReductionParameter_ReductionOp_Name(op_); + } + bottom_data_off += dim_; + ++top_data_off; + } + if (coeff_ != Dtype(1)) { + // Reset the top_data pointer. + top_data = top[0]->mutable_gpu_data(); + caffe_gpu_scal(num_, coeff_, top_data); } - bottom_data += dim_; - ++top_data; - } - if (coeff_ != Dtype(1)) { - // Reset the top_data pointer. - top_data = top[0]->mutable_gpu_data(); - caffe_gpu_scal(num_, coeff_, top_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + if (sum_multiplier_.count() > 0) { + mult_data = sum_multiplier_.gpu_data(); + } + Dtype* top_data = top[0]->mutable_cpu_data(); + for (int_tp i = 0; i < num_; ++i) { + switch (op_) { + case ReductionParameter_ReductionOp_SUM: + case ReductionParameter_ReductionOp_MEAN: + greentea_gpu_dot(this->device_->id(), dim_, + (cl_mem) mult_data, 0, (cl_mem) bottom_data, + bottom_data_off, top_data + top_data_off); + break; + case ReductionParameter_ReductionOp_ASUM: + greentea_gpu_asum(this->device_->id(), dim_, + (cl_mem) bottom_data, bottom_data_off, + top_data + top_data_off); + break; + case ReductionParameter_ReductionOp_SUMSQ: + greentea_gpu_dot(this->device_->id(), dim_, + (cl_mem) bottom_data, bottom_data_off, + (cl_mem) bottom_data, bottom_data_off, + top_data + top_data_off); + break; + default: + LOG(FATAL)<< "Unknown reduction op: " + << ReductionParameter_ReductionOp_Name(op_); + } + bottom_data_off += dim_; + ++top_data_off; + } + if (coeff_ != Dtype(1)) { + // Reset the top_data pointer. + top_data = top[0]->mutable_gpu_data(); + greentea_gpu_scal(this->device_->id(), num_, coeff_, + (cl_mem) top_data, 0); + } +#endif // USE_GREENTEA } } -template +template void ReductionLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (!propagate_down[0]) { return; } + const vector& propagate_down, + const vector*>& bottom) { + if (!propagate_down[0]) { + return; + } // Get bottom_data, if needed. const Dtype* bottom_data = NULL; switch (op_) { - // Operations that don't need bottom_data - case ReductionParameter_ReductionOp_SUM: - case ReductionParameter_ReductionOp_MEAN: - break; - // Operations that need bottom_data - case ReductionParameter_ReductionOp_ASUM: - case ReductionParameter_ReductionOp_SUMSQ: - bottom_data = bottom[0]->gpu_data(); - break; - default: - LOG(FATAL) << "Unknown reduction op: " - << ReductionParameter_ReductionOp_Name(op_); - } - const Dtype* top_diff = top[0]->cpu_diff(); - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - for (int i = 0; i < num_; ++i) { - const Dtype bottom_coeff = (*top_diff) * coeff_; - switch (op_) { + // Operations that don't need bottom_data case ReductionParameter_ReductionOp_SUM: case ReductionParameter_ReductionOp_MEAN: - caffe_gpu_set(dim_, bottom_coeff, bottom_diff); break; + // Operations that need bottom_data case ReductionParameter_ReductionOp_ASUM: - caffe_gpu_sign(dim_, bottom_data, bottom_diff); - caffe_gpu_scal(dim_, bottom_coeff, bottom_diff); - break; case ReductionParameter_ReductionOp_SUMSQ: - caffe_gpu_scale(dim_, 2 * bottom_coeff, bottom_data, bottom_diff); + bottom_data = bottom[0]->gpu_data(); break; default: - LOG(FATAL) << "Unknown reduction op: " + LOG(FATAL)<< "Unknown reduction op: " + << ReductionParameter_ReductionOp_Name(op_); + } + const Dtype* top_diff = top[0]->cpu_diff(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + + int_tp bottom_data_off = 0; + int_tp bottom_diff_off = 0; + int_tp top_diff_off = 0; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + for (int_tp i = 0; i < num_; ++i) { + const Dtype bottom_coeff = (*(top_diff + top_diff_off)) * coeff_; + switch (op_) { + case ReductionParameter_ReductionOp_SUM: + case ReductionParameter_ReductionOp_MEAN: + caffe_gpu_set(dim_, bottom_coeff, bottom_diff + bottom_diff_off); + break; + case ReductionParameter_ReductionOp_ASUM: + caffe_gpu_sign(dim_, bottom_data + bottom_data_off, + bottom_diff + bottom_diff_off); + caffe_gpu_scal(dim_, bottom_coeff, bottom_diff + bottom_diff_off); + break; + case ReductionParameter_ReductionOp_SUMSQ: + caffe_gpu_scale(dim_, 2 * bottom_coeff, bottom_data + bottom_data_off, + bottom_diff + bottom_diff_off); + break; + default: + LOG(FATAL)<< "Unknown reduction op: " + << ReductionParameter_ReductionOp_Name(op_); + } + bottom_data_off += dim_; + bottom_diff_off += dim_; + ++top_diff_off; + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + for (int_tp i = 0; i < num_; ++i) { + const Dtype bottom_coeff = (*(top_diff + top_diff_off)) * coeff_; + switch (op_) { + case ReductionParameter_ReductionOp_SUM: + case ReductionParameter_ReductionOp_MEAN: + greentea_gpu_set(this->device_->id(), dim_, + bottom_coeff, (cl_mem) bottom_diff, + bottom_diff_off); + break; + case ReductionParameter_ReductionOp_ASUM: + greentea_gpu_sign(this->device_->id(), dim_, + (cl_mem) bottom_data, bottom_data_off, + (cl_mem) bottom_diff, bottom_diff_off); + greentea_gpu_scal(this->device_->id(), dim_, + bottom_coeff, (cl_mem) bottom_diff, + bottom_diff_off); + break; + case ReductionParameter_ReductionOp_SUMSQ: + greentea_gpu_scale(this->device_->id(), dim_, + 2 * bottom_coeff, (cl_mem) bottom_data, + bottom_data_off, (cl_mem) bottom_diff, + bottom_diff_off); + break; + default: + LOG(FATAL)<< "Unknown reduction op: " << ReductionParameter_ReductionOp_Name(op_); + } + bottom_data_off += dim_; + bottom_diff_off += dim_; + ++top_diff_off; } - bottom_data += dim_; - bottom_diff += dim_; - ++top_diff; +#endif // USE_GREENTEA } } diff --git a/src/caffe/layers/relu_layer.cpp b/src/caffe/layers/relu_layer.cpp index 92a729c81bd..c70d733b77b 100644 --- a/src/caffe/layers/relu_layer.cpp +++ b/src/caffe/layers/relu_layer.cpp @@ -10,9 +10,9 @@ void ReLULayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); Dtype negative_slope = this->layer_param_.relu_param().negative_slope(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { top_data[i] = std::max(bottom_data[i], Dtype(0)) + negative_slope * std::min(bottom_data[i], Dtype(0)); } @@ -26,9 +26,9 @@ void ReLULayer::Backward_cpu(const vector*>& top, const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); Dtype negative_slope = this->layer_param_.relu_param().negative_slope(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0) + negative_slope * (bottom_data[i] <= 0)); } diff --git a/src/caffe/layers/relu_layer.cu b/src/caffe/layers/relu_layer.cu index 4bf15b3aad3..4afd35ed6a3 100644 --- a/src/caffe/layers/relu_layer.cu +++ b/src/caffe/layers/relu_layer.cu @@ -3,27 +3,52 @@ #include "caffe/layers/relu_layer.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -__global__ void ReLUForward(const int n, const Dtype* in, Dtype* out, - Dtype negative_slope) { +#ifdef USE_CUDA +template +__global__ void ReLUForward(const int_tp n, const Dtype* in, Dtype* out, + Dtype negative_slope) { CUDA_KERNEL_LOOP(index, n) { out[index] = in[index] > 0 ? in[index] : in[index] * negative_slope; } } +#endif // USE_CUDA -template +template void ReLULayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); Dtype negative_slope = this->layer_param_.relu_param().negative_slope(); - // NOLINT_NEXT_LINE(whitespace/operators) - ReLUForward<<>>( - count, bottom_data, top_data, negative_slope); - CUDA_POST_KERNEL_CHECK; + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + ReLUForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, top_data, negative_slope); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + viennacl::ocl::kernel &oclk_relu_forward = program.get_kernel( + CL_KERNEL_SELECT("relu_forward")); + viennacl::ocl::enqueue( + oclk_relu_forward(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx), negative_slope), + ctx.get_queue()); + ctx.get_queue().finish(); +#endif // USE_GREENTEA + } // << " count: " << count << " bottom_data: " // << (unsigned long)bottom_data // << " top_data: " << (unsigned long)top_data @@ -31,34 +56,55 @@ void ReLULayer::Forward_gpu(const vector*>& bottom, // << " threads: " << CAFFE_CUDA_NUM_THREADS; } -template -__global__ void ReLUBackward(const int n, const Dtype* in_diff, - const Dtype* in_data, Dtype* out_diff, Dtype negative_slope) { +#ifdef USE_CUDA +template +__global__ void ReLUBackward(const int_tp n, const Dtype* in_diff, + const Dtype* in_data, Dtype* out_diff, + Dtype negative_slope) { CUDA_KERNEL_LOOP(index, n) { - out_diff[index] = in_diff[index] * ((in_data[index] > 0) - + (in_data[index] <= 0) * negative_slope); + out_diff[index] = in_diff[index] + * ((in_data[index] > 0) + (in_data[index] <= 0) * negative_slope); } } +#endif // USE_CUDA -template +template void ReLULayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[0]) { const Dtype* bottom_data = bottom[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); Dtype negative_slope = this->layer_param_.relu_param().negative_slope(); - // NOLINT_NEXT_LINE(whitespace/operators) - ReLUBackward<<>>( - count, top_diff, bottom_data, bottom_diff, negative_slope); - CUDA_POST_KERNEL_CHECK; + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + ReLUBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, bottom_data, bottom_diff, negative_slope); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + viennacl::ocl::kernel &oclk_relu_backward = program.get_kernel( + CL_KERNEL_SELECT("relu_backward")); + viennacl::ocl::enqueue( + oclk_relu_backward(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx), + negative_slope), + ctx.get_queue()); + ctx.get_queue().finish(); +#endif // USE_GREENTEA + } } } - INSTANTIATE_LAYER_GPU_FUNCS(ReLULayer); - } // namespace caffe diff --git a/src/caffe/layers/reshape_layer.cpp b/src/caffe/layers/reshape_layer.cpp index 45dd0902d6a..2013ba4ed30 100644 --- a/src/caffe/layers/reshape_layer.cpp +++ b/src/caffe/layers/reshape_layer.cpp @@ -12,10 +12,10 @@ void ReshapeLayer::LayerSetUp(const vector*>& bottom, inferred_axis_ = -1; copy_axes_.clear(); const BlobShape& top_blob_shape = this->layer_param_.reshape_param().shape(); - const int top_num_axes = top_blob_shape.dim_size(); + const int_tp top_num_axes = top_blob_shape.dim_size(); constant_count_ = 1; - for (int i = 0; i < top_num_axes; ++i) { - const int top_dim = top_blob_shape.dim(i); + for (int_tp i = 0; i < top_num_axes; ++i) { + const int_tp top_dim = top_blob_shape.dim(i); if (top_dim == 0) { copy_axes_.push_back(i); } else if (top_dim == -1) { @@ -31,36 +31,36 @@ void ReshapeLayer::LayerSetUp(const vector*>& bottom, template void ReshapeLayer::Reshape(const vector*>& bottom, const vector*>& top) { - const int input_start_axis = this->layer_param_.reshape_param().axis(); - const int start_axis = (input_start_axis >= 0) ? input_start_axis : + const int_tp input_start_axis = this->layer_param_.reshape_param().axis(); + const int_tp start_axis = (input_start_axis >= 0) ? input_start_axis : bottom[0]->num_axes() + input_start_axis + 1; CHECK_GE(start_axis, 0) << "axis " << input_start_axis << " out of range"; CHECK_LE(start_axis, bottom[0]->num_axes()) << "axis " << input_start_axis << " out of range for " << bottom[0]->num_axes() << "-D input blob"; - const int num_axes = this->layer_param_.reshape_param().num_axes(); + const int_tp num_axes = this->layer_param_.reshape_param().num_axes(); CHECK_GE(num_axes, -1) << "num_axes must be >= 0, or -1 for all"; - const int end_axis = + const int_tp end_axis = (num_axes == -1) ? bottom[0]->num_axes() : (start_axis + num_axes); CHECK_LE(end_axis, bottom[0]->num_axes()) << "end_axis = axis + num_axes is out of range"; - const int num_axes_replaced = end_axis - start_axis; - const int num_axes_retained = bottom[0]->num_axes() - num_axes_replaced; + const int_tp num_axes_replaced = end_axis - start_axis; + const int_tp num_axes_retained = bottom[0]->num_axes() - num_axes_replaced; const BlobShape& top_blob_shape = this->layer_param_.reshape_param().shape(); - const int num_new_axes = top_blob_shape.dim_size(); - vector top_shape(num_axes_retained + num_new_axes); - int top_shape_index = 0; - for (int i = 0; i < start_axis; ++i) { + const int_tp num_new_axes = top_blob_shape.dim_size(); + vector top_shape(num_axes_retained + num_new_axes); + int_tp top_shape_index = 0; + for (int_tp i = 0; i < start_axis; ++i) { top_shape[top_shape_index++] = bottom[0]->shape(i); } - for (int i = 0; i < num_new_axes; ++i) { + for (int_tp i = 0; i < num_new_axes; ++i) { top_shape[top_shape_index++] = top_blob_shape.dim(i); } - for (int i = end_axis; i < bottom[0]->num_axes(); ++i) { + for (int_tp i = end_axis; i < bottom[0]->num_axes(); ++i) { top_shape[top_shape_index++] = bottom[0]->shape(i); } CHECK_EQ(top_shape_index, top_shape.size()); - for (int i = 0; i < copy_axes_.size(); ++i) { - const int copy_axis_index = copy_axes_[i]; + for (int_tp i = 0; i < copy_axes_.size(); ++i) { + const int_tp copy_axis_index = copy_axes_[i]; CHECK_GT(bottom[0]->num_axes(), start_axis + copy_axis_index) << "new shape contains a 0, but there was no corresponding bottom axis " << "to copy"; @@ -70,17 +70,17 @@ void ReshapeLayer::Reshape(const vector*>& bottom, if (inferred_axis_ >= 0) { // A -1 dim was specified; infer the correct dimension by computing the // product of the other dimensions. - int explicit_count = constant_count_; + int_tp explicit_count = constant_count_; explicit_count *= bottom[0]->count(0, start_axis); explicit_count *= bottom[0]->count(end_axis); - for (int i = 0; i < copy_axes_.size(); ++i) { - const int copy_axis_index = copy_axes_[i]; + for (int_tp i = 0; i < copy_axes_.size(); ++i) { + const int_tp copy_axis_index = copy_axes_[i]; explicit_count *= top_shape[start_axis + copy_axis_index]; } CHECK_EQ(0, bottom[0]->count() % explicit_count) << "bottom count (" << bottom[0]->count() << ") must be divisible by the product of " << "the specified dimensions (" << explicit_count << ")"; - const int inferred_dim = bottom[0]->count() / explicit_count; + const int_tp inferred_dim = bottom[0]->count() / explicit_count; top_shape[start_axis + inferred_axis_] = inferred_dim; } top[0]->Reshape(top_shape); diff --git a/src/caffe/layers/scale_layer.cpp b/src/caffe/layers/scale_layer.cpp index ecdbb123e31..34ca2ea5174 100644 --- a/src/caffe/layers/scale_layer.cpp +++ b/src/caffe/layers/scale_layer.cpp @@ -17,7 +17,7 @@ void ScaleLayer::LayerSetUp(const vector*>& bottom, } else if (bottom.size() == 1) { // scale is a learned parameter; initialize it axis_ = bottom[0]->CanonicalAxisIndex(param.axis()); - const int num_axes = param.num_axes(); + const int_tp num_axes = param.num_axes(); CHECK_GE(num_axes, -1) << "num_axes must be non-negative, " << "or -1 to extend to the end of bottom[0]"; if (num_axes >= 0) { @@ -26,11 +26,11 @@ void ScaleLayer::LayerSetUp(const vector*>& bottom, << "starting with bottom[0] axis = " << axis_; } this->blobs_.resize(1); - const vector::const_iterator& shape_start = + const vector::const_iterator& shape_start = bottom[0]->shape().begin() + axis_; - const vector::const_iterator& shape_end = + const vector::const_iterator& shape_end = (num_axes == -1) ? bottom[0]->shape().end() : (shape_start + num_axes); - vector scale_shape(shape_start, shape_end); + vector scale_shape(shape_start, shape_end); this->blobs_[0].reset(new Blob(scale_shape)); FillerParameter filler_param(param.filler()); if (!param.has_filler()) { @@ -80,7 +80,7 @@ void ScaleLayer::Reshape(const vector*>& bottom, CHECK_GE(bottom[0]->num_axes(), axis_ + scale->num_axes()) << "scale blob's shape extends past bottom[0]'s shape when applied " << "starting with bottom[0] axis = " << axis_; - for (int i = 0; i < scale->num_axes(); ++i) { + for (int_tp i = 0; i < scale->num_axes(); ++i) { CHECK_EQ(bottom[0]->shape(axis_ + i), scale->shape(i)) << "dimension mismatch between bottom[0]->shape(" << axis_ + i << ") and scale->shape(" << i << ")"; @@ -93,9 +93,9 @@ void ScaleLayer::Reshape(const vector*>& bottom, } else { top[0]->ReshapeLike(*bottom[0]); } - sum_result_.Reshape(vector(1, outer_dim_ * scale_dim_)); - const int sum_mult_size = std::max(outer_dim_, inner_dim_); - sum_multiplier_.Reshape(vector(1, sum_mult_size)); + sum_result_.Reshape(vector(1, outer_dim_ * scale_dim_)); + const int_tp sum_mult_size = std::max(outer_dim_, inner_dim_); + sum_multiplier_.Reshape(vector(1, sum_mult_size)); if (sum_multiplier_.cpu_data()[sum_mult_size - 1] != Dtype(1)) { caffe_set(sum_mult_size, Dtype(1), sum_multiplier_.mutable_cpu_data()); } @@ -120,8 +120,8 @@ void ScaleLayer::Forward_cpu( const Dtype* scale_data = ((bottom.size() > 1) ? bottom[1] : this->blobs_[0].get())->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - for (int n = 0; n < outer_dim_; ++n) { - for (int d = 0; d < scale_dim_; ++d) { + for (int_tp n = 0; n < outer_dim_; ++n) { + for (int_tp d = 0; d < scale_dim_; ++d) { const Dtype factor = scale_data[d]; caffe_cpu_scale(inner_dim_, factor, bottom_data, top_data); bottom_data += inner_dim_; @@ -198,8 +198,8 @@ void ScaleLayer::Backward_cpu(const vector*>& top, const Dtype* top_diff = top[0]->cpu_diff(); const Dtype* scale_data = scale->cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - for (int n = 0; n < outer_dim_; ++n) { - for (int d = 0; d < scale_dim_; ++d) { + for (int_tp n = 0; n < outer_dim_; ++n) { + for (int_tp d = 0; d < scale_dim_; ++d) { const Dtype factor = scale_data[d]; caffe_cpu_scale(inner_dim_, factor, top_diff, bottom_diff); bottom_diff += inner_dim_; diff --git a/src/caffe/layers/scale_layer.cu b/src/caffe/layers/scale_layer.cu index fc9a8064db5..02c10dbf8e6 100644 --- a/src/caffe/layers/scale_layer.cu +++ b/src/caffe/layers/scale_layer.cu @@ -4,129 +4,266 @@ #include "caffe/layers/scale_layer.hpp" #include "caffe/util/math_functions.hpp" + +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { +#ifdef USE_CUDA template -__global__ void ScaleForward(const int n, const Dtype* in, - const Dtype* scale, const int scale_dim, const int inner_dim, +__global__ void ScaleForward(const int_tp n, const Dtype* in, + const Dtype* scale, const int_tp scale_dim, const int_tp inner_dim, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { - const int scale_index = (index / inner_dim) % scale_dim; + const int_tp scale_index = (index / inner_dim) % scale_dim; out[index] = in[index] * scale[scale_index]; } } template -__global__ void ScaleBiasForward(const int n, const Dtype* in, +__global__ void ScaleBiasForward(const int_tp n, const Dtype* in, const Dtype* scale, const Dtype* bias, - const int scale_dim, const int inner_dim, Dtype* out) { + const int_tp scale_dim, const int_tp inner_dim, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { - const int scale_index = (index / inner_dim) % scale_dim; + const int_tp scale_index = (index / inner_dim) % scale_dim; out[index] = in[index] * scale[scale_index] + bias[scale_index]; } } +#endif // USE_CUDA -template -void ScaleLayer::Forward_gpu( - const vector*>& bottom, const vector*>& top) { - const int count = top[0]->count(); +template +void ScaleLayer::Forward_gpu(const vector*>& bottom, + const vector*>& top) { + const int_tp count = top[0]->count(); const Dtype* bottom_data = bottom[0]->gpu_data(); - if (bottom[0] == top[0]) { - // in-place computation; need to store bottom data before overwriting it. - // Note that this is only necessary for Backward; we could skip this if not - // doing Backward, but Caffe currently provides no way of knowing whether - // we'll need to do Backward at the time of the Forward call. - caffe_copy(bottom[0]->count(), bottom[0]->gpu_data(), - temp_.mutable_gpu_data()); - } - const Dtype* scale_data = - ((bottom.size() > 1) ? bottom[1] : this->blobs_[0].get())->gpu_data(); - Dtype* top_data = top[0]->mutable_gpu_data(); - if (bias_layer_) { - const Dtype* bias_data = this->blobs_[bias_param_id_]->gpu_data(); - ScaleBiasForward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - count, bottom_data, scale_data, bias_data, scale_dim_, inner_dim_, - top_data); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (bottom[0] == top[0]) { + caffe_copy(bottom[0]->count(), bottom[0]->gpu_data(), + temp_.mutable_gpu_data()); + } + const Dtype* scale_data = ( + (bottom.size() > 1) ? bottom[1] : this->blobs_[0].get())->gpu_data(); + Dtype* top_data = top[0]->mutable_gpu_data(); + if (bias_layer_) { + const Dtype* bias_data = this->blobs_[bias_param_id_]->gpu_data(); + ScaleBiasForward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, scale_data, bias_data, scale_dim_, inner_dim_, + top_data); + } else { + ScaleForward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, scale_data, scale_dim_, inner_dim_, top_data); + } +#endif // USE_CUDA } else { - ScaleForward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - count, bottom_data, scale_data, scale_dim_, inner_dim_, top_data); +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if (bottom[0] == top[0]) { + greentea_copy(bottom[0]->count(), (cl_mem) (bottom[0]->gpu_data()), + 0, (cl_mem) (temp_.mutable_gpu_data()), 0, &ctx); + } + const Dtype* scale_data = ( + (bottom.size() > 1) ? bottom[1] : this->blobs_[0].get())->gpu_data(); + Dtype* top_data = top[0]->mutable_gpu_data(); + if (bias_layer_) { + const Dtype* bias_data = this->blobs_[bias_param_id_]->gpu_data(); + viennacl::ocl::kernel &oclk_scale_bias_forward = program.get_kernel( + CL_KERNEL_SELECT("scale_bias_forward")); + viennacl::ocl::enqueue( + oclk_scale_bias_forward(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) scale_data, &ctx), + WrapHandle((cl_mem) bias_data, &ctx), + scale_dim_, inner_dim_, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + } else { + viennacl::ocl::kernel &oclk_scale_forward = program.get_kernel( + CL_KERNEL_SELECT("scale_forward")); + viennacl::ocl::enqueue( + oclk_scale_forward(count, WrapHandle((cl_mem)bottom_data, &ctx), + WrapHandle((cl_mem)scale_data, &ctx), scale_dim_, + inner_dim_, WrapHandle((cl_mem)top_data, &ctx)), + ctx.get_queue()); + } +#endif // USE_GREENTEA } } -template +template void ScaleLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (bias_layer_ && - this->param_propagate_down_[this->param_propagate_down_.size() - 1]) { + const vector& propagate_down, + const vector*>& bottom) { + if (bias_layer_ + && this->param_propagate_down_[this->param_propagate_down_.size() - 1]) { bias_layer_->Backward(top, bias_propagate_down_, bias_bottom_vec_); } const bool scale_param = (bottom.size() == 1); Blob* scale = scale_param ? this->blobs_[0].get() : bottom[1]; - if ((!scale_param && propagate_down[1]) || - (scale_param && this->param_propagate_down_[0])) { - const Dtype* top_diff = top[0]->gpu_diff(); - const bool in_place = (bottom[0] == top[0]); - const Dtype* bottom_data = (in_place ? &temp_ : bottom[0])->gpu_data(); - // Hack: store big eltwise product in bottom[0] diff, except in the special - // case where this layer itself does the eltwise product, in which case we - // can store it directly in the scale diff, and we're done. - // If we're computing in-place (and not doing eltwise computation), this - // hack doesn't work and we store the product in temp_. - const bool is_eltwise = (bottom[0]->count() == scale->count()); - Dtype* product = (is_eltwise ? scale->mutable_gpu_diff() : - (in_place ? temp_.mutable_gpu_data() : bottom[0]->mutable_gpu_diff())); - caffe_gpu_mul(top[0]->count(), top_diff, bottom_data, product); - if (!is_eltwise) { - Dtype* sum_result = NULL; - if (inner_dim_ == 1) { - sum_result = product; - } else if (sum_result_.count() == 1) { - const Dtype* sum_mult = sum_multiplier_.gpu_data(); - Dtype* scale_diff = scale->mutable_cpu_diff(); - if (scale_param) { - Dtype result; - caffe_gpu_dot(inner_dim_, product, sum_mult, &result); - *scale_diff += result; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if ((!scale_param && propagate_down[1]) + || (scale_param && this->param_propagate_down_[0])) { + const Dtype* top_diff = top[0]->gpu_diff(); + const bool in_place = (bottom[0] == top[0]); + const Dtype* bottom_data = (in_place ? &temp_ : bottom[0])->gpu_data(); + const bool is_eltwise = (bottom[0]->count() == scale->count()); + Dtype* product = ( + is_eltwise ? + scale->mutable_gpu_diff() : + (in_place ? + temp_.mutable_gpu_data() : bottom[0]->mutable_gpu_diff())); + caffe_gpu_mul(top[0]->count(), top_diff, bottom_data, product); + if (!is_eltwise) { + Dtype* sum_result = NULL; + if (inner_dim_ == 1) { + sum_result = product; + } else if (sum_result_.count() == 1) { + const Dtype* sum_mult = sum_multiplier_.gpu_data(); + Dtype* scale_diff = scale->mutable_cpu_diff(); + if (scale_param) { + Dtype result; + caffe_gpu_dot(inner_dim_, product, sum_mult, &result); + *scale_diff += result; + } else { + caffe_gpu_dot(inner_dim_, product, sum_mult, scale_diff); + } } else { - caffe_gpu_dot(inner_dim_, product, sum_mult, scale_diff); + const Dtype* sum_mult = sum_multiplier_.gpu_data(); + sum_result = + (outer_dim_ == 1) ? + scale->mutable_gpu_diff() : sum_result_.mutable_gpu_data(); + caffe_gpu_gemv(CblasNoTrans, sum_result_.count(), inner_dim_, + Dtype(1), product, sum_mult, Dtype(0), sum_result); + } + if (outer_dim_ != 1) { + const Dtype* sum_mult = sum_multiplier_.gpu_data(); + if (scale_dim_ == 1) { + Dtype* scale_diff = scale->mutable_cpu_diff(); + if (scale_param) { + Dtype result; + caffe_gpu_dot(outer_dim_, sum_mult, sum_result, &result); + *scale_diff += result; + } else { + caffe_gpu_dot(outer_dim_, sum_mult, sum_result, scale_diff); + } + } else { + Dtype* scale_diff = scale->mutable_gpu_diff(); + caffe_gpu_gemv(CblasTrans, outer_dim_, scale_dim_, Dtype(1), + sum_result, sum_mult, Dtype(scale_param), + scale_diff); + } } - } else { - const Dtype* sum_mult = sum_multiplier_.gpu_data(); - sum_result = (outer_dim_ == 1) ? - scale->mutable_gpu_diff() : sum_result_.mutable_gpu_data(); - caffe_gpu_gemv(CblasNoTrans, sum_result_.count(), inner_dim_, - Dtype(1), product, sum_mult, Dtype(0), sum_result); } - if (outer_dim_ != 1) { - const Dtype* sum_mult = sum_multiplier_.gpu_data(); - if (scale_dim_ == 1) { + } + if (propagate_down[0]) { + const int_tp count = top[0]->count(); + const Dtype* top_diff = top[0]->gpu_diff(); + const Dtype* scale_data = scale->gpu_data(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + ScaleForward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS)( + count, top_diff, scale_data, scale_dim_, inner_dim_, bottom_diff); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + if ((!scale_param && propagate_down[1]) + || (scale_param && this->param_propagate_down_[0])) { + const Dtype* top_diff = top[0]->gpu_diff(); + const bool in_place = (bottom[0] == top[0]); + const Dtype* bottom_data = (in_place ? &temp_ : bottom[0])->gpu_data(); + const bool is_eltwise = (bottom[0]->count() == scale->count()); + Dtype* product = ( + is_eltwise ? + scale->mutable_gpu_diff() : + (in_place ? + temp_.mutable_gpu_data() : bottom[0]->mutable_gpu_diff())); + greentea_gpu_mul(this->device_->id(), top[0]->count(), + (cl_mem) top_diff, 0, (cl_mem) bottom_data, 0, + (cl_mem) product, 0); + if (!is_eltwise) { + Dtype* sum_result = NULL; + if (inner_dim_ == 1) { + sum_result = product; + } else if (sum_result_.count() == 1) { + const Dtype* sum_mult = sum_multiplier_.gpu_data(); Dtype* scale_diff = scale->mutable_cpu_diff(); if (scale_param) { Dtype result; - caffe_gpu_dot(outer_dim_, sum_mult, sum_result, &result); + greentea_gpu_dot(this->device_->id(), inner_dim_, + (cl_mem) product, 0, (cl_mem) sum_mult, 0, + &result); *scale_diff += result; } else { - caffe_gpu_dot(outer_dim_, sum_mult, sum_result, scale_diff); + greentea_gpu_dot(this->device_->id(), inner_dim_, + (cl_mem) product, 0, (cl_mem) sum_mult, 0, + scale_diff); } } else { - Dtype* scale_diff = scale->mutable_gpu_diff(); - caffe_gpu_gemv(CblasTrans, outer_dim_, scale_dim_, - Dtype(1), sum_result, sum_mult, Dtype(scale_param), - scale_diff); + const Dtype* sum_mult = sum_multiplier_.gpu_data(); + sum_result = + (outer_dim_ == 1) ? + scale->mutable_gpu_diff() : sum_result_.mutable_gpu_data(); + greentea_gpu_gemv(this->device_->id(), CblasNoTrans, + sum_result_.count(), inner_dim_, Dtype(1), + (cl_mem) product, 0, (cl_mem) sum_mult, 0, + Dtype(0), (cl_mem) sum_result, 0); + } + if (outer_dim_ != 1) { + const Dtype* sum_mult = sum_multiplier_.gpu_data(); + if (scale_dim_ == 1) { + Dtype* scale_diff = scale->mutable_cpu_diff(); + if (scale_param) { + Dtype result; + greentea_gpu_dot(this->device_->id(), outer_dim_, + (cl_mem) sum_mult, 0, (cl_mem) sum_result, + 0, &result); + *scale_diff += result; + } else { + greentea_gpu_dot(this->device_->id(), outer_dim_, + (cl_mem) sum_mult, 0, (cl_mem) sum_result, + 0, scale_diff); + } + } else { + Dtype* scale_diff = scale->mutable_gpu_diff(); + greentea_gpu_gemv(this->device_->id(), CblasTrans, + outer_dim_, scale_dim_, Dtype(1), + (cl_mem) sum_result, 0, (cl_mem) sum_mult, + 0, Dtype(scale_param), (cl_mem) scale_diff, + 0); + } } } } - } - if (propagate_down[0]) { - const int count = top[0]->count(); - const Dtype* top_diff = top[0]->gpu_diff(); - const Dtype* scale_data = scale->gpu_data(); - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - ScaleForward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - count, top_diff, scale_data, scale_dim_, inner_dim_, bottom_diff); + if (propagate_down[0]) { + const int_tp count = top[0]->count(); + const Dtype* top_diff = top[0]->gpu_diff(); + const Dtype* scale_data = scale->gpu_data(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + viennacl::ocl::kernel &oclk_scale_forward = program.get_kernel( + CL_KERNEL_SELECT("scale_forward")); + viennacl::ocl::enqueue( + oclk_scale_forward(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) scale_data, &ctx), scale_dim_, + inner_dim_, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); + } +#endif // USE_GREENTEA } } diff --git a/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp b/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp index 10ac9470832..7248dabc086 100644 --- a/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp +++ b/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cpp @@ -32,13 +32,13 @@ void SigmoidCrossEntropyLossLayer::Forward_cpu( sigmoid_bottom_vec_[0] = bottom[0]; sigmoid_layer_->Forward(sigmoid_bottom_vec_, sigmoid_top_vec_); // Compute the loss (negative log likelihood) - const int count = bottom[0]->count(); - const int num = bottom[0]->num(); + const int_tp count = bottom[0]->count(); + const int_tp num = bottom[0]->num(); // Stable version of loss computation from input data const Dtype* input_data = bottom[0]->cpu_data(); const Dtype* target = bottom[1]->cpu_data(); Dtype loss = 0; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { loss -= input_data[i] * (target[i] - (input_data[i] >= 0)) - log(1 + exp(input_data[i] - 2 * input_data[i] * (input_data[i] >= 0))); } @@ -55,8 +55,8 @@ void SigmoidCrossEntropyLossLayer::Backward_cpu( } if (propagate_down[0]) { // First, compute the diff - const int count = bottom[0]->count(); - const int num = bottom[0]->num(); + const int_tp count = bottom[0]->count(); + const int_tp num = bottom[0]->num(); const Dtype* sigmoid_output_data = sigmoid_output_->cpu_data(); const Dtype* target = bottom[1]->cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); diff --git a/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cu b/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cu index 046cb9d3a31..7e33af2081d 100644 --- a/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cu +++ b/src/caffe/layers/sigmoid_cross_entropy_loss_layer.cu @@ -3,32 +3,57 @@ #include "caffe/layers/sigmoid_cross_entropy_loss_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void SigmoidCrossEntropyLossLayer::Backward_gpu( const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (propagate_down[1]) { - LOG(FATAL) << this->type() - << " Layer cannot backpropagate to label inputs."; + LOG(FATAL)<< this->type() + << " Layer cannot backpropagate to label inputs."; } if (propagate_down[0]) { - // First, compute the diff - const int count = bottom[0]->count(); - const int num = bottom[0]->num(); + const int_tp count = bottom[0]->count(); + const int_tp num = bottom[0]->num(); const Dtype* sigmoid_output_data = sigmoid_output_->gpu_data(); const Dtype* target = bottom[1]->gpu_data(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - caffe_copy(count, sigmoid_output_data, bottom_diff); - caffe_gpu_axpy(count, Dtype(-1), target, bottom_diff); - // Scale down gradient - const Dtype loss_weight = top[0]->cpu_diff()[0]; - caffe_gpu_scal(count, loss_weight / num, bottom_diff); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // First, compute the diff + caffe_copy(count, sigmoid_output_data, bottom_diff); + caffe_gpu_axpy(count, Dtype(-1), target, bottom_diff); + // Scale down gradient + const Dtype loss_weight = top[0]->cpu_diff()[0]; + caffe_gpu_scal(count, loss_weight / num, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + // First, compute the diff + greentea_copy(count, (cl_mem)sigmoid_output_data, 0, + (cl_mem)bottom_diff, 0, &ctx); + greentea_gpu_axpy(this->device_->id(), count, + Dtype(-1), (cl_mem)target, 0, + (cl_mem)bottom_diff, 0); + // Scale down gradient + const Dtype loss_weight = top[0]->cpu_diff()[0]; + greentea_gpu_scal(this->device_->id(), count, loss_weight / num, + (cl_mem)bottom_diff, 0); +#endif // USE_GREENTEA + } } } INSTANTIATE_LAYER_GPU_BACKWARD(SigmoidCrossEntropyLossLayer); - } // namespace caffe diff --git a/src/caffe/layers/sigmoid_layer.cpp b/src/caffe/layers/sigmoid_layer.cpp index 85fd9676812..3535d7d61d8 100644 --- a/src/caffe/layers/sigmoid_layer.cpp +++ b/src/caffe/layers/sigmoid_layer.cpp @@ -15,8 +15,8 @@ void SigmoidLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); - for (int i = 0; i < count; ++i) { + const int_tp count = bottom[0]->count(); + for (int_tp i = 0; i < count; ++i) { top_data[i] = sigmoid(bottom_data[i]); } } @@ -29,8 +29,8 @@ void SigmoidLayer::Backward_cpu(const vector*>& top, const Dtype* top_data = top[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - const int count = bottom[0]->count(); - for (int i = 0; i < count; ++i) { + const int_tp count = bottom[0]->count(); + for (int_tp i = 0; i < count; ++i) { const Dtype sigmoid_x = top_data[i]; bottom_diff[i] = top_diff[i] * sigmoid_x * (1. - sigmoid_x); } diff --git a/src/caffe/layers/sigmoid_layer.cu b/src/caffe/layers/sigmoid_layer.cu index 184c61ede83..2d54e4f71e4 100644 --- a/src/caffe/layers/sigmoid_layer.cu +++ b/src/caffe/layers/sigmoid_layer.cu @@ -5,23 +5,45 @@ namespace caffe { -template -__global__ void SigmoidForward(const int n, const Dtype* in, Dtype* out) { +#ifdef USE_CUDA +template +__global__ void SigmoidForward(const int_tp n, const Dtype* in, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { out[index] = 1. / (1. + exp(-in[index])); } } +#endif // USE_CUDA -template +template void SigmoidLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - SigmoidForward<<>>( - count, bottom_data, top_data); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + SigmoidForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, top_data); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_sigmoid = program.get_kernel( + CL_KERNEL_SELECT("sigmoid_forward")); + viennacl::ocl::enqueue( + oclk_sigmoid(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } + // << " count: " << count << " bottom_data: " // << (unsigned long)bottom_data // << " top_data: " << (unsigned long)top_data @@ -29,32 +51,53 @@ void SigmoidLayer::Forward_gpu(const vector*>& bottom, // << " threads: " << CAFFE_CUDA_NUM_THREADS; } -template -__global__ void SigmoidBackward(const int n, const Dtype* in_diff, - const Dtype* out_data, Dtype* out_diff) { +#ifdef USE_CUDA +template +__global__ void SigmoidBackward(const int_tp n, const Dtype* in_diff, + const Dtype* out_data, Dtype* out_diff) { CUDA_KERNEL_LOOP(index, n) { const Dtype sigmoid_x = out_data[index]; out_diff[index] = in_diff[index] * sigmoid_x * (1 - sigmoid_x); } } +#endif // USE_CUDA -template +template void SigmoidLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[0]) { const Dtype* top_data = top[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - SigmoidBackward<<>>( - count, top_diff, top_data, bottom_diff); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + SigmoidBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, top_data, bottom_diff); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_sigmoid = program.get_kernel( + CL_KERNEL_SELECT("sigmoid_backward")); + viennacl::ocl::enqueue( + oclk_sigmoid(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } } INSTANTIATE_LAYER_GPU_FUNCS(SigmoidLayer); - } // namespace caffe diff --git a/src/caffe/layers/silence_layer.cpp b/src/caffe/layers/silence_layer.cpp index b2f85c52a0f..7eab0d3e4d6 100644 --- a/src/caffe/layers/silence_layer.cpp +++ b/src/caffe/layers/silence_layer.cpp @@ -8,7 +8,7 @@ namespace caffe { template void SilenceLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { if (propagate_down[i]) { caffe_set(bottom[i]->count(), Dtype(0), bottom[i]->mutable_cpu_diff()); diff --git a/src/caffe/layers/silence_layer.cu b/src/caffe/layers/silence_layer.cu index 3494f6f6731..c7b5b3e261d 100644 --- a/src/caffe/layers/silence_layer.cu +++ b/src/caffe/layers/silence_layer.cu @@ -3,21 +3,46 @@ #include "caffe/layers/silence_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template +template void SilenceLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { // Do nothing. } -template +template void SilenceLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - for (int i = 0; i < bottom.size(); ++i) { + const vector& propagate_down, + const vector*>& bottom) { + for (int_tp i = 0; i < bottom.size(); ++i) { if (propagate_down[i]) { - caffe_gpu_set(bottom[i]->count(), Dtype(0), - bottom[i]->mutable_gpu_diff()); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_set(bottom[i]->count(), Dtype(0), + bottom[i]->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_gpu_set = program.get_kernel( + CL_KERNEL_SELECT("gpu_set")); + viennacl::ocl::enqueue( + oclk_gpu_set( + bottom[i]->count(), Dtype(0), + WrapHandle((cl_mem) bottom[i]->mutable_gpu_diff(), &ctx)), + ctx.get_queue()); + ctx.get_queue().finish(); +#endif + } } } } diff --git a/src/caffe/layers/slice_layer.cpp b/src/caffe/layers/slice_layer.cpp index 759beafe0d9..08bfba9ecf9 100644 --- a/src/caffe/layers/slice_layer.cpp +++ b/src/caffe/layers/slice_layer.cpp @@ -21,10 +21,10 @@ void SliceLayer::LayerSetUp(const vector*>& bottom, template void SliceLayer::Reshape(const vector*>& bottom, const vector*>& top) { - const int num_axes = bottom[0]->num_axes(); + const int_tp num_axes = bottom[0]->num_axes(); const SliceParameter& slice_param = this->layer_param_.slice_param(); if (slice_param.has_slice_dim()) { - slice_axis_ = static_cast(slice_param.slice_dim()); + slice_axis_ = static_cast(slice_param.slice_dim()); // Don't allow negative indexing for slice_dim, a uint32 -- almost // certainly unintended. CHECK_GE(slice_axis_, 0) << "casting slice_dim from uint32 to int32 " @@ -34,23 +34,23 @@ void SliceLayer::Reshape(const vector*>& bottom, } else { slice_axis_ = bottom[0]->CanonicalAxisIndex(slice_param.axis()); } - vector top_shape = bottom[0]->shape(); - const int bottom_slice_axis = bottom[0]->shape(slice_axis_); + vector top_shape = bottom[0]->shape(); + const int_tp bottom_slice_axis = bottom[0]->shape(slice_axis_); num_slices_ = bottom[0]->count(0, slice_axis_); slice_size_ = bottom[0]->count(slice_axis_ + 1); - int count = 0; + int_tp count = 0; if (slice_point_.size() != 0) { CHECK_EQ(slice_point_.size(), top.size() - 1); CHECK_LE(top.size(), bottom_slice_axis); - int prev = 0; - vector slices; - for (int i = 0; i < slice_point_.size(); ++i) { + int_tp prev = 0; + vector slices; + for (int_tp i = 0; i < slice_point_.size(); ++i) { CHECK_GT(slice_point_[i], prev); slices.push_back(slice_point_[i] - prev); prev = slice_point_[i]; } slices.push_back(bottom_slice_axis - prev); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { top_shape[slice_axis_] = slices[i]; top[i]->Reshape(top_shape); count += top[i]->count(); @@ -60,7 +60,7 @@ void SliceLayer::Reshape(const vector*>& bottom, << "Number of top blobs (" << top.size() << ") should evenly " << "divide input slice axis (" << bottom_slice_axis << ")"; top_shape[slice_axis_] = bottom_slice_axis / top.size(); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { top[i]->Reshape(top_shape); count += top[i]->count(); } @@ -76,17 +76,17 @@ template void SliceLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { if (top.size() == 1) { return; } - int offset_slice_axis = 0; + int_tp offset_slice_axis = 0; const Dtype* bottom_data = bottom[0]->cpu_data(); - const int bottom_slice_axis = bottom[0]->shape(slice_axis_); - for (int i = 0; i < top.size(); ++i) { + const int_tp bottom_slice_axis = bottom[0]->shape(slice_axis_); + for (int_tp i = 0; i < top.size(); ++i) { Dtype* top_data = top[i]->mutable_cpu_data(); - const int top_slice_axis = top[i]->shape(slice_axis_); - for (int n = 0; n < num_slices_; ++n) { - const int top_offset = n * top_slice_axis * slice_size_; - const int bottom_offset = + const int_tp top_slice_axis = top[i]->shape(slice_axis_); + for (int_tp n = 0; n < num_slices_; ++n) { + const int_tp top_offset = n * top_slice_axis * slice_size_; + const int_tp bottom_offset = (n * bottom_slice_axis + offset_slice_axis) * slice_size_; - caffe_copy(top_slice_axis * slice_size_, + caffe_cpu_copy(top_slice_axis * slice_size_, bottom_data + bottom_offset, top_data + top_offset); } offset_slice_axis += top_slice_axis; @@ -97,17 +97,17 @@ template void SliceLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (!propagate_down[0] || top.size() == 1) { return; } - int offset_slice_axis = 0; + int_tp offset_slice_axis = 0; Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - const int bottom_slice_axis = bottom[0]->shape(slice_axis_); - for (int i = 0; i < top.size(); ++i) { + const int_tp bottom_slice_axis = bottom[0]->shape(slice_axis_); + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->cpu_diff(); - const int top_slice_axis = top[i]->shape(slice_axis_); - for (int n = 0; n < num_slices_; ++n) { - const int top_offset = n * top_slice_axis * slice_size_; - const int bottom_offset = + const int_tp top_slice_axis = top[i]->shape(slice_axis_); + for (int_tp n = 0; n < num_slices_; ++n) { + const int_tp top_offset = n * top_slice_axis * slice_size_; + const int_tp bottom_offset = (n * bottom_slice_axis + offset_slice_axis) * slice_size_; - caffe_copy(top_slice_axis * slice_size_, + caffe_cpu_copy(top_slice_axis * slice_size_, top_diff + top_offset, bottom_diff + bottom_offset); } offset_slice_axis += top_slice_axis; diff --git a/src/caffe/layers/slice_layer.cu b/src/caffe/layers/slice_layer.cu index 1be3a797d3e..fe4a334ce02 100644 --- a/src/caffe/layers/slice_layer.cu +++ b/src/caffe/layers/slice_layer.cu @@ -5,17 +5,20 @@ namespace caffe { -template -__global__ void Slice(const int nthreads, const Dtype* in_data, - const bool forward, const int num_slices, const int slice_size, - const int bottom_slice_axis, const int top_slice_axis, - const int offset_slice_axis, Dtype* out_data) { +#ifdef USE_CUDA +template +__global__ void Slice(const int_tp nthreads, const Dtype* in_data, + const bool forward, const int_tp num_slices, + const int_tp slice_size, const int_tp bottom_slice_axis, + const int_tp top_slice_axis, + const int_tp offset_slice_axis, + Dtype* out_data) { CUDA_KERNEL_LOOP(index, nthreads) { - const int total_slice_size = slice_size * top_slice_axis; - const int slice_num = index / total_slice_size; - const int slice_index = index % total_slice_size; - const int bottom_index = slice_index + - (slice_num * bottom_slice_axis + offset_slice_axis) * slice_size; + const int_tp total_slice_size = slice_size * top_slice_axis; + const int_tp slice_num = index / total_slice_size; + const int_tp slice_index = index % total_slice_size; + const int_tp bottom_index = slice_index + + (slice_num * bottom_slice_axis + offset_slice_axis) * slice_size; if (forward) { out_data[index] = in_data[bottom_index]; } else { @@ -23,45 +26,87 @@ __global__ void Slice(const int nthreads, const Dtype* in_data, } } } +#endif // USE_CUDA -template +template void SliceLayer::Forward_gpu(const vector*>& bottom, const vector*>& top) { if (top.size() == 1) { return; } - int offset_slice_axis = 0; + int_tp offset_slice_axis = 0; const Dtype* bottom_data = bottom[0]->gpu_data(); - const int bottom_slice_axis = bottom[0]->shape(slice_axis_); + const int_tp bottom_slice_axis = bottom[0]->shape(slice_axis_); const bool kForward = true; - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { Dtype* top_data = top[i]->mutable_gpu_data(); - const int top_slice_axis = top[i]->shape(slice_axis_); - const int top_slice_size = top_slice_axis * slice_size_; - const int nthreads = top_slice_size * num_slices_; - Slice // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - nthreads, bottom_data, kForward, num_slices_, slice_size_, - bottom_slice_axis, top_slice_axis, offset_slice_axis, top_data); + const int_tp top_slice_axis = top[i]->shape(slice_axis_); + const int_tp top_slice_size = top_slice_axis * slice_size_; + const int_tp nthreads = top_slice_size * num_slices_; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + Slice // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), CAFFE_CUDA_NUM_THREADS)( + nthreads, bottom_data, kForward, num_slices_, slice_size_, + bottom_slice_axis, top_slice_axis, offset_slice_axis, top_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_slice = program.get_kernel( + CL_KERNEL_SELECT("slice")); + viennacl::ocl::enqueue( + oclk_slice(nthreads, WrapHandle((cl_mem) bottom_data, &ctx), + kForward ? 1 : 0, num_slices_, slice_size_, + bottom_slice_axis, top_slice_axis, offset_slice_axis, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } + offset_slice_axis += top_slice_axis; } } -template +template void SliceLayer::Backward_gpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (!propagate_down[0] || top.size() == 1) { return; } - int offset_slice_axis = 0; + int_tp offset_slice_axis = 0; Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int bottom_slice_axis = bottom[0]->shape(slice_axis_); + const int_tp bottom_slice_axis = bottom[0]->shape(slice_axis_); const bool kForward = false; - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->gpu_diff(); - const int top_slice_axis = top[i]->shape(slice_axis_); - const int top_slice_size = top_slice_axis * slice_size_; - const int nthreads = top_slice_size * num_slices_; - Slice // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - nthreads, top_diff, kForward, num_slices_, slice_size_, - bottom_slice_axis, top_slice_axis, offset_slice_axis, bottom_diff); + const int_tp top_slice_axis = top[i]->shape(slice_axis_); + const int_tp top_slice_size = top_slice_axis * slice_size_; + const int_tp nthreads = top_slice_size * num_slices_; + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + Slice // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), CAFFE_CUDA_NUM_THREADS)( + nthreads, top_diff, kForward, num_slices_, slice_size_, + bottom_slice_axis, top_slice_axis, offset_slice_axis, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_slice = program.get_kernel( + CL_KERNEL_SELECT("slice")); + viennacl::ocl::enqueue( + oclk_slice(nthreads, WrapHandle((cl_mem) top_diff, &ctx), + kForward ? 1 : 0, num_slices_, slice_size_, + bottom_slice_axis, top_slice_axis, offset_slice_axis, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } offset_slice_axis += top_slice_axis; } } diff --git a/src/caffe/layers/softmax_layer.cpp b/src/caffe/layers/softmax_layer.cpp index f60e9b03ebf..23705bc7f9d 100644 --- a/src/caffe/layers/softmax_layer.cpp +++ b/src/caffe/layers/softmax_layer.cpp @@ -12,13 +12,13 @@ void SoftmaxLayer::Reshape(const vector*>& bottom, softmax_axis_ = bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis()); top[0]->ReshapeLike(*bottom[0]); - vector mult_dims(1, bottom[0]->shape(softmax_axis_)); + vector mult_dims(1, bottom[0]->shape(softmax_axis_)); sum_multiplier_.Reshape(mult_dims); Dtype* multiplier_data = sum_multiplier_.mutable_cpu_data(); caffe_set(sum_multiplier_.count(), Dtype(1), multiplier_data); outer_num_ = bottom[0]->count(0, softmax_axis_); inner_num_ = bottom[0]->count(softmax_axis_ + 1); - vector scale_dims = bottom[0]->shape(); + vector scale_dims = bottom[0]->shape(); scale_dims[softmax_axis_] = 1; scale_.Reshape(scale_dims); } @@ -29,16 +29,16 @@ void SoftmaxLayer::Forward_cpu(const vector*>& bottom, const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); Dtype* scale_data = scale_.mutable_cpu_data(); - int channels = bottom[0]->shape(softmax_axis_); - int dim = bottom[0]->count() / outer_num_; - caffe_copy(bottom[0]->count(), bottom_data, top_data); + int_tp channels = bottom[0]->shape(softmax_axis_); + int_tp dim = bottom[0]->count() / outer_num_; + caffe_cpu_copy(bottom[0]->count(), bottom_data, top_data); // We need to subtract the max to avoid numerical issues, compute the exp, // and then normalize. - for (int i = 0; i < outer_num_; ++i) { + for (int_tp i = 0; i < outer_num_; ++i) { // initialize scale_data to the first plane - caffe_copy(inner_num_, bottom_data + i * dim, scale_data); - for (int j = 0; j < channels; j++) { - for (int k = 0; k < inner_num_; k++) { + caffe_cpu_copy(inner_num_, bottom_data + i * dim, scale_data); + for (int_tp j = 0; j < channels; j++) { + for (int_tp k = 0; k < inner_num_; k++) { scale_data[k] = std::max(scale_data[k], bottom_data[i * dim + j * inner_num_ + k]); } @@ -52,7 +52,7 @@ void SoftmaxLayer::Forward_cpu(const vector*>& bottom, caffe_cpu_gemv(CblasTrans, channels, inner_num_, 1., top_data, sum_multiplier_.cpu_data(), 0., scale_data); // division - for (int j = 0; j < channels; j++) { + for (int_tp j = 0; j < channels; j++) { caffe_div(inner_num_, top_data, scale_data, top_data); top_data += inner_num_; } @@ -67,12 +67,12 @@ void SoftmaxLayer::Backward_cpu(const vector*>& top, const Dtype* top_data = top[0]->cpu_data(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); Dtype* scale_data = scale_.mutable_cpu_data(); - int channels = top[0]->shape(softmax_axis_); - int dim = top[0]->count() / outer_num_; - caffe_copy(top[0]->count(), top_diff, bottom_diff); - for (int i = 0; i < outer_num_; ++i) { + int_tp channels = top[0]->shape(softmax_axis_); + int_tp dim = top[0]->count() / outer_num_; + caffe_cpu_copy(top[0]->count(), top_diff, bottom_diff); + for (int_tp i = 0; i < outer_num_; ++i) { // compute dot(top_diff, top_data) and subtract them from the bottom diff - for (int k = 0; k < inner_num_; ++k) { + for (int_tp k = 0; k < inner_num_; ++k) { scale_data[k] = caffe_cpu_strided_dot(channels, bottom_diff + i * dim + k, inner_num_, top_data + i * dim + k, inner_num_); diff --git a/src/caffe/layers/softmax_layer.cu b/src/caffe/layers/softmax_layer.cu index 7a9e6833bf6..4d701c8fe07 100644 --- a/src/caffe/layers/softmax_layer.cu +++ b/src/caffe/layers/softmax_layer.cu @@ -2,147 +2,260 @@ #include #include +#ifdef USE_CUDA #include "thrust/device_vector.h" +#endif #include "caffe/layers/softmax_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -__global__ void kernel_channel_max(const int num, const int channels, - const int spatial_dim, const Dtype* data, Dtype* out) { +#ifdef USE_CUDA +template +__global__ void kernel_channel_max(const int_tp num, const int_tp channels, + const int_tp spatial_dim, const Dtype* data, + Dtype* out) { CUDA_KERNEL_LOOP(index, num * spatial_dim) { - int n = index / spatial_dim; - int s = index % spatial_dim; + int_tp n = index / spatial_dim; + int_tp s = index % spatial_dim; Dtype maxval = -FLT_MAX; - for (int c = 0; c < channels; ++c) { + for (int_tp c = 0; c < channels; ++c) { maxval = max(data[(n * channels + c) * spatial_dim + s], maxval); } out[index] = maxval; } } -template -__global__ void kernel_channel_subtract(const int count, - const int num, const int channels, - const int spatial_dim, const Dtype* channel_max, Dtype* data) { +template +__global__ void kernel_channel_subtract(const int_tp count, const int_tp num, + const int_tp channels, + const int_tp spatial_dim, + const Dtype* channel_max, Dtype* data) { CUDA_KERNEL_LOOP(index, count) { - int n = index / channels / spatial_dim; - int s = index % spatial_dim; + int_tp n = index / channels / spatial_dim; + int_tp s = index % spatial_dim; data[index] -= channel_max[n * spatial_dim + s]; } } -template -__global__ void kernel_exp(const int count, const Dtype* data, Dtype* out) { +template +__global__ void kernel_exp(const int_tp count, const Dtype* data, Dtype* out) { CUDA_KERNEL_LOOP(index, count) { out[index] = exp(data[index]); } } -template -__global__ void kernel_channel_sum(const int num, const int channels, - const int spatial_dim, const Dtype* data, Dtype* channel_sum) { +template +__global__ void kernel_channel_sum(const int_tp num, const int_tp channels, + const int_tp spatial_dim, const Dtype* data, + Dtype* channel_sum) { CUDA_KERNEL_LOOP(index, num * spatial_dim) { - int n = index / spatial_dim; - int s = index % spatial_dim; + int_tp n = index / spatial_dim; + int_tp s = index % spatial_dim; Dtype sum = 0; - for (int c = 0; c < channels; ++c) { + for (int_tp c = 0; c < channels; ++c) { sum += data[(n * channels + c) * spatial_dim + s]; } channel_sum[index] = sum; } } -template -__global__ void kernel_channel_div(const int count, - const int num, const int channels, - const int spatial_dim, const Dtype* channel_sum, Dtype* data) { +template +__global__ void kernel_channel_div(const int_tp count, const int_tp num, + const int_tp channels, + const int_tp spatial_dim, + const Dtype* channel_sum, Dtype* data) { CUDA_KERNEL_LOOP(index, count) { - int n = index / channels / spatial_dim; - int s = index % spatial_dim; + int_tp n = index / channels / spatial_dim; + int_tp s = index % spatial_dim; data[index] /= channel_sum[n * spatial_dim + s]; } } -template -__global__ void kernel_channel_dot(const int num, const int channels, - const int spatial_dim, const Dtype* data_1, const Dtype* data_2, - Dtype* channel_dot) { +template +__global__ void kernel_channel_dot(const int_tp num, const int_tp channels, + const int_tp spatial_dim, + const Dtype* data_1, const Dtype* data_2, + Dtype* channel_dot) { CUDA_KERNEL_LOOP(index, num * spatial_dim) { - int n = index / spatial_dim; - int s = index % spatial_dim; + int_tp n = index / spatial_dim; + int_tp s = index % spatial_dim; Dtype dot = 0; - for (int c = 0; c < channels; ++c) { + for (int_tp c = 0; c < channels; ++c) { dot += (data_1[(n * channels + c) * spatial_dim + s] * data_2[(n * channels + c) * spatial_dim + s]); } channel_dot[index] = dot; } } +#endif -template +template void SoftmaxLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); Dtype* scale_data = scale_.mutable_gpu_data(); - int count = bottom[0]->count(); - int channels = top[0]->shape(softmax_axis_); - caffe_copy(count, bottom_data, top_data); - // We need to subtract the max to avoid numerical issues, compute the exp, - // and then normalize. - // compute max - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_channel_max<<>>(outer_num_, channels, inner_num_, top_data, - scale_data); - // subtract - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_channel_subtract<<>>(count, outer_num_, channels, inner_num_, - scale_data, top_data); - // exponentiate - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_exp<<>>( - count, top_data, top_data); - // sum after exp - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_channel_sum<<>>(outer_num_, channels, inner_num_, top_data, - scale_data); - // divide - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_channel_div<<>>(count, outer_num_, channels, inner_num_, - scale_data, top_data); + int_tp count = bottom[0]->count(); + int_tp channels = top[0]->shape(softmax_axis_); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // CUDA backend code + caffe_copy(count, bottom_data, top_data); + // We need to subtract the max to avoid numerical issues, compute the exp, + // and then normalize. + // compute max + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_channel_max CUDA_KERNEL( + CAFFE_GET_BLOCKS(outer_num_ * inner_num_), + CAFFE_CUDA_NUM_THREADS)(outer_num_, channels, inner_num_, top_data, + scale_data); + // subtract + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_channel_subtract CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)(count, outer_num_, channels, inner_num_, + scale_data, top_data); + // exponentiate + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_exp CUDA_KERNEL( + CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)(count, top_data, + top_data); + // sum after exp + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_channel_sum CUDA_KERNEL( + CAFFE_GET_BLOCKS(outer_num_ * inner_num_), + CAFFE_CUDA_NUM_THREADS)(outer_num_, channels, + inner_num_, top_data, scale_data); + // divide + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_channel_div CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)(count, outer_num_, channels, inner_num_, + scale_data, top_data); +#endif + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + greentea_copy(count, (cl_mem) bottom_data, 0, (cl_mem) top_data, 0, + &ctx); + + viennacl::ocl::kernel &oclk_channel_max = program.get_kernel( + CL_KERNEL_SELECT("kernel_channel_max")); + viennacl::ocl::enqueue( + oclk_channel_max(outer_num_, channels, inner_num_, + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) scale_data, &ctx)), + ctx.get_queue()); + + viennacl::ocl::kernel &oclk_channel_subtract = program.get_kernel( + CL_KERNEL_SELECT("kernel_channel_subtract")); + viennacl::ocl::enqueue( + oclk_channel_subtract(count, outer_num_, channels, inner_num_, + WrapHandle((cl_mem) scale_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + + viennacl::ocl::kernel &oclk_exp = program.get_kernel( + CL_KERNEL_SELECT("kernel_exp")); + viennacl::ocl::enqueue( + oclk_exp(count, + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + + viennacl::ocl::kernel &oclk_channel_sum = program.get_kernel( + CL_KERNEL_SELECT("kernel_channel_sum")); + viennacl::ocl::enqueue( + oclk_channel_sum(outer_num_, channels, inner_num_, + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) scale_data, &ctx)), + ctx.get_queue()); + + viennacl::ocl::kernel &oclk_channel_div = program.get_kernel( + CL_KERNEL_SELECT("kernel_channel_div")); + viennacl::ocl::enqueue( + oclk_channel_div(count, outer_num_, channels, inner_num_, + WrapHandle((cl_mem) scale_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + +#endif + } } -template +template void SoftmaxLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { const Dtype* top_diff = top[0]->gpu_diff(); const Dtype* top_data = top[0]->gpu_data(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); Dtype* scale_data = scale_.mutable_gpu_data(); - int count = top[0]->count(); - int channels = top[0]->shape(softmax_axis_); - caffe_copy(count, top_diff, bottom_diff); - // Compute inner1d(top_diff, top_data) and subtract them from the bottom diff. - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_channel_dot<<>>(outer_num_, channels, inner_num_, - top_diff, top_data, scale_data); - // NOLINT_NEXT_LINE(whitespace/operators) - kernel_channel_subtract<<>>(count, outer_num_, channels, inner_num_, - scale_data, bottom_diff); - // elementwise multiplication - caffe_gpu_mul(top[0]->count(), bottom_diff, top_data, bottom_diff); + int_tp count = top[0]->count(); + int_tp channels = top[0]->shape(softmax_axis_); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_copy(top[0]->count(), top_diff, bottom_diff); + // Compute inner1d(top_diff, top_data) and + // subtract them from the bottom diff. + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_channel_dot CUDA_KERNEL( + CAFFE_GET_BLOCKS(outer_num_ * inner_num_), + CAFFE_CUDA_NUM_THREADS)(outer_num_, channels, inner_num_, + top_diff, top_data, scale_data); + // NOLINT_NEXT_LINE(whitespace/operators) + kernel_channel_subtract CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)(count, outer_num_, channels, inner_num_, + scale_data, bottom_diff); + // elementwise multiplication + caffe_gpu_mul(top[0]->count(), bottom_diff, top_data, bottom_diff); +#endif + } else { +#ifdef USE_GREENTEA + + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + greentea_copy(top[0]->count(), (cl_mem)top_diff, + 0, (cl_mem)bottom_diff, 0, &ctx); + + viennacl::ocl::kernel &oclk_channel_dot = program.get_kernel( + CL_KERNEL_SELECT("kernel_channel_dot")); + viennacl::ocl::enqueue( + oclk_channel_dot(outer_num_, channels, inner_num_, + WrapHandle((cl_mem)top_diff, &ctx), + WrapHandle((cl_mem)top_data, &ctx), + WrapHandle((cl_mem)scale_data, &ctx)), + ctx.get_queue()); + + viennacl::ocl::kernel &oclk_channel_subtract = program.get_kernel( + CL_KERNEL_SELECT("kernel_channel_subtract")); + viennacl::ocl::enqueue( + oclk_channel_subtract(count, outer_num_, channels, inner_num_, + WrapHandle((cl_mem)scale_data, &ctx), + WrapHandle((cl_mem)bottom_diff, &ctx)), + ctx.get_queue()); + + greentea_gpu_mul(this->device_->id(), top[0]->count(), + (cl_mem)bottom_diff, 0, + (cl_mem)top_data, 0, (cl_mem)bottom_diff, 0); + +#endif + } } INSTANTIATE_LAYER_GPU_FUNCS(SoftmaxLayer); - } // namespace caffe diff --git a/src/caffe/layers/softmax_loss_layer.cpp b/src/caffe/layers/softmax_loss_layer.cpp index dddb7606573..cfdbc891c89 100644 --- a/src/caffe/layers/softmax_loss_layer.cpp +++ b/src/caffe/layers/softmax_loss_layer.cpp @@ -57,7 +57,7 @@ void SoftmaxWithLossLayer::Reshape( template Dtype SoftmaxWithLossLayer::get_normalizer( - LossParameter_NormalizationMode normalization_mode, int valid_count) { + LossParameter_NormalizationMode normalization_mode, int_tp valid_count) { Dtype normalizer; switch (normalization_mode) { case LossParameter_NormalizationMode_FULL: @@ -92,12 +92,12 @@ void SoftmaxWithLossLayer::Forward_cpu( softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_); const Dtype* prob_data = prob_.cpu_data(); const Dtype* label = bottom[1]->cpu_data(); - int dim = prob_.count() / outer_num_; - int count = 0; + int_tp dim = prob_.count() / outer_num_; + int_tp count = 0; Dtype loss = 0; - for (int i = 0; i < outer_num_; ++i) { - for (int j = 0; j < inner_num_; j++) { - const int label_value = static_cast(label[i * inner_num_ + j]); + for (int_tp i = 0; i < outer_num_; ++i) { + for (int_tp j = 0; j < inner_num_; j++) { + const int_tp label_value = static_cast(label[i * inner_num_ + j]); if (has_ignore_label_ && label_value == ignore_label_) { continue; } @@ -124,15 +124,16 @@ void SoftmaxWithLossLayer::Backward_cpu(const vector*>& top, if (propagate_down[0]) { Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); const Dtype* prob_data = prob_.cpu_data(); - caffe_copy(prob_.count(), prob_data, bottom_diff); + caffe_cpu_copy(prob_.count(), prob_data, bottom_diff); const Dtype* label = bottom[1]->cpu_data(); - int dim = prob_.count() / outer_num_; - int count = 0; - for (int i = 0; i < outer_num_; ++i) { - for (int j = 0; j < inner_num_; ++j) { - const int label_value = static_cast(label[i * inner_num_ + j]); + int_tp dim = prob_.count() / outer_num_; + int_tp count = 0; + for (int_tp i = 0; i < outer_num_; ++i) { + for (int_tp j = 0; j < inner_num_; ++j) { + const int_tp label_value = static_cast + (label[i * inner_num_ + j]); if (has_ignore_label_ && label_value == ignore_label_) { - for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) { + for (int_tp c = 0; c < bottom[0]->shape(softmax_axis_); ++c) { bottom_diff[i * dim + c * inner_num_ + j] = 0; } } else { diff --git a/src/caffe/layers/softmax_loss_layer.cu b/src/caffe/layers/softmax_loss_layer.cu index 660e1b39fe0..e58484d9a19 100644 --- a/src/caffe/layers/softmax_loss_layer.cu +++ b/src/caffe/layers/softmax_loss_layer.cu @@ -5,78 +5,139 @@ #include "caffe/layers/softmax_loss_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -__global__ void SoftmaxLossForwardGPU(const int nthreads, - const Dtype* prob_data, const Dtype* label, Dtype* loss, - const int num, const int dim, const int spatial_dim, - const bool has_ignore_label_, const int ignore_label_, - Dtype* counts) { +#ifdef USE_CUDA +template +__global__ void SoftmaxLossForwardGPU(const int_tp nthreads, + const Dtype* prob_data, + const Dtype* label, Dtype* loss, + const int_tp num, const int_tp dim, + const int_tp spatial_dim, + const bool has_ignore_label_, + const int_tp ignore_label_, + Dtype* counts) { CUDA_KERNEL_LOOP(index, nthreads) { - const int n = index / spatial_dim; - const int s = index % spatial_dim; - const int label_value = static_cast(label[n * spatial_dim + s]); + const int_tp n = index / spatial_dim; + const int_tp s = index % spatial_dim; + const int_tp label_value = static_cast(label[n * spatial_dim + s]); if (has_ignore_label_ && label_value == ignore_label_) { loss[index] = 0; counts[index] = 0; } else { - loss[index] = -log(max(prob_data[n * dim + label_value * spatial_dim + s], - Dtype(FLT_MIN))); + loss[index] = -log( + max(prob_data[n * dim + label_value * spatial_dim + s], + Dtype(FLT_MIN))); counts[index] = 1; } } } +#endif // USE_CUDA -template +template void SoftmaxWithLossLayer::Forward_gpu( const vector*>& bottom, const vector*>& top) { softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_); - const Dtype* prob_data = prob_.gpu_data(); - const Dtype* label = bottom[1]->gpu_data(); - const int dim = prob_.count() / outer_num_; - const int nthreads = outer_num_ * inner_num_; - // Since this memory is not used for anything until it is overwritten - // on the backward pass, we use it here to avoid having to allocate new GPU - // memory to accumulate intermediate results in the kernel. - Dtype* loss_data = bottom[0]->mutable_gpu_diff(); - // Similarly, this memory is never used elsewhere, and thus we can use it - // to avoid having to allocate additional GPU memory. - Dtype* counts = prob_.mutable_gpu_diff(); - // NOLINT_NEXT_LINE(whitespace/operators) - SoftmaxLossForwardGPU<<>>(nthreads, prob_data, label, loss_data, - outer_num_, dim, inner_num_, has_ignore_label_, ignore_label_, counts); - Dtype loss; - caffe_gpu_asum(nthreads, loss_data, &loss); - Dtype valid_count = -1; - // Only launch another CUDA kernel if we actually need the count of valid - // outputs. - if (normalization_ == LossParameter_NormalizationMode_VALID && - has_ignore_label_) { - caffe_gpu_asum(nthreads, counts, &valid_count); - } - top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, - valid_count); - if (top.size() == 2) { - top[1]->ShareData(prob_); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + const Dtype* prob_data = prob_.gpu_data(); + const Dtype* label = bottom[1]->gpu_data(); + const int_tp dim = prob_.count() / outer_num_; + const int_tp nthreads = outer_num_ * inner_num_; + // Since this memory is not used for anything until it is overwritten + // on the backward pass, we use it here to avoid having to allocate new GPU + // memory to accumulate intermediate results in the kernel. + Dtype* loss_data = bottom[0]->mutable_gpu_diff(); + // Similarly, this memory is never used elsewhere, and thus we can use it + // to avoid having to allocate additional GPU memory. + Dtype* counts = prob_.mutable_gpu_diff(); + // NOLINT_NEXT_LINE(whitespace/operators) + SoftmaxLossForwardGPU CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), + CAFFE_CUDA_NUM_THREADS)(nthreads, prob_data, + label, loss_data, outer_num_, + dim, inner_num_, has_ignore_label_, ignore_label_, counts); + Dtype loss; + caffe_gpu_asum(nthreads, loss_data, &loss); + Dtype valid_count = -1; + // Only launch another CUDA kernel if we actually need the count of valid + // outputs. + if (normalization_ == LossParameter_NormalizationMode_VALID + && has_ignore_label_) { + caffe_gpu_asum(nthreads, counts, &valid_count); + } + top[0]->mutable_cpu_data()[0] = loss + / get_normalizer(normalization_, valid_count); + if (top.size() >= 2) { + top[1]->ShareData(prob_); + } + +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + cl_mem prob_data = (cl_mem) (prob_.gpu_data()); + cl_mem label = (cl_mem) (bottom[1]->gpu_data()); + const int_tp dim = prob_.count() / outer_num_; + const int_tp nthreads = outer_num_ * inner_num_; + cl_mem loss_data = (cl_mem) (bottom[0]->mutable_gpu_diff()); + cl_mem counts = (cl_mem) (prob_.mutable_gpu_diff()); + + viennacl::ocl::kernel &oclk_softmax_loss_forward = program.get_kernel( + CL_KERNEL_SELECT("softmax_loss_forward")); + viennacl::ocl::enqueue( + oclk_softmax_loss_forward(nthreads, WrapHandle(prob_data, &ctx), + WrapHandle(label, &ctx), + WrapHandle(loss_data, &ctx), outer_num_, dim, + inner_num_, has_ignore_label_ ? 1 : 0, + ignore_label_, WrapHandle(counts, &ctx)), + ctx.get_queue()); + + Dtype loss; + greentea_gpu_asum(this->device_->id(), nthreads, loss_data, 0, + &loss); + Dtype valid_count = -1; + // Only launch another CUDA kernel if we actually need the count of valid + // outputs. + if (normalization_ == LossParameter_NormalizationMode_VALID + && has_ignore_label_) { + greentea_gpu_asum(this->device_->id(), nthreads, counts, 0, + &valid_count); + } + top[0]->mutable_cpu_data()[0] = loss + / get_normalizer(normalization_, valid_count); + if (top.size() >= 2) { + top[1]->ShareData(prob_); + } +#endif // USE_GREENTEA } } -template -__global__ void SoftmaxLossBackwardGPU(const int nthreads, const Dtype* top, - const Dtype* label, Dtype* bottom_diff, const int num, const int dim, - const int spatial_dim, const bool has_ignore_label_, - const int ignore_label_, Dtype* counts) { - const int channels = dim / spatial_dim; +#ifdef USE_CUDA +template +__global__ void SoftmaxLossBackwardGPU(const int_tp nthreads, const Dtype* top, + const Dtype* label, Dtype* bottom_diff, + const int_tp num, const int_tp dim, + const int_tp spatial_dim, + const bool has_ignore_label_, + const int_tp ignore_label_, + Dtype* counts) { + const int_tp channels = dim / spatial_dim; CUDA_KERNEL_LOOP(index, nthreads) { - const int n = index / spatial_dim; - const int s = index % spatial_dim; - const int label_value = static_cast(label[n * spatial_dim + s]); + const int_tp n = index / spatial_dim; + const int_tp s = index % spatial_dim; + const int_tp label_value = static_cast(label[n * spatial_dim + s]); if (has_ignore_label_ && label_value == ignore_label_) { - for (int c = 0; c < channels; ++c) { + for (int_tp c = 0; c < channels; ++c) { bottom_diff[n * dim + c * spatial_dim + s] = 0; } counts[index] = 0; @@ -86,40 +147,81 @@ __global__ void SoftmaxLossBackwardGPU(const int nthreads, const Dtype* top, } } } +#endif // USE_CUDA -template -void SoftmaxWithLossLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { +template +void SoftmaxWithLossLayer::Backward_gpu( + const vector*>& top, const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[1]) { - LOG(FATAL) << this->type() - << " Layer cannot backpropagate to label inputs."; + LOG(FATAL) << + this->type() << " Layer cannot backpropagate to label inputs."; } if (propagate_down[0]) { - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const Dtype* prob_data = prob_.gpu_data(); - const Dtype* top_data = top[0]->gpu_data(); - caffe_gpu_memcpy(prob_.count() * sizeof(Dtype), prob_data, bottom_diff); - const Dtype* label = bottom[1]->gpu_data(); - const int dim = prob_.count() / outer_num_; - const int nthreads = outer_num_ * inner_num_; - // Since this memory is never used for anything else, - // we use to to avoid allocating new GPU memory. - Dtype* counts = prob_.mutable_gpu_diff(); - // NOLINT_NEXT_LINE(whitespace/operators) - SoftmaxLossBackwardGPU<<>>(nthreads, top_data, label, bottom_diff, - outer_num_, dim, inner_num_, has_ignore_label_, ignore_label_, counts); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + const Dtype* prob_data = prob_.gpu_data(); + const Dtype* top_data = top[0]->gpu_data(); + caffe_gpu_memcpy(prob_.count() * sizeof(Dtype), prob_data, bottom_diff); + const Dtype* label = bottom[1]->gpu_data(); + const int_tp dim = prob_.count() / outer_num_; + const int_tp nthreads = outer_num_ * inner_num_; + // Since this memory is never used for anything else, + // we use to to avoid allocating new GPU memory. + Dtype* counts = prob_.mutable_gpu_diff(); + // NOLINT_NEXT_LINE(whitespace/operators) + SoftmaxLossBackwardGPU CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), + CAFFE_CUDA_NUM_THREADS) (nthreads, top_data, label, bottom_diff, + outer_num_, dim, inner_num_, has_ignore_label_, + ignore_label_, counts); - Dtype valid_count = -1; - // Only launch another CUDA kernel if we actually need the count of valid - // outputs. - if (normalization_ == LossParameter_NormalizationMode_VALID && - has_ignore_label_) { - caffe_gpu_asum(nthreads, counts, &valid_count); + Dtype valid_count = -1; + if (normalization_ == LossParameter_NormalizationMode_VALID && + has_ignore_label_) { + caffe_gpu_asum(nthreads, counts, &valid_count); + } + const Dtype loss_weight = top[0]->cpu_diff()[0] / + get_normalizer(normalization_, valid_count); + caffe_gpu_scal(prob_.count(), loss_weight , bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + cl_mem bottom_diff = (cl_mem)(bottom[0]->mutable_gpu_diff()); + cl_mem prob_data = (cl_mem)(prob_.gpu_data()); + cl_mem top_data = (cl_mem)(top[0]->gpu_data()); + greentea_gpu_memcpy(prob_.count() * sizeof(Dtype), + prob_data, 0, bottom_diff, 0, &ctx); + cl_mem label = (cl_mem)(bottom[1]->gpu_data()); + const int_tp dim = prob_.count() / outer_num_; + const int_tp nthreads = outer_num_ * inner_num_; + cl_mem counts = (cl_mem)(prob_.mutable_gpu_diff()); + + viennacl::ocl::kernel &oclk_softmax_loss_backward = program.get_kernel( + CL_KERNEL_SELECT("softmax_loss_backward")); + viennacl::ocl::enqueue( + oclk_softmax_loss_backward(nthreads, WrapHandle(top_data, &ctx), + WrapHandle(label, &ctx), WrapHandle(bottom_diff, &ctx), + outer_num_, dim, inner_num_, has_ignore_label_ ? 1 : 0, + ignore_label_, WrapHandle(counts, &ctx)), + ctx.get_queue()); + + Dtype valid_count = -1; + if (normalization_ == LossParameter_NormalizationMode_VALID && + has_ignore_label_) { + greentea_gpu_asum(this->device_->id(), + nthreads, counts, 0, &valid_count); + } + const Dtype loss_weight = top[0]->cpu_diff()[0] / + get_normalizer(normalization_, valid_count); + greentea_gpu_scal(this->device_->id(), + prob_.count(), loss_weight, bottom_diff, 0); +#endif // USE_GREENTEA } - const Dtype loss_weight = top[0]->cpu_diff()[0] / - get_normalizer(normalization_, valid_count); - caffe_gpu_scal(prob_.count(), loss_weight , bottom_diff); } } diff --git a/src/caffe/layers/split_layer.cpp b/src/caffe/layers/split_layer.cpp index 1a27a9af0a1..066782c1cef 100644 --- a/src/caffe/layers/split_layer.cpp +++ b/src/caffe/layers/split_layer.cpp @@ -9,7 +9,7 @@ template void SplitLayer::Reshape(const vector*>& bottom, const vector*>& top) { count_ = bottom[0]->count(); - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { // Do not allow in-place computation in the SplitLayer. Instead, share data // by reference in the forward pass, and keep separate diff allocations in // the backward pass. (Technically, it should be possible to share the diff @@ -25,7 +25,7 @@ void SplitLayer::Reshape(const vector*>& bottom, template void SplitLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { - for (int i = 0; i < top.size(); ++i) { + for (int_tp i = 0; i < top.size(); ++i) { top[i]->ShareData(*bottom[0]); } } @@ -35,13 +35,13 @@ void SplitLayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { if (!propagate_down[0]) { return; } if (top.size() == 1) { - caffe_copy(count_, top[0]->cpu_diff(), bottom[0]->mutable_cpu_diff()); + caffe_cpu_copy(count_, top[0]->cpu_diff(), bottom[0]->mutable_cpu_diff()); return; } caffe_add(count_, top[0]->cpu_diff(), top[1]->cpu_diff(), bottom[0]->mutable_cpu_diff()); // Add remaining top blob diffs. - for (int i = 2; i < top.size(); ++i) { + for (int_tp i = 2; i < top.size(); ++i) { const Dtype* top_diff = top[i]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); caffe_axpy(count_, Dtype(1.), top_diff, bottom_diff); diff --git a/src/caffe/layers/split_layer.cu b/src/caffe/layers/split_layer.cu index bec9987c7cc..8503e2a82c0 100644 --- a/src/caffe/layers/split_layer.cu +++ b/src/caffe/layers/split_layer.cu @@ -5,33 +5,62 @@ namespace caffe { -template +template void SplitLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { - for (int i = 0; i < top.size(); ++i) { + const vector*>& top) { + for (int_tp i = 0; i < top.size(); ++i) { top[i]->ShareData(*bottom[0]); } } -template +template void SplitLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, const vector*>& bottom) { - if (!propagate_down[0]) { return; } - if (top.size() == 1) { - caffe_copy(count_, top[0]->gpu_diff(), bottom[0]->mutable_gpu_diff()); + const vector& propagate_down, + const vector*>& bottom) { + if (!propagate_down[0]) { return; } - caffe_gpu_add(count_, top[0]->gpu_diff(), top[1]->gpu_diff(), - bottom[0]->mutable_gpu_diff()); - // Add remaining top blob diffs. - for (int i = 2; i < top.size(); ++i) { - const Dtype* top_diff = top[i]->gpu_diff(); - Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - caffe_gpu_axpy(count_, Dtype(1.), top_diff, bottom_diff); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (top.size() == 1) { + caffe_copy(count_, top[0]->gpu_diff(), bottom[0]->mutable_gpu_diff()); + return; + } + caffe_gpu_add(count_, top[0]->gpu_diff(), top[1]->gpu_diff(), + bottom[0]->mutable_gpu_diff()); + // Add remaining top blob diffs. + for (int_tp i = 2; i < top.size(); ++i) { + const Dtype* top_diff = top[i]->gpu_diff(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + caffe_gpu_axpy(count_, Dtype(1.), top_diff, bottom_diff); + } +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + + if (top.size() == 1) { + greentea_copy(count_, (cl_mem) (top[0]->gpu_diff()), 0, + (cl_mem) (bottom[0]->mutable_gpu_diff()), 0, &ctx); + return; + } + greentea_gpu_add(this->device_->id(), count_, + (cl_mem) (top[0]->gpu_diff()), 0, + (cl_mem) (top[1]->gpu_diff()), 0, + (cl_mem) (bottom[0]->mutable_gpu_diff()), 0); + // Add remaining top blob diffs. + for (int_tp i = 2; i < top.size(); ++i) { + const Dtype* top_diff = top[i]->gpu_diff(); + Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); + greentea_gpu_axpy(this->device_->id(), count_, Dtype(1.), + (cl_mem) top_diff, 0, (cl_mem) bottom_diff, 0); + } +#endif // USE_GREENTEA } } - INSTANTIATE_LAYER_GPU_FUNCS(SplitLayer); } // namespace caffe diff --git a/src/caffe/layers/spp_layer.cpp b/src/caffe/layers/spp_layer.cpp index b9af8e8af0e..219a61b2a8c 100644 --- a/src/caffe/layers/spp_layer.cpp +++ b/src/caffe/layers/spp_layer.cpp @@ -14,25 +14,27 @@ using std::min; using std::max; template -LayerParameter SPPLayer::GetPoolingParam(const int pyramid_level, - const int bottom_h, const int bottom_w, const SPPParameter spp_param) { +LayerParameter SPPLayer::GetPoolingParam(const int_tp pyramid_level, + const int_tp bottom_h, + const int_tp bottom_w, + const SPPParameter spp_param) { LayerParameter pooling_param; - int num_bins = pow(2, pyramid_level); + int_tp num_bins = pow(2, pyramid_level); // find padding and kernel size so that the pooling is // performed across the entire image - int kernel_h = ceil(bottom_h / static_cast(num_bins)); + int_tp kernel_h = ceil(bottom_h / static_cast(num_bins)); // remainder_h is the min number of pixels that need to be padded before // entire image height is pooled over with the chosen kernel dimension - int remainder_h = kernel_h * num_bins - bottom_h; + int_tp remainder_h = kernel_h * num_bins - bottom_h; // pooling layer pads (2 * pad_h) pixels on the top and bottom of the // image. - int pad_h = (remainder_h + 1) / 2; + int_tp pad_h = (remainder_h + 1) / 2; // similar logic for width - int kernel_w = ceil(bottom_w / static_cast(num_bins)); - int remainder_w = kernel_w * num_bins - bottom_w; - int pad_w = (remainder_w + 1) / 2; + int_tp kernel_w = ceil(bottom_w / static_cast(num_bins)); + int_tp remainder_w = kernel_w * num_bins - bottom_w; + int_tp pad_w = (remainder_w + 1) / 2; pooling_param.mutable_pooling_param()->set_pad_h(pad_h); pooling_param.mutable_pooling_param()->set_pad_w(pad_w); @@ -95,7 +97,7 @@ void SPPLayer::LayerSetUp(const vector*>& bottom, return; } // split layer output holders setup - for (int i = 0; i < pyramid_height_; i++) { + for (int_tp i = 0; i < pyramid_height_; i++) { split_top_vec_.push_back(new Blob()); } @@ -104,7 +106,7 @@ void SPPLayer::LayerSetUp(const vector*>& bottom, split_layer_.reset(new SplitLayer(split_param)); split_layer_->SetUp(bottom, split_top_vec_); - for (int i = 0; i < pyramid_height_; i++) { + for (int_tp i = 0; i < pyramid_height_; i++) { // pooling layer input holders setup pooling_bottom_vecs_.push_back(new vector*>); pooling_bottom_vecs_[i]->push_back(split_top_vec_[i]); @@ -168,7 +170,7 @@ void SPPLayer::Reshape(const vector*>& bottom, return; } split_layer_->Reshape(bottom, split_top_vec_); - for (int i = 0; i < pyramid_height_; i++) { + for (int_tp i = 0; i < pyramid_height_; i++) { LayerParameter pooling_param = GetPoolingParam( i, bottom_h_, bottom_w_, spp_param); @@ -192,7 +194,7 @@ void SPPLayer::Forward_cpu(const vector*>& bottom, return; } split_layer_->Forward(bottom, split_top_vec_); - for (int i = 0; i < pyramid_height_; i++) { + for (int_tp i = 0; i < pyramid_height_; i++) { pooling_layers_[i]->Forward( *pooling_bottom_vecs_[i], *pooling_top_vecs_[i]); flatten_layers_[i]->Forward( @@ -213,7 +215,7 @@ void SPPLayer::Backward_cpu(const vector*>& top, } vector concat_propagate_down(pyramid_height_, true); concat_layer_->Backward(top, concat_propagate_down, concat_bottom_vec_); - for (int i = 0; i < pyramid_height_; i++) { + for (int_tp i = 0; i < pyramid_height_; i++) { flatten_layers_[i]->Backward( *flatten_top_vecs_[i], propagate_down, *pooling_top_vecs_[i]); pooling_layers_[i]->Backward( diff --git a/src/caffe/layers/tanh_layer.cpp b/src/caffe/layers/tanh_layer.cpp index 184e926d22a..08f375b6140 100644 --- a/src/caffe/layers/tanh_layer.cpp +++ b/src/caffe/layers/tanh_layer.cpp @@ -12,8 +12,8 @@ void TanHLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); - for (int i = 0; i < count; ++i) { + const int_tp count = bottom[0]->count(); + for (int_tp i = 0; i < count; ++i) { top_data[i] = tanh(bottom_data[i]); } } @@ -26,9 +26,9 @@ void TanHLayer::Backward_cpu(const vector*>& top, const Dtype* top_data = top[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - const int count = bottom[0]->count(); + const int_tp count = bottom[0]->count(); Dtype tanhx; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { tanhx = top_data[i]; bottom_diff[i] = top_diff[i] * (1 - tanhx * tanhx); } diff --git a/src/caffe/layers/tanh_layer.cu b/src/caffe/layers/tanh_layer.cu index cbfc178e6db..eeebf81745c 100644 --- a/src/caffe/layers/tanh_layer.cu +++ b/src/caffe/layers/tanh_layer.cu @@ -7,51 +7,93 @@ namespace caffe { -template -__global__ void TanHForward(const int n, const Dtype* in, Dtype* out) { +#ifdef USE_CUDA +template +__global__ void TanHForward(const int_tp n, const Dtype* in, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { out[index] = tanh(in[index]); } } +#endif // USE_CUDA -template +template void TanHLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - TanHForward<<>>( - count, bottom_data, top_data); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + TanHForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, bottom_data, top_data); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_tanh = program.get_kernel( + CL_KERNEL_SELECT("tanh_forward")); + viennacl::ocl::enqueue( + oclk_tanh(count, WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template -__global__ void TanHBackward(const int n, const Dtype* in_diff, - const Dtype* out_data, Dtype* out_diff) { +#ifdef USE_CUDA +template +__global__ void TanHBackward(const int_tp n, const Dtype* in_diff, + const Dtype* out_data, Dtype* out_diff) { CUDA_KERNEL_LOOP(index, n) { Dtype tanhx = out_data[index]; out_diff[index] = in_diff[index] * (1 - tanhx * tanhx); } } +#endif // USE_CUDA -template +template void TanHLayer::Backward_gpu(const vector*>& top, - const vector& propagate_down, - const vector*>& bottom) { + const vector& propagate_down, + const vector*>& bottom) { if (propagate_down[0]) { const Dtype* top_data = top[0]->gpu_data(); const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - TanHBackward<<>>( - count, top_diff, top_data, bottom_diff); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + TanHBackward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, top_diff, top_data, bottom_diff); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_tanh = program.get_kernel( + CL_KERNEL_SELECT("tanh_backward")); + viennacl::ocl::enqueue( + oclk_tanh(count, WrapHandle((cl_mem) top_diff, &ctx), + WrapHandle((cl_mem) top_data, &ctx), + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } } INSTANTIATE_LAYER_GPU_FUNCS(TanHLayer); - } // namespace caffe diff --git a/src/caffe/layers/threshold_layer.cpp b/src/caffe/layers/threshold_layer.cpp index 63822ee5520..ad5f0c87cd7 100644 --- a/src/caffe/layers/threshold_layer.cpp +++ b/src/caffe/layers/threshold_layer.cpp @@ -16,8 +16,8 @@ void ThresholdLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - const int count = bottom[0]->count(); - for (int i = 0; i < count; ++i) { + const int_tp count = bottom[0]->count(); + for (int_tp i = 0; i < count; ++i) { top_data[i] = (bottom_data[i] > threshold_) ? Dtype(1) : Dtype(0); } } diff --git a/src/caffe/layers/threshold_layer.cu b/src/caffe/layers/threshold_layer.cu index b0b0665589f..b3486f4c318 100644 --- a/src/caffe/layers/threshold_layer.cu +++ b/src/caffe/layers/threshold_layer.cu @@ -2,30 +2,56 @@ #include "caffe/layers/threshold_layer.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -template -__global__ void ThresholdForward(const int n, const Dtype threshold, - const Dtype* in, Dtype* out) { +#ifdef USE_CUDA +template +__global__ void ThresholdForward(const int_tp n, const Dtype threshold, + const Dtype* in, Dtype* out) { CUDA_KERNEL_LOOP(index, n) { out[index] = in[index] > threshold ? 1 : 0; } } +#endif -template +template void ThresholdLayer::Forward_gpu(const vector*>& bottom, - const vector*>& top) { + const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int count = bottom[0]->count(); - // NOLINT_NEXT_LINE(whitespace/operators) - ThresholdForward<<>>( - count, threshold_, bottom_data, top_data); - CUDA_POST_KERNEL_CHECK; + const int_tp count = bottom[0]->count(); + + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + // NOLINT_NEXT_LINE(whitespace/operators) + ThresholdForward CUDA_KERNEL(CAFFE_GET_BLOCKS(count), + CAFFE_CUDA_NUM_THREADS)( + count, threshold_, bottom_data, top_data); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_threshold = program.get_kernel( + CL_KERNEL_SELECT("threshold")); + viennacl::ocl::enqueue( + oclk_threshold(count, threshold_, + WrapHandle((cl_mem) bottom_data, &ctx), + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); + ctx.get_queue().finish(); +#endif // USE_GREENTEA + } } - INSTANTIATE_LAYER_GPU_FORWARD(ThresholdLayer); - } // namespace caffe diff --git a/src/caffe/layers/tile_layer.cpp b/src/caffe/layers/tile_layer.cpp index cf0c187005c..cfcd3ff88b9 100644 --- a/src/caffe/layers/tile_layer.cpp +++ b/src/caffe/layers/tile_layer.cpp @@ -13,7 +13,7 @@ void TileLayer::Reshape( CHECK(tile_param.has_tiles()) << "Number of tiles must be specified"; tiles_ = tile_param.tiles(); CHECK_GT(tiles_, 0) << "Number of tiles must be positive."; - vector top_shape = bottom[0]->shape(); + vector top_shape = bottom[0]->shape(); top_shape[axis_] = bottom[0]->shape(axis_) * tiles_; top[0]->Reshape(top_shape); outer_dim_ = bottom[0]->count(0, axis_); @@ -25,8 +25,8 @@ void TileLayer::Forward_cpu( const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); - for (int i = 0; i < outer_dim_; ++i) { - for (int t = 0; t < tiles_; ++t) { + for (int_tp i = 0; i < outer_dim_; ++i) { + for (int_tp t = 0; t < tiles_; ++t) { caffe_copy(inner_dim_, bottom_data, top_data); top_data += inner_dim_; } @@ -40,10 +40,10 @@ void TileLayer::Backward_cpu(const vector*>& top, if (!propagate_down[0]) { return; } const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); - for (int i = 0; i < outer_dim_; ++i) { + for (int_tp i = 0; i < outer_dim_; ++i) { caffe_copy(inner_dim_, top_diff, bottom_diff); top_diff += inner_dim_; - for (int t = 1; t < tiles_; ++t) { + for (int_tp t = 1; t < tiles_; ++t) { caffe_axpy(inner_dim_, Dtype(1), top_diff, bottom_diff); top_diff += inner_dim_; } diff --git a/src/caffe/layers/tile_layer.cu b/src/caffe/layers/tile_layer.cu index 282049ebd7b..15d0a114135 100644 --- a/src/caffe/layers/tile_layer.cu +++ b/src/caffe/layers/tile_layer.cu @@ -3,49 +3,78 @@ #include "caffe/layers/tile_layer.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + + namespace caffe { -template -__global__ void Tile(const int nthreads, const Dtype* bottom_data, - const int tile_size, const int num_tiles, const int bottom_tile_axis, - Dtype* top_data) { +#ifdef USE_CUDA +template +__global__ void Tile(const int_tp nthreads, const Dtype* bottom_data, + const int_tp tile_size, const int_tp num_tiles, + const int_tp bottom_tile_axis, Dtype* top_data) { CUDA_KERNEL_LOOP(index, nthreads) { - const int d = index % tile_size; - const int b = (index / tile_size / num_tiles) % bottom_tile_axis; - const int n = index / tile_size / num_tiles / bottom_tile_axis; - const int bottom_index = (n * bottom_tile_axis + b) * tile_size + d; + const int_tp d = index % tile_size; + const int_tp b = (index / tile_size / num_tiles) % bottom_tile_axis; + const int_tp n = index / tile_size / num_tiles / bottom_tile_axis; + const int_tp bottom_index = (n * bottom_tile_axis + b) * tile_size + d; top_data[index] = bottom_data[bottom_index]; } } +#endif // USE_CUDA template void TileLayer::Forward_gpu( const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->gpu_data(); Dtype* top_data = top[0]->mutable_gpu_data(); - const int bottom_tile_axis = bottom[0]->shape(axis_); - const int nthreads = top[0]->count(); - Tile // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - nthreads, bottom_data, inner_dim_, tiles_, bottom_tile_axis, top_data); + const int_tp bottom_tile_axis = bottom[0]->shape(axis_); + const int_tp nthreads = top[0]->count(); + if (this->get_device()->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + Tile // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), CAFFE_CUDA_NUM_THREADS)( + nthreads, bottom_data, inner_dim_, tiles_, bottom_tile_axis, top_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_tile = program.get_kernel( + CL_KERNEL_SELECT("tile")); + viennacl::ocl::enqueue( + oclk_tile(nthreads, WrapHandle((cl_mem) bottom_data, &ctx), inner_dim_, + tiles_, bottom_tile_axis, + WrapHandle((cl_mem) top_data, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } +#ifdef USE_CUDA template -__global__ void TileBackward(const int nthreads, const Dtype* top_diff, - const int tile_size, const int num_tiles, const int bottom_tile_axis, +__global__ void TileBackward(const int_tp nthreads, const Dtype* top_diff, + const int_tp tile_size, const int_tp num_tiles, + const int_tp bottom_tile_axis, Dtype* bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { - const int d = index % tile_size; - const int b = (index / tile_size) % bottom_tile_axis; - const int n = index / tile_size / bottom_tile_axis; + const int_tp d = index % tile_size; + const int_tp b = (index / tile_size) % bottom_tile_axis; + const int_tp n = index / tile_size / bottom_tile_axis; bottom_diff[index] = 0; - int top_index = (n * num_tiles * bottom_tile_axis + b) * tile_size + d; - for (int t = 0; t < num_tiles; ++t) { + int_tp top_index = (n * num_tiles * bottom_tile_axis + b) * tile_size + d; + for (int_tp t = 0; t < num_tiles; ++t) { bottom_diff[index] += top_diff[top_index]; top_index += bottom_tile_axis * tile_size; } } } +#endif // USE_CUDA template void TileLayer::Backward_gpu(const vector*>& top, @@ -53,12 +82,31 @@ void TileLayer::Backward_gpu(const vector*>& top, if (!propagate_down[0]) { return; } const Dtype* top_diff = top[0]->gpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_gpu_diff(); - const int bottom_tile_axis = bottom[0]->shape(axis_); - const int tile_size = inner_dim_ / bottom_tile_axis; - const int nthreads = bottom[0]->count(); - TileBackward // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - nthreads, top_diff, tile_size, tiles_, bottom_tile_axis, bottom_diff); + const int_tp bottom_tile_axis = bottom[0]->shape(axis_); + const int_tp tile_size = inner_dim_ / bottom_tile_axis; + const int_tp nthreads = bottom[0]->count(); + + if (this->get_device()->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + TileBackward // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(nthreads), CAFFE_CUDA_NUM_THREADS)( + nthreads, top_diff, tile_size, tiles_, bottom_tile_axis, bottom_diff); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + this->device_->id()); + viennacl::ocl::program &program = this->device_->program(); + + viennacl::ocl::kernel &oclk_tile = program.get_kernel( + CL_KERNEL_SELECT("tile_backward")); + viennacl::ocl::enqueue( + oclk_tile(nthreads, WrapHandle((cl_mem) top_diff, &ctx), tile_size, + tiles_, bottom_tile_axis, + WrapHandle((cl_mem) bottom_diff, &ctx)), + ctx.get_queue()); +#endif // USE_GREENTEA + } } INSTANTIATE_LAYER_GPU_FUNCS(TileLayer); diff --git a/src/caffe/layers/window_data_layer.cpp b/src/caffe/layers/window_data_layer.cpp index 4ca8315d791..92860cde7fa 100644 --- a/src/caffe/layers/window_data_layer.cpp +++ b/src/caffe/layers/window_data_layer.cpp @@ -69,7 +69,7 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, this->transform_param_.mirror() || this->transform_param_.crop_size(); if (prefetch_needs_rand) { - const unsigned int prefetch_rng_seed = caffe_rng_rand(); + const uint_tp prefetch_rng_seed = caffe_rng_rand(); prefetch_rng_.reset(new Caffe::RNG(prefetch_rng_seed)); } else { prefetch_rng_.reset(); @@ -79,11 +79,11 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, CHECK(infile.good()) << "Failed to open window file " << this->layer_param_.window_data_param().source() << std::endl; - map label_hist; + map label_hist; label_hist.insert(std::make_pair(0, 0)); string hashtag; - int image_index, channels; + int_tp image_index, channels; if (!(infile >> hashtag >> image_index)) { LOG(FATAL) << "Window file is empty"; } @@ -94,7 +94,7 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, infile >> image_path; image_path = root_folder + image_path; // read image dimensions - vector image_size(3); + vector image_size(3); infile >> image_size[0] >> image_size[1] >> image_size[2]; channels = image_size[0]; image_database_.push_back(std::make_pair(image_path, image_size)); @@ -108,14 +108,14 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, image_database_cache_.push_back(std::make_pair(image_path, datum)); } // read each box - int num_windows; + int_tp num_windows; infile >> num_windows; const float fg_threshold = this->layer_param_.window_data_param().fg_threshold(); const float bg_threshold = this->layer_param_.window_data_param().bg_threshold(); - for (int i = 0; i < num_windows; ++i) { - int label, x1, y1, x2, y2; + for (int_tp i = 0; i < num_windows; ++i) { + int_tp label, x1, y1, x2, y2; float overlap; infile >> label >> overlap >> x1 >> y1 >> x2 >> y2; @@ -130,7 +130,7 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, // add window to foreground list or background list if (overlap >= fg_threshold) { - int label = window[WindowDataLayer::LABEL]; + int_tp label = window[WindowDataLayer::LABEL]; CHECK_GT(label, 0); fg_windows_.push_back(window); label_hist.insert(std::make_pair(label, 0)); @@ -156,7 +156,7 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, LOG(INFO) << "Number of images: " << image_index+1; - for (map::iterator it = label_hist.begin(); + for (map::iterator it = label_hist.begin(); it != label_hist.end(); ++it) { LOG(INFO) << "class " << it->first << " has " << label_hist[it->first] << " samples"; @@ -169,11 +169,11 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, << this->layer_param_.window_data_param().crop_mode(); // image - const int crop_size = this->transform_param_.crop_size(); + const int_tp crop_size = this->transform_param_.crop_size(); CHECK_GT(crop_size, 0); - const int batch_size = this->layer_param_.window_data_param().batch_size(); + const int_tp batch_size = this->layer_param_.window_data_param().batch_size(); top[0]->Reshape(batch_size, channels, crop_size, crop_size); - for (int i = 0; i < this->PREFETCH_COUNT; ++i) + for (int_tp i = 0; i < this->PREFETCH_COUNT; ++i) this->prefetch_[i].data_.Reshape( batch_size, channels, crop_size, crop_size); @@ -181,9 +181,9 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, << top[0]->channels() << "," << top[0]->height() << "," << top[0]->width(); // label - vector label_shape(1, batch_size); + vector label_shape(1, batch_size); top[1]->Reshape(label_shape); - for (int i = 0; i < this->PREFETCH_COUNT; ++i) { + for (int_tp i = 0; i < this->PREFETCH_COUNT; ++i) { this->prefetch_[i].label_.Reshape(label_shape); } @@ -201,14 +201,14 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, if (has_mean_values_) { CHECK(has_mean_file_ == false) << "Cannot specify mean_file and mean_value at the same time"; - for (int c = 0; c < this->transform_param_.mean_value_size(); ++c) { + for (int_tp c = 0; c < this->transform_param_.mean_value_size(); ++c) { mean_values_.push_back(this->transform_param_.mean_value(c)); } CHECK(mean_values_.size() == 1 || mean_values_.size() == channels) << "Specify either 1 mean_value or as many as channels: " << channels; if (channels > 1 && mean_values_.size() == 1) { // Replicate the mean_value for simplicity - for (int c = 1; c < channels; ++c) { + for (int_tp c = 1; c < channels; ++c) { mean_values_.push_back(mean_values_[0]); } } @@ -216,7 +216,7 @@ void WindowDataLayer::DataLayerSetUp(const vector*>& bottom, } template -unsigned int WindowDataLayer::PrefetchRand() { +uint_tp WindowDataLayer::PrefetchRand() { CHECK(prefetch_rng_); caffe::rng_t* prefetch_rng = static_cast(prefetch_rng_->generator()); @@ -236,16 +236,17 @@ void WindowDataLayer::load_batch(Batch* batch) { Dtype* top_data = batch->data_.mutable_cpu_data(); Dtype* top_label = batch->label_.mutable_cpu_data(); const Dtype scale = this->layer_param_.window_data_param().scale(); - const int batch_size = this->layer_param_.window_data_param().batch_size(); - const int context_pad = this->layer_param_.window_data_param().context_pad(); - const int crop_size = this->transform_param_.crop_size(); + const int_tp batch_size = this->layer_param_.window_data_param().batch_size(); + const int_tp context_pad = + this->layer_param_.window_data_param().context_pad(); + const int_tp crop_size = this->transform_param_.crop_size(); const bool mirror = this->transform_param_.mirror(); const float fg_fraction = this->layer_param_.window_data_param().fg_fraction(); Dtype* mean = NULL; - int mean_off = 0; - int mean_width = 0; - int mean_height = 0; + int_tp mean_off = 0; + int_tp mean_width = 0; + int_tp mean_height = 0; if (this->has_mean_file_) { mean = this->data_mean_.mutable_cpu_data(); mean_off = (this->data_mean_.width() - crop_size) / 2; @@ -260,17 +261,17 @@ void WindowDataLayer::load_batch(Batch* batch) { // zero out batch caffe_set(batch->data_.count(), Dtype(0), top_data); - const int num_fg = static_cast(static_cast(batch_size) + const int_tp num_fg = static_cast(static_cast(batch_size) * fg_fraction); - const int num_samples[2] = { batch_size - num_fg, num_fg }; + const int_tp num_samples[2] = { batch_size - num_fg, num_fg }; - int item_id = 0; + int_tp item_id = 0; // sample from bg set then fg set - for (int is_fg = 0; is_fg < 2; ++is_fg) { - for (int dummy = 0; dummy < num_samples[is_fg]; ++dummy) { + for (int_tp is_fg = 0; is_fg < 2; ++is_fg) { + for (int_tp dummy = 0; dummy < num_samples[is_fg]; ++dummy) { // sample a window timer.Start(); - const unsigned int rand_index = PrefetchRand(); + const uint_tp rand_index = PrefetchRand(); vector window = (is_fg) ? fg_windows_[rand_index % fg_windows_.size()] : bg_windows_[rand_index % bg_windows_.size()]; @@ -278,7 +279,7 @@ void WindowDataLayer::load_batch(Batch* batch) { bool do_mirror = mirror && PrefetchRand() % 2; // load the image containing the window - pair > image = + pair > image = image_database_[window[WindowDataLayer::IMAGE_INDEX]]; cv::Mat cv_img; @@ -295,16 +296,16 @@ void WindowDataLayer::load_batch(Batch* batch) { } read_time += timer.MicroSeconds(); timer.Start(); - const int channels = cv_img.channels(); + const int_tp channels = cv_img.channels(); // crop window out of image and warp it - int x1 = window[WindowDataLayer::X1]; - int y1 = window[WindowDataLayer::Y1]; - int x2 = window[WindowDataLayer::X2]; - int y2 = window[WindowDataLayer::Y2]; + int_tp x1 = window[WindowDataLayer::X1]; + int_tp y1 = window[WindowDataLayer::Y1]; + int_tp x2 = window[WindowDataLayer::X2]; + int_tp y2 = window[WindowDataLayer::Y2]; - int pad_w = 0; - int pad_h = 0; + int_tp pad_w = 0; + int_tp pad_h = 0; if (context_pad > 0 || use_square) { // scale factor by which to expand the original region // such that after warping the expanded region to crop_size x crop_size @@ -324,20 +325,20 @@ void WindowDataLayer::load_batch(Batch* batch) { half_height = half_width; } } - x1 = static_cast(round(center_x - half_width*context_scale)); - x2 = static_cast(round(center_x + half_width*context_scale)); - y1 = static_cast(round(center_y - half_height*context_scale)); - y2 = static_cast(round(center_y + half_height*context_scale)); + x1 = static_cast(round(center_x - half_width*context_scale)); + x2 = static_cast(round(center_x + half_width*context_scale)); + y1 = static_cast(round(center_y - half_height*context_scale)); + y2 = static_cast(round(center_y + half_height*context_scale)); // the expanded region may go outside of the image // so we compute the clipped (expanded) region and keep track of // the extent beyond the image - int unclipped_height = y2-y1+1; - int unclipped_width = x2-x1+1; - int pad_x1 = std::max(0, -x1); - int pad_y1 = std::max(0, -y1); - int pad_x2 = std::max(0, x2 - cv_img.cols + 1); - int pad_y2 = std::max(0, y2 - cv_img.rows + 1); + int_tp unclipped_height = y2-y1+1; + int_tp unclipped_width = x2-x1+1; + int_tp pad_x1 = std::max((int_tp)0, -x1); + int_tp pad_y1 = std::max((int_tp)0, -y1); + int_tp pad_x2 = std::max((int_tp)0, x2 - cv_img.cols + 1); + int_tp pad_y2 = std::max((int_tp)0, y2 - cv_img.rows + 1); // clip bounds x1 = x1 + pad_x1; x2 = x2 - pad_x2; @@ -348,8 +349,8 @@ void WindowDataLayer::load_batch(Batch* batch) { CHECK_LT(x2, cv_img.cols); CHECK_LT(y2, cv_img.rows); - int clipped_height = y2-y1+1; - int clipped_width = x2-x1+1; + int_tp clipped_height = y2-y1+1; + int_tp clipped_width = x2-x1+1; // scale factors that would be used to warp the unclipped // expanded region @@ -359,14 +360,15 @@ void WindowDataLayer::load_batch(Batch* batch) { static_cast(crop_size)/static_cast(unclipped_height); // size to warp the clipped expanded region to - cv_crop_size.width = - static_cast(round(static_cast(clipped_width)*scale_x)); - cv_crop_size.height = - static_cast(round(static_cast(clipped_height)*scale_y)); - pad_x1 = static_cast(round(static_cast(pad_x1)*scale_x)); - pad_x2 = static_cast(round(static_cast(pad_x2)*scale_x)); - pad_y1 = static_cast(round(static_cast(pad_y1)*scale_y)); - pad_y2 = static_cast(round(static_cast(pad_y2)*scale_y)); + cv_crop_size.width = static_cast(round( + static_cast(clipped_width) * scale_x)); + cv_crop_size.height = static_cast(round( + static_cast(clipped_height) * scale_y)); + pad_x1 = + static_cast(round(static_cast(pad_x1) * scale_x)); + pad_x2 = static_cast(round(static_cast(pad_x2)*scale_x)); + pad_y1 = static_cast(round(static_cast(pad_y1)*scale_y)); + pad_y2 = static_cast(round(static_cast(pad_y2)*scale_y)); pad_h = pad_y1; // if we're mirroring, we mirror the padding too (to be pedantic) @@ -397,17 +399,18 @@ void WindowDataLayer::load_batch(Batch* batch) { } // copy the warped window into top_data - for (int h = 0; h < cv_cropped_img.rows; ++h) { + for (int_tp h = 0; h < cv_cropped_img.rows; ++h) { const uchar* ptr = cv_cropped_img.ptr(h); - int img_index = 0; - for (int w = 0; w < cv_cropped_img.cols; ++w) { - for (int c = 0; c < channels; ++c) { - int top_index = ((item_id * channels + c) * crop_size + h + pad_h) - * crop_size + w + pad_w; - // int top_index = (c * height + h) * width + w; + int_tp img_index = 0; + for (int_tp w = 0; w < cv_cropped_img.cols; ++w) { + for (int_tp c = 0; c < channels; ++c) { + int_tp top_index = + ((item_id * channels + c) * crop_size + h + pad_h) * crop_size + + w + pad_w; + // int_tp top_index = (c * height + h) * width + w; Dtype pixel = static_cast(ptr[img_index++]); if (this->has_mean_file_) { - int mean_index = (c * mean_height + h + mean_off + pad_h) + int_tp mean_index = (c * mean_height + h + mean_off + pad_h) * mean_width + w + mean_off + pad_w; top_data[top_index] = (pixel - mean[mean_index]) * scale; } else { @@ -444,9 +447,9 @@ void WindowDataLayer::load_batch(Batch* batch) { std::ofstream top_data_file((string("dump/") + file_id + string("_data.txt")).c_str(), std::ofstream::out | std::ofstream::binary); - for (int c = 0; c < channels; ++c) { - for (int h = 0; h < crop_size; ++h) { - for (int w = 0; w < crop_size; ++w) { + for (int_tp c = 0; c < channels; ++c) { + for (int_tp h = 0; h < crop_size; ++h) { + for (int_tp w = 0; w < crop_size; ++w) { top_data_file.write(reinterpret_cast( &top_data[((item_id * channels + c) * crop_size + h) * crop_size + w]), diff --git a/src/caffe/net.cpp b/src/caffe/net.cpp index 05bee7987da..1688fbaf38f 100644 --- a/src/caffe/net.cpp +++ b/src/caffe/net.cpp @@ -21,22 +21,25 @@ namespace caffe { -template -Net::Net(const NetParameter& param, const Net* root_net) - : root_net_(root_net) { + +template +Net::Net(const NetParameter& param, device* device_context, + const Net* root_net) + : device_(device_context), root_net_(root_net) { Init(param); } -template -Net::Net(const string& param_file, Phase phase, const Net* root_net) - : root_net_(root_net) { +template +Net::Net(const string& param_file, Phase phase, device* device_context, + const Net* root_net) + : device_(device_context), root_net_(root_net) { NetParameter param; ReadNetParamsFromTextFileOrDie(param_file, ¶m); param.mutable_state()->set_phase(phase); Init(param); } -template +template void Net::Init(const NetParameter& in_param) { CHECK(Caffe::root_solver() || root_net_) << "root_net_ needs to be set for all non-root solvers"; @@ -46,15 +49,16 @@ void Net::Init(const NetParameter& in_param) { // the current NetState. NetParameter filtered_param; FilterNet(in_param, &filtered_param); - LOG_IF(INFO, Caffe::root_solver()) - << "Initializing net from parameters: " << std::endl - << filtered_param.DebugString(); + if (Caffe::root_solver()) { + LOG(INFO) << "Initializing net from parameters: " << std::endl + << filtered_param.DebugString(); + } // Create a copy of filtered_param with splits added where necessary. NetParameter param; InsertSplits(filtered_param, ¶m); - // Basically, build all the layers and set up their connections. + // Basically, build all the layers and set up its connections. name_ = param.name(); - map blob_name_to_idx; + map blob_name_to_idx; set available_blobs; CHECK(param.input_dim_size() == 0 || param.input_shape_size() == 0) << "Must specify either input_shape OR deprecated input_dim, not both."; @@ -64,14 +68,16 @@ void Net::Init(const NetParameter& in_param) { << "Incorrect input blob dimension specifications."; } else { CHECK_EQ(param.input_size(), param.input_shape_size()) - << "Exactly one input_shape must be specified per input."; + << "Exactly one input_shape must be specified per input."; } memory_used_ = 0; // set the input blobs - for (int input_id = 0; input_id < param.input_size(); ++input_id) { - const int layer_id = -1; // inputs have fake layer ID -1 + for (int_tp input_id = 0; input_id < param.input_size(); ++input_id) { + const int_tp layer_id = -1; // inputs have fake layer ID -1 AppendTop(param, layer_id, input_id, &available_blobs, &blob_name_to_idx); } + DLOG_IF(INFO, Caffe::root_solver()) + << "Memory required for data: " << memory_used_ * sizeof(Dtype); // For each layer, set up its input and output bottom_vecs_.resize(param.layer_size()); top_vecs_.resize(param.layer_size()); @@ -79,7 +85,7 @@ void Net::Init(const NetParameter& in_param) { param_id_vecs_.resize(param.layer_size()); top_id_vecs_.resize(param.layer_size()); bottom_need_backward_.resize(param.layer_size()); - for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) { + for (int_tp layer_id = 0; layer_id < param.layer_size(); ++layer_id) { // For non-root solvers, whether this layer is shared from root_net_. bool share_from_root = !Caffe::root_solver() && root_net_->layers_[layer_id]->ShareInParallel(); @@ -88,12 +94,17 @@ void Net::Init(const NetParameter& in_param) { param.mutable_layer(layer_id)->set_phase(phase_); } // Setup layer. - const LayerParameter& layer_param = param.layer(layer_id); + const LayerParameter& c_layer_param = param.layer(layer_id); + + LayerParameter layer_param = c_layer_param; + + // Set device + layer_param.set_device(Caffe::GetDefaultDevice()->list_id()); + if (layer_param.propagate_down_size() > 0) { CHECK_EQ(layer_param.propagate_down_size(), - layer_param.bottom_size()) - << "propagate_down param must be specified " - << "either 0 or bottom_size times "; + layer_param.bottom_size())<< "propagate_down param must be specified " + << "either 0 or bottom_size times "; } if (share_from_root) { LOG(INFO) << "Sharing layer " << layer_param.name() << " from root net"; @@ -103,20 +114,21 @@ void Net::Init(const NetParameter& in_param) { layers_.push_back(LayerRegistry::CreateLayer(layer_param)); } layer_names_.push_back(layer_param.name()); - LOG_IF(INFO, Caffe::root_solver()) - << "Creating Layer " << layer_param.name(); + if (Caffe::root_solver()) { + LOG(INFO) << "Creating Layer " << layer_param.name(); + } bool need_backward = false; // Figure out this layer's input and output - for (int bottom_id = 0; bottom_id < layer_param.bottom_size(); - ++bottom_id) { - const int blob_id = AppendBottom(param, layer_id, bottom_id, + for (int_tp bottom_id = 0; bottom_id < layer_param.bottom_size(); + ++bottom_id) { + const int_tp blob_id = AppendBottom(param, layer_id, bottom_id, &available_blobs, &blob_name_to_idx); // If a blob needs backward, this layer should provide it. need_backward |= blob_need_backward_[blob_id]; } - int num_top = layer_param.top_size(); - for (int top_id = 0; top_id < num_top; ++top_id) { + int_tp num_top = layer_param.top_size(); + for (int_tp top_id = 0; top_id < num_top; ++top_id) { AppendTop(param, layer_id, top_id, &available_blobs, &blob_name_to_idx); } // If the layer specifies that AutoTopBlobs() -> true and the LayerParameter @@ -124,8 +136,8 @@ void Net::Init(const NetParameter& in_param) { // ExactNumTopBlobs() or MinTopBlobs()), allocate them here. Layer* layer = layers_[layer_id].get(); if (layer->AutoTopBlobs()) { - const int needed_num_top = - std::max(layer->MinTopBlobs(), layer->ExactNumTopBlobs()); + const int_tp needed_num_top = std::max(layer->MinTopBlobs(), + layer->ExactNumTopBlobs()); for (; num_top < needed_num_top; ++num_top) { // Add "anonymous" top blobs -- do not modify available_blobs or // blob_name_to_idx as we don't want these blobs to be usable as input @@ -138,7 +150,7 @@ void Net::Init(const NetParameter& in_param) { // Set up size of top blobs using root_net_ const vector*>& base_top = root_net_->top_vecs_[layer_id]; const vector*>& this_top = this->top_vecs_[layer_id]; - for (int top_id = 0; top_id < base_top.size(); ++top_id) { + for (int_tp top_id = 0; top_id < base_top.size(); ++top_id) { this_top[top_id]->ReshapeLike(*base_top[top_id]); LOG(INFO) << "Created top blob " << top_id << " (shape: " << this_top[top_id]->shape_string() << ") for shared layer " @@ -147,29 +159,35 @@ void Net::Init(const NetParameter& in_param) { } else { layers_[layer_id]->SetUp(bottom_vecs_[layer_id], top_vecs_[layer_id]); } - LOG_IF(INFO, Caffe::root_solver()) - << "Setting up " << layer_names_[layer_id]; - for (int top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) { + if (Caffe::root_solver()) { + LOG(INFO) << "Setting up " << layer_names_[layer_id]; + } + for (int_tp top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) { if (blob_loss_weights_.size() <= top_id_vecs_[layer_id][top_id]) { blob_loss_weights_.resize(top_id_vecs_[layer_id][top_id] + 1, Dtype(0)); } blob_loss_weights_[top_id_vecs_[layer_id][top_id]] = layer->loss(top_id); - LOG_IF(INFO, Caffe::root_solver()) - << "Top shape: " << top_vecs_[layer_id][top_id]->shape_string(); + if (Caffe::root_solver()) { + LOG(INFO) << "Top shape: " + << top_vecs_[layer_id][top_id]->shape_string(); + } if (layer->loss(top_id)) { - LOG_IF(INFO, Caffe::root_solver()) - << " with loss weight " << layer->loss(top_id); + if (Caffe::root_solver()) { + LOG(INFO) << " with loss weight " << layer->loss(top_id); + } } memory_used_ += top_vecs_[layer_id][top_id]->count(); } - LOG_IF(INFO, Caffe::root_solver()) - << "Memory required for data: " << memory_used_ * sizeof(Dtype); - const int param_size = layer_param.param_size(); - const int num_param_blobs = layers_[layer_id]->blobs().size(); + if (Caffe::root_solver()) { + DLOG(INFO) << "Memory required for data: " + << memory_used_ * sizeof(Dtype); + } + const int_tp param_size = layer_param.param_size(); + const int_tp num_param_blobs = layers_[layer_id]->blobs().size(); CHECK_LE(param_size, num_param_blobs) << "Too many params specified for layer " << layer_param.name(); ParamSpec default_param_spec; - for (int param_id = 0; param_id < num_param_blobs; ++param_id) { + for (int_tp param_id = 0; param_id < num_param_blobs; ++param_id) { const ParamSpec* param_spec = (param_id < param_size) ? &layer_param.param(param_id) : &default_param_spec; const bool param_need_backward = param_spec->lr_mult() != 0; @@ -177,17 +195,19 @@ void Net::Init(const NetParameter& in_param) { layers_[layer_id]->set_param_propagate_down(param_id, param_need_backward); } - for (int param_id = 0; param_id < num_param_blobs; ++param_id) { + for (int_tp param_id = 0; param_id < num_param_blobs; ++param_id) { AppendParam(param, layer_id, param_id); } // Finally, set the backward flag layer_need_backward_.push_back(need_backward); if (need_backward) { - for (int top_id = 0; top_id < top_id_vecs_[layer_id].size(); ++top_id) { + for (int_tp top_id = 0; top_id < top_id_vecs_[layer_id].size(); + ++top_id) { blob_need_backward_[top_id_vecs_[layer_id][top_id]] = true; } } } + // Go through the net backwards to determine which blobs contribute to the // loss. We can skip backward computation for blobs that don't contribute // to the loss. @@ -196,13 +216,13 @@ void Net::Init(const NetParameter& in_param) { // computation for the entire layer set blobs_under_loss; set blobs_skip_backp; - for (int layer_id = layers_.size() - 1; layer_id >= 0; --layer_id) { + for (int_tp layer_id = layers_.size() - 1; layer_id >= 0; --layer_id) { bool layer_contributes_loss = false; bool layer_skip_propagate_down = true; - for (int top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) { + for (int_tp top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) { const string& blob_name = blob_names_[top_id_vecs_[layer_id][top_id]]; - if (layers_[layer_id]->loss(top_id) || - (blobs_under_loss.find(blob_name) != blobs_under_loss.end())) { + if (layers_[layer_id]->loss(top_id) + || (blobs_under_loss.find(blob_name) != blobs_under_loss.end())) { layer_contributes_loss = true; } if (blobs_skip_backp.find(blob_name) == blobs_skip_backp.end()) { @@ -215,22 +235,26 @@ void Net::Init(const NetParameter& in_param) { // don't need backpropagation if (layer_need_backward_[layer_id] && layer_skip_propagate_down) { layer_need_backward_[layer_id] = false; - for (int bottom_id = 0; bottom_id < bottom_vecs_[layer_id].size(); - ++bottom_id) { + for (int_tp bottom_id = 0; bottom_id < bottom_vecs_[layer_id].size(); + ++bottom_id) { bottom_need_backward_[layer_id][bottom_id] = false; } } - if (!layer_contributes_loss) { layer_need_backward_[layer_id] = false; } - if (Caffe::root_solver()) { - if (layer_need_backward_[layer_id]) { + if (!layer_contributes_loss) { + layer_need_backward_[layer_id] = false; + } + if (layer_need_backward_[layer_id]) { + if (Caffe::root_solver()) { LOG(INFO) << layer_names_[layer_id] << " needs backward computation."; - } else { + } + } else { + if (Caffe::root_solver()) { LOG(INFO) << layer_names_[layer_id] - << " does not need backward computation."; + << " does not need backward computation."; } } - for (int bottom_id = 0; bottom_id < bottom_vecs_[layer_id].size(); - ++bottom_id) { + for (int_tp bottom_id = 0; bottom_id < bottom_vecs_[layer_id].size(); + ++bottom_id) { if (layer_contributes_loss) { const string& blob_name = blob_names_[bottom_id_vecs_[layer_id][bottom_id]]; @@ -240,26 +264,26 @@ void Net::Init(const NetParameter& in_param) { } if (!bottom_need_backward_[layer_id][bottom_id]) { const string& blob_name = - blob_names_[bottom_id_vecs_[layer_id][bottom_id]]; + blob_names_[bottom_id_vecs_[layer_id][bottom_id]]; blobs_skip_backp.insert(blob_name); } } } // Handle force_backward if needed. if (param.force_backward()) { - for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) { + for (int_tp layer_id = 0; layer_id < layers_.size(); ++layer_id) { layer_need_backward_[layer_id] = true; - for (int bottom_id = 0; - bottom_id < bottom_need_backward_[layer_id].size(); ++bottom_id) { + for (int_tp bottom_id = 0; + bottom_id < bottom_need_backward_[layer_id].size(); ++bottom_id) { bottom_need_backward_[layer_id][bottom_id] = - bottom_need_backward_[layer_id][bottom_id] || - layers_[layer_id]->AllowForceBackward(bottom_id); + bottom_need_backward_[layer_id][bottom_id] + || layers_[layer_id]->AllowForceBackward(bottom_id); blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] = - blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] || - bottom_need_backward_[layer_id][bottom_id]; + blob_need_backward_[bottom_id_vecs_[layer_id][bottom_id]] + || bottom_need_backward_[layer_id][bottom_id]; } - for (int param_id = 0; param_id < layers_[layer_id]->blobs().size(); - ++param_id) { + for (int_tp param_id = 0; param_id < layers_[layer_id]->blobs().size(); + ++param_id) { layers_[layer_id]->set_param_propagate_down(param_id, true); } } @@ -267,42 +291,46 @@ void Net::Init(const NetParameter& in_param) { // In the end, all remaining blobs are considered output blobs. for (set::iterator it = available_blobs.begin(); it != available_blobs.end(); ++it) { - LOG_IF(INFO, Caffe::root_solver()) - << "This network produces output " << *it; + if (Caffe::root_solver()) { + LOG(INFO) << "This network produces output " << *it; + } net_output_blobs_.push_back(blobs_[blob_name_to_idx[*it]].get()); net_output_blob_indices_.push_back(blob_name_to_idx[*it]); } - for (size_t blob_id = 0; blob_id < blob_names_.size(); ++blob_id) { + for (uint_tp blob_id = 0; blob_id < blob_names_.size(); ++blob_id) { blob_names_index_[blob_names_[blob_id]] = blob_id; } - for (size_t layer_id = 0; layer_id < layer_names_.size(); ++layer_id) { + for (uint_tp layer_id = 0; layer_id < layer_names_.size(); ++layer_id) { layer_names_index_[layer_names_[layer_id]] = layer_id; } ShareWeights(); debug_info_ = param.debug_info(); - LOG_IF(INFO, Caffe::root_solver()) << "Network initialization done."; + if (Caffe::root_solver()) { + LOG(INFO) << "Network initialization done."; + LOG(INFO) << "Memory required for data: " << memory_used_ * sizeof(Dtype); + } } -template +template void Net::FilterNet(const NetParameter& param, - NetParameter* param_filtered) { + NetParameter* param_filtered) { NetState net_state(param.state()); param_filtered->CopyFrom(param); param_filtered->clear_layer(); - for (int i = 0; i < param.layer_size(); ++i) { + for (int_tp i = 0; i < param.layer_size(); ++i) { const LayerParameter& layer_param = param.layer(i); const string& layer_name = layer_param.name(); CHECK(layer_param.include_size() == 0 || layer_param.exclude_size() == 0) - << "Specify either include rules or exclude rules; not both."; + << "Specify either include rules or exclude rules; not both."; // If no include rules are specified, the layer is included by default and // only excluded if it meets one of the exclude rules. bool layer_included = (layer_param.include_size() == 0); - for (int j = 0; layer_included && j < layer_param.exclude_size(); ++j) { + for (int_tp j = 0; layer_included && j < layer_param.exclude_size(); ++j) { if (StateMeetsRule(net_state, layer_param.exclude(j), layer_name)) { layer_included = false; } } - for (int j = 0; !layer_included && j < layer_param.include_size(); ++j) { + for (int_tp j = 0; !layer_included && j < layer_param.include_size(); ++j) { if (StateMeetsRule(net_state, layer_param.include(j), layer_name)) { layer_included = true; } @@ -313,66 +341,71 @@ void Net::FilterNet(const NetParameter& param, } } -template -bool Net::StateMeetsRule(const NetState& state, - const NetStateRule& rule, const string& layer_name) { +template +bool Net::StateMeetsRule(const NetState& state, const NetStateRule& rule, + const string& layer_name) { // Check whether the rule is broken due to phase. if (rule.has_phase()) { - if (rule.phase() != state.phase()) { - LOG_IF(INFO, Caffe::root_solver()) - << "The NetState phase (" << state.phase() - << ") differed from the phase (" << rule.phase() - << ") specified by a rule in layer " << layer_name; - return false; + if (rule.phase() != state.phase()) { + if (Caffe::root_solver()) { + LOG(INFO)<< "The NetState phase (" << state.phase() + << ") differed from the phase (" << rule.phase() + << ") specified by a rule in layer " << layer_name; } + return false; + } } // Check whether the rule is broken due to min level. if (rule.has_min_level()) { if (state.level() < rule.min_level()) { - LOG_IF(INFO, Caffe::root_solver()) - << "The NetState level (" << state.level() - << ") is above the min_level (" << rule.min_level() - << ") specified by a rule in layer " << layer_name; + if (Caffe::root_solver()) { + LOG(INFO) << "The NetState level (" << state.level() + << ") is above the min_level (" << rule.min_level() + << ") specified by a rule in layer " << layer_name; + } return false; } } // Check whether the rule is broken due to max level. if (rule.has_max_level()) { if (state.level() > rule.max_level()) { - LOG_IF(INFO, Caffe::root_solver()) - << "The NetState level (" << state.level() - << ") is above the max_level (" << rule.max_level() - << ") specified by a rule in layer " << layer_name; + if (Caffe::root_solver()) { + LOG(INFO) << "The NetState level (" << state.level() + << ") is above the max_level (" << rule.max_level() + << ") specified by a rule in layer " << layer_name; + } return false; } } // Check whether the rule is broken due to stage. The NetState must // contain ALL of the rule's stages to meet it. - for (int i = 0; i < rule.stage_size(); ++i) { + for (int_tp i = 0; i < rule.stage_size(); ++i) { // Check that the NetState contains the rule's ith stage. bool has_stage = false; - for (int j = 0; !has_stage && j < state.stage_size(); ++j) { - if (rule.stage(i) == state.stage(j)) { has_stage = true; } + for (int_tp j = 0; !has_stage && j < state.stage_size(); ++j) { + if (rule.stage(i) == state.stage(j)) {has_stage = true;} } if (!has_stage) { - LOG_IF(INFO, Caffe::root_solver()) - << "The NetState did not contain stage '" << rule.stage(i) - << "' specified by a rule in layer " << layer_name; + if (Caffe::root_solver()) { + LOG(INFO) << "The NetState did not contain stage '" << rule.stage(i) + << "' specified by a rule in layer " << layer_name; + } return false; } } // Check whether the rule is broken due to not_stage. The NetState must // contain NONE of the rule's not_stages to meet it. - for (int i = 0; i < rule.not_stage_size(); ++i) { + for (int_tp i = 0; i < rule.not_stage_size(); ++i) { // Check that the NetState contains the rule's ith not_stage. bool has_stage = false; - for (int j = 0; !has_stage && j < state.stage_size(); ++j) { - if (rule.not_stage(i) == state.stage(j)) { has_stage = true; } + for (int_tp j = 0; !has_stage && j < state.stage_size(); ++j) { + if (rule.not_stage(i) == state.stage(j)) {has_stage = true;} } if (has_stage) { - LOG_IF(INFO, Caffe::root_solver()) - << "The NetState contained a not_stage '" << rule.not_stage(i) - << "' specified by a rule in layer " << layer_name; + if (Caffe::root_solver()) { + LOG(INFO) << "The NetState contained a not_stage '" << rule.not_stage(i) + << "' specified by a rule in layer " << layer_name; + } return false; } } @@ -381,25 +414,28 @@ bool Net::StateMeetsRule(const NetState& state, // Helper for Net::Init: add a new input or top blob to the net. (Inputs have // layer_id == -1, tops have layer_id >= 0.) -template -void Net::AppendTop(const NetParameter& param, const int layer_id, - const int top_id, set* available_blobs, - map* blob_name_to_idx) { - shared_ptr layer_param((layer_id >= 0) ? - (new LayerParameter(param.layer(layer_id))) : NULL); - const string& blob_name = layer_param ? - (layer_param->top_size() > top_id ? - layer_param->top(top_id) : "(automatic)") : param.input(top_id); +template +void Net::AppendTop(const NetParameter& param, const int_tp layer_id, + const int_tp top_id, set* available_blobs, + map* blob_name_to_idx) { + shared_ptr layer_param( + (layer_id >= 0) ? (new LayerParameter(param.layer(layer_id))) : NULL); + const string& blob_name = + layer_param ? + (layer_param->top_size() > top_id ? + layer_param->top(top_id) : "(automatic)") : + param.input(top_id); // Check if we are doing in-place computation - if (blob_name_to_idx && layer_param && layer_param->bottom_size() > top_id && - blob_name == layer_param->bottom(top_id)) { + if (blob_name_to_idx && layer_param && layer_param->bottom_size() > top_id + && blob_name == layer_param->bottom(top_id)) { // In-place computation - LOG_IF(INFO, Caffe::root_solver()) - << layer_param->name() << " -> " << blob_name << " (in-place)"; + if (Caffe::root_solver()) { + LOG(INFO) << layer_param->name() << " -> " << blob_name << " (in-place)"; + } top_vecs_[layer_id].push_back(blobs_[(*blob_name_to_idx)[blob_name]].get()); top_id_vecs_[layer_id].push_back((*blob_name_to_idx)[blob_name]); } else if (blob_name_to_idx && - blob_name_to_idx->find(blob_name) != blob_name_to_idx->end()) { + blob_name_to_idx->find(blob_name) != blob_name_to_idx->end()) { // If we are not doing in-place computation but have duplicated blobs, // raise an error. LOG(FATAL) << "Top blob '" << blob_name @@ -414,18 +450,18 @@ void Net::AppendTop(const NetParameter& param, const int layer_id, } } shared_ptr > blob_pointer(new Blob()); - const int blob_id = blobs_.size(); + const int_tp blob_id = blobs_.size(); blobs_.push_back(blob_pointer); blob_names_.push_back(blob_name); blob_need_backward_.push_back(false); - if (blob_name_to_idx) { (*blob_name_to_idx)[blob_name] = blob_id; } + if (blob_name_to_idx) {(*blob_name_to_idx)[blob_name] = blob_id;} if (layer_id == -1) { // Set the (explicitly specified) dimensions of the input blob. if (param.input_dim_size() > 0) { blob_pointer->Reshape(param.input_dim(top_id * 4), - param.input_dim(top_id * 4 + 1), - param.input_dim(top_id * 4 + 2), - param.input_dim(top_id * 4 + 3)); + param.input_dim(top_id * 4 + 1), + param.input_dim(top_id * 4 + 2), + param.input_dim(top_id * 4 + 3)); } else { blob_pointer->Reshape(param.input_shape(top_id)); } @@ -436,23 +472,28 @@ void Net::AppendTop(const NetParameter& param, const int layer_id, top_vecs_[layer_id].push_back(blob_pointer.get()); } } - if (available_blobs) { available_blobs->insert(blob_name); } + if (available_blobs) { + available_blobs->insert(blob_name); + } } // Helper for Net::Init: add a new bottom blob to the net. -template -int Net::AppendBottom(const NetParameter& param, const int layer_id, - const int bottom_id, set* available_blobs, - map* blob_name_to_idx) { + +template +int_tp Net::AppendBottom(const NetParameter& param, + const int_tp layer_id, const int_tp bottom_id, + set* available_blobs, + map* blob_name_to_idx) { const LayerParameter& layer_param = param.layer(layer_id); const string& blob_name = layer_param.bottom(bottom_id); if (available_blobs->find(blob_name) == available_blobs->end()) { LOG(FATAL) << "Unknown bottom blob '" << blob_name << "' (layer '" << layer_param.name() << "', bottom index " << bottom_id << ")"; } - const int blob_id = (*blob_name_to_idx)[blob_name]; - LOG_IF(INFO, Caffe::root_solver()) - << layer_names_[layer_id] << " <- " << blob_name; + const int_tp blob_id = (*blob_name_to_idx)[blob_name]; + if (Caffe::root_solver()) { + LOG(INFO) << layer_names_[layer_id] << " <- " << blob_name; + } bottom_vecs_[layer_id].push_back(blobs_[blob_id].get()); bottom_id_vecs_[layer_id].push_back(blob_id); available_blobs->erase(blob_name); @@ -460,17 +501,16 @@ int Net::AppendBottom(const NetParameter& param, const int layer_id, // Check if the backpropagation on bottom_id should be skipped if (layer_param.propagate_down_size() > 0) propagate_down = layer_param.propagate_down(bottom_id); - const bool need_backward = blob_need_backward_[blob_id] && - propagate_down; + const bool need_backward = blob_need_backward_[blob_id] && propagate_down; bottom_need_backward_[layer_id].push_back(need_backward); return blob_id; } -template -void Net::AppendParam(const NetParameter& param, const int layer_id, - const int param_id) { +template +void Net::AppendParam(const NetParameter& param, const int_tp layer_id, + const int_tp param_id) { const LayerParameter& layer_param = layers_[layer_id]->layer_param(); - const int param_size = layer_param.param_size(); + const int_tp param_size = layer_param.param_size(); string param_name = (param_size > param_id) ? layer_param.param(param_id).name() : ""; if (param_name.size()) { @@ -480,7 +520,7 @@ void Net::AppendParam(const NetParameter& param, const int layer_id, param_display_name << param_id; param_display_names_.push_back(param_display_name.str()); } - const int net_param_id = params_.size(); + const int_tp net_param_id = params_.size(); params_.push_back(layers_[layer_id]->blobs()[param_id]); param_id_vecs_[layer_id].push_back(net_param_id); param_layer_indices_.push_back(make_pair(layer_id, param_id)); @@ -496,7 +536,7 @@ void Net::AppendParam(const NetParameter& param, const int layer_id, if (param_name.size()) { param_names_index_[param_name] = net_param_id; } - const int learnable_param_id = learnable_params_.size(); + const int_tp learnable_param_id = learnable_params_.size(); learnable_params_.push_back(params_[net_param_id].get()); learnable_param_ids_.push_back(learnable_param_id); has_params_lr_.push_back(param_spec->has_lr_mult()); @@ -505,22 +545,23 @@ void Net::AppendParam(const NetParameter& param, const int layer_id, params_weight_decay_.push_back(param_spec->decay_mult()); } else { // Named param blob with name we've seen before: share params - const int owner_net_param_id = param_names_index_[param_name]; + const int_tp owner_net_param_id = param_names_index_[param_name]; param_owners_.push_back(owner_net_param_id); - const pair& owner_index = + const pair& owner_index = param_layer_indices_[owner_net_param_id]; - const int owner_layer_id = owner_index.first; - const int owner_param_id = owner_index.second; + const int_tp owner_layer_id = owner_index.first; + const int_tp owner_param_id = owner_index.second; LOG_IF(INFO, Caffe::root_solver()) << "Sharing parameters '" << param_name << "' owned by " << "layer '" << layer_names_[owner_layer_id] << "', param " << "index " << owner_param_id; Blob* this_blob = layers_[layer_id]->blobs()[param_id].get(); - Blob* owner_blob = - layers_[owner_layer_id]->blobs()[owner_param_id].get(); - const int param_size = layer_param.param_size(); - if (param_size > param_id && (layer_param.param(param_id).share_mode() == - ParamSpec_DimCheckMode_PERMISSIVE)) { + Blob* owner_blob = layers_[owner_layer_id]->blobs()[owner_param_id] + .get(); + const int_tp param_size = layer_param.param_size(); + if (param_size > param_id + && (layer_param.param(param_id).share_mode() + == ParamSpec_DimCheckMode_PERMISSIVE)) { // Permissive dimension checking -- only check counts are the same. CHECK_EQ(this_blob->count(), owner_blob->count()) << "Cannot share param '" << param_name << "' owned by layer '" @@ -537,7 +578,8 @@ void Net::AppendParam(const NetParameter& param, const int layer_id, << "shape is " << owner_blob->shape_string() << "; sharing layer " << "expects shape " << this_blob->shape_string(); } - const int learnable_param_id = learnable_param_ids_[owner_net_param_id]; + + const int_tp learnable_param_id = learnable_param_ids_[owner_net_param_id]; learnable_param_ids_.push_back(learnable_param_id); if (param_spec->has_lr_mult()) { if (has_params_lr_[learnable_param_id]) { @@ -561,36 +603,38 @@ void Net::AppendParam(const NetParameter& param, const int layer_id, } } -template -Dtype Net::ForwardFromTo(int start, int end) { +template +Dtype Net::ForwardFromTo(int_tp start, int_tp end) { CHECK_GE(start, 0); CHECK_LT(end, layers_.size()); Dtype loss = 0; if (debug_info_) { - for (int i = 0; i < net_input_blobs_.size(); ++i) { + for (int_tp i = 0; i < net_input_blobs_.size(); ++i) { InputDebugInfo(i); } } - for (int i = start; i <= end; ++i) { + for (int_tp i = start; i <= end; ++i) { // LOG(ERROR) << "Forwarding " << layer_names_[i]; Dtype layer_loss = layers_[i]->Forward(bottom_vecs_[i], top_vecs_[i]); loss += layer_loss; - if (debug_info_) { ForwardDebugInfo(i); } + if (debug_info_) { + ForwardDebugInfo(i); + } } return loss; } -template -Dtype Net::ForwardFrom(int start) { +template +Dtype Net::ForwardFrom(int_tp start) { return ForwardFromTo(start, layers_.size() - 1); } -template -Dtype Net::ForwardTo(int end) { +template +Dtype Net::ForwardTo(int_tp end) { return ForwardFromTo(0, end); } -template +template const vector*>& Net::ForwardPrefilled(Dtype* loss) { if (loss != NULL) { *loss = ForwardFromTo(0, layers_.size() - 1); @@ -600,30 +644,30 @@ const vector*>& Net::ForwardPrefilled(Dtype* loss) { return net_output_blobs_; } -template +template const vector*>& Net::Forward( const vector*> & bottom, Dtype* loss) { // Copy bottom to internal bottom - for (int i = 0; i < bottom.size(); ++i) { + for (int_tp i = 0; i < bottom.size(); ++i) { net_input_blobs_[i]->CopyFrom(*bottom[i]); } return ForwardPrefilled(loss); } -template +template string Net::Forward(const string& input_blob_protos, Dtype* loss) { BlobProtoVector blob_proto_vec; if (net_input_blobs_.size()) { blob_proto_vec.ParseFromString(input_blob_protos); CHECK_EQ(blob_proto_vec.blobs_size(), net_input_blobs_.size()) << "Incorrect input size."; - for (int i = 0; i < blob_proto_vec.blobs_size(); ++i) { + for (int_tp i = 0; i < blob_proto_vec.blobs_size(); ++i) { net_input_blobs_[i]->FromProto(blob_proto_vec.blobs(i)); } } ForwardPrefilled(loss); blob_proto_vec.Clear(); - for (int i = 0; i < net_output_blobs_.size(); ++i) { + for (int_tp i = 0; i < net_output_blobs_.size(); ++i) { net_output_blobs_[i]->ToProto(blob_proto_vec.add_blobs()); } string output; @@ -631,129 +675,142 @@ string Net::Forward(const string& input_blob_protos, Dtype* loss) { return output; } -template -void Net::BackwardFromTo(int start, int end) { +template +void Net::BackwardFromTo(int_tp start, int_tp end) { CHECK_GE(end, 0); CHECK_LT(start, layers_.size()); - for (int i = start; i >= end; --i) { + for (int_tp i = start; i >= end; --i) { if (layer_need_backward_[i]) { - layers_[i]->Backward( - top_vecs_[i], bottom_need_backward_[i], bottom_vecs_[i]); - if (debug_info_) { BackwardDebugInfo(i); } + layers_[i]->Backward(top_vecs_[i], bottom_need_backward_[i], + bottom_vecs_[i]); + if (debug_info_) { + BackwardDebugInfo(i); + } } } } -template -void Net::InputDebugInfo(const int input_id) { +template +void Net::InputDebugInfo(const int_tp input_id) { const Blob& blob = *net_input_blobs_[input_id]; const string& blob_name = blob_names_[net_input_blob_indices_[input_id]]; const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); - LOG_IF(INFO, Caffe::root_solver()) - << " [Forward] " - << "Input " << blob_name << " data: " << data_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Forward] " + << "Input " << blob_name << " data: " << data_abs_val_mean; + } } -template -void Net::ForwardDebugInfo(const int layer_id) { - for (int top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) { +template +void Net::ForwardDebugInfo(const int_tp layer_id) { + for (int_tp top_id = 0; top_id < top_vecs_[layer_id].size(); ++top_id) { const Blob& blob = *top_vecs_[layer_id][top_id]; const string& blob_name = blob_names_[top_id_vecs_[layer_id][top_id]]; const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); - LOG_IF(INFO, Caffe::root_solver()) - << " [Forward] " - << "Layer " << layer_names_[layer_id] - << ", top blob " << blob_name - << " data: " << data_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Forward] " + << "Layer " << layer_names_[layer_id] + << ", top blob " << blob_name + << " data: " << data_abs_val_mean; + } } - for (int param_id = 0; param_id < layers_[layer_id]->blobs().size(); - ++param_id) { + for (int_tp param_id = 0; param_id < layers_[layer_id]->blobs().size(); + ++param_id) { const Blob& blob = *layers_[layer_id]->blobs()[param_id]; - const int net_param_id = param_id_vecs_[layer_id][param_id]; + const int_tp net_param_id = param_id_vecs_[layer_id][param_id]; const string& blob_name = param_display_names_[net_param_id]; const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); - LOG_IF(INFO, Caffe::root_solver()) - << " [Forward] " - << "Layer " << layer_names_[layer_id] - << ", param blob " << blob_name - << " data: " << data_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Forward] " + << "Layer " << layer_names_[layer_id] + << ", param blob " << blob_name + << " data: " << data_abs_val_mean; + } } } -template -void Net::BackwardDebugInfo(const int layer_id) { +template +void Net::BackwardDebugInfo(const int_tp layer_id) { const vector*>& bottom_vec = bottom_vecs_[layer_id]; - for (int bottom_id = 0; bottom_id < bottom_vec.size(); ++bottom_id) { - if (!bottom_need_backward_[layer_id][bottom_id]) { continue; } + for (int_tp bottom_id = 0; bottom_id < bottom_vec.size(); ++bottom_id) { + if (!bottom_need_backward_[layer_id][bottom_id]) { + continue; + } const Blob& blob = *bottom_vec[bottom_id]; const string& blob_name = blob_names_[bottom_id_vecs_[layer_id][bottom_id]]; const Dtype diff_abs_val_mean = blob.asum_diff() / blob.count(); - LOG_IF(INFO, Caffe::root_solver()) - << " [Backward] " - << "Layer " << layer_names_[layer_id] - << ", bottom blob " << blob_name - << " diff: " << diff_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Backward] " + << "Layer " << layer_names_[layer_id] + << ", bottom blob " << blob_name + << " diff: " << diff_abs_val_mean; + } } - for (int param_id = 0; param_id < layers_[layer_id]->blobs().size(); - ++param_id) { - if (!layers_[layer_id]->param_propagate_down(param_id)) { continue; } + for (int_tp param_id = 0; param_id < layers_[layer_id]->blobs().size(); + ++param_id) { + if (!layers_[layer_id]->param_propagate_down(param_id)) { + continue; + } const Blob& blob = *layers_[layer_id]->blobs()[param_id]; const Dtype diff_abs_val_mean = blob.asum_diff() / blob.count(); - LOG_IF(INFO, Caffe::root_solver()) - << " [Backward] " - << "Layer " << layer_names_[layer_id] - << ", param blob " << param_id - << " diff: " << diff_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Backward] " + << "Layer " << layer_names_[layer_id] + << ", param blob " << param_id + << " diff: " << diff_abs_val_mean; + } } } -template -void Net::UpdateDebugInfo(const int param_id) { +template +void Net::UpdateDebugInfo(const int_tp param_id) { const Blob& blob = *params_[param_id]; - const int param_owner = param_owners_[param_id]; + const int_tp param_owner = param_owners_[param_id]; const string& layer_name = layer_names_[param_layer_indices_[param_id].first]; const string& param_display_name = param_display_names_[param_id]; const Dtype diff_abs_val_mean = blob.asum_diff() / blob.count(); if (param_owner < 0) { const Dtype data_abs_val_mean = blob.asum_data() / blob.count(); - LOG_IF(INFO, Caffe::root_solver()) - << " [Update] Layer " << layer_name - << ", param " << param_display_name - << " data: " << data_abs_val_mean - << "; diff: " << diff_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Update] Layer " << layer_name + << ", param " << param_display_name + << " data: " << data_abs_val_mean + << "; diff: " << diff_abs_val_mean; + } } else { const string& owner_layer_name = layer_names_[param_layer_indices_[param_owner].first]; - LOG_IF(INFO, Caffe::root_solver()) - << " [Update] Layer " << layer_name - << ", param blob " << param_display_name - << " (owned by layer " << owner_layer_name << ", " << "param " - << param_display_names_[param_owners_[param_id]] << ")" - << " diff: " << diff_abs_val_mean; + if (Caffe::root_solver()) { + LOG(INFO) << " [Update] Layer " << layer_name + << ", param blob " << param_display_name + << " (owned by layer " << owner_layer_name << ", " << "param " + << param_display_names_[param_owners_[param_id]] << ")" + << " diff: " << diff_abs_val_mean; + } } } -template +template void Net::ShareTrainedLayersWith(const Net* other) { - int num_source_layers = other->layers().size(); - for (int i = 0; i < num_source_layers; ++i) { + int_tp num_source_layers = other->layers().size(); + for (int_tp i = 0; i < num_source_layers; ++i) { Layer* source_layer = other->layers()[i].get(); const string& source_layer_name = other->layer_names()[i]; - int target_layer_id = 0; - while (target_layer_id != layer_names_.size() && - layer_names_[target_layer_id] != source_layer_name) { + int_tp target_layer_id = 0; + while (target_layer_id != layer_names_.size() + && layer_names_[target_layer_id] != source_layer_name) { ++target_layer_id; } if (target_layer_id == layer_names_.size()) { LOG(INFO) << "Ignoring source layer " << source_layer_name; continue; } - DLOG(INFO) << "Copying source layer " << source_layer_name; - vector > >& target_blobs = - layers_[target_layer_id]->blobs(); + DLOG(INFO)<< "Copying source layer " << source_layer_name; + vector > >& target_blobs = layers_[target_layer_id] + ->blobs(); CHECK_EQ(target_blobs.size(), source_layer->blobs().size()) << "Incompatible number of blobs for layer " << source_layer_name; - for (int j = 0; j < target_blobs.size(); ++j) { + for (int_tp j = 0; j < target_blobs.size(); ++j) { Blob* source_blob = source_layer->blobs()[j].get(); CHECK(target_blobs[j]->shape() == source_blob->shape()) << "Cannot share param " << j << " weights from layer '" @@ -765,22 +822,22 @@ void Net::ShareTrainedLayersWith(const Net* other) { } } -template -void Net::BackwardFrom(int start) { +template +void Net::BackwardFrom(int_tp start) { BackwardFromTo(start, 0); } -template -void Net::BackwardTo(int end) { +template +void Net::BackwardTo(int_tp end) { BackwardFromTo(layers_.size() - 1, end); } -template +template void Net::Backward() { BackwardFromTo(layers_.size() - 1, 0); if (debug_info_) { Dtype asum_data = 0, asum_diff = 0, sumsq_data = 0, sumsq_diff = 0; - for (int i = 0; i < learnable_params_.size(); ++i) { + for (int_tp i = 0; i < learnable_params_.size(); ++i) { asum_data += learnable_params_[i]->asum_data(); asum_diff += learnable_params_[i]->asum_diff(); sumsq_data += learnable_params_[i]->sumsq_data(); @@ -794,34 +851,34 @@ void Net::Backward() { } } -template +template void Net::Reshape() { - for (int i = 0; i < layers_.size(); ++i) { + for (int_tp i = 0; i < layers_.size(); ++i) { layers_[i]->Reshape(bottom_vecs_[i], top_vecs_[i]); } } -template +template void Net::CopyTrainedLayersFrom(const NetParameter& param) { - int num_source_layers = param.layer_size(); - for (int i = 0; i < num_source_layers; ++i) { + int_tp num_source_layers = param.layer_size(); + for (int_tp i = 0; i < num_source_layers; ++i) { const LayerParameter& source_layer = param.layer(i); const string& source_layer_name = source_layer.name(); - int target_layer_id = 0; - while (target_layer_id != layer_names_.size() && - layer_names_[target_layer_id] != source_layer_name) { + int_tp target_layer_id = 0; + while (target_layer_id != layer_names_.size() + && layer_names_[target_layer_id] != source_layer_name) { ++target_layer_id; } if (target_layer_id == layer_names_.size()) { LOG(INFO) << "Ignoring source layer " << source_layer_name; continue; } - DLOG(INFO) << "Copying source layer " << source_layer_name; - vector > >& target_blobs = - layers_[target_layer_id]->blobs(); + DLOG(INFO)<< "Copying source layer " << source_layer_name; + vector > >& target_blobs = layers_[target_layer_id] + ->blobs(); CHECK_EQ(target_blobs.size(), source_layer.blobs_size()) << "Incompatible number of blobs for layer " << source_layer_name; - for (int j = 0; j < target_blobs.size(); ++j) { + for (int_tp j = 0; j < target_blobs.size(); ++j) { if (!target_blobs[j]->ShapeEquals(source_layer.blobs(j))) { Blob source_blob; const bool kReshape = true; @@ -839,7 +896,7 @@ void Net::CopyTrainedLayersFrom(const NetParameter& param) { } } -template +template void Net::CopyTrainedLayersFrom(const string trained_filename) { if (trained_filename.size() >= 3 && trained_filename.compare(trained_filename.size() - 3, 3, ".h5") == 0) { @@ -864,14 +921,14 @@ void Net::CopyTrainedLayersFromHDF5(const string trained_filename) { CHECK_GE(file_hid, 0) << "Couldn't open " << trained_filename; hid_t data_hid = H5Gopen2(file_hid, "data", H5P_DEFAULT); CHECK_GE(data_hid, 0) << "Error reading weights from " << trained_filename; - int num_layers = hdf5_get_num_links(data_hid); - for (int i = 0; i < num_layers; ++i) { + int_tp num_layers = hdf5_get_num_links(data_hid); + for (int_tp i = 0; i < num_layers; ++i) { string source_layer_name = hdf5_get_name_by_idx(data_hid, i); if (!layer_names_index_.count(source_layer_name)) { LOG(INFO) << "Ignoring source layer " << source_layer_name; continue; } - int target_layer_id = layer_names_index_[source_layer_name]; + int_tp target_layer_id = layer_names_index_[source_layer_name]; DLOG(INFO) << "Copying source layer " << source_layer_name; vector > >& target_blobs = layers_[target_layer_id]->blobs(); @@ -880,14 +937,14 @@ void Net::CopyTrainedLayersFromHDF5(const string trained_filename) { CHECK_GE(layer_hid, 0) << "Error reading weights from " << trained_filename; // Check that source layer doesn't have more params than target layer - int num_source_params = hdf5_get_num_links(layer_hid); + int_tp num_source_params = hdf5_get_num_links(layer_hid); CHECK_LE(num_source_params, target_blobs.size()) << "Incompatible number of blobs for layer " << source_layer_name; - for (int j = 0; j < target_blobs.size(); ++j) { + for (int_tp j = 0; j < target_blobs.size(); ++j) { ostringstream oss; oss << j; string dataset_name = oss.str(); - int target_net_param_id = param_id_vecs_[target_layer_id][j]; + int_tp target_net_param_id = param_id_vecs_[target_layer_id][j]; if (!H5Lexists(layer_hid, dataset_name.c_str(), H5P_DEFAULT)) { // Target param doesn't exist in source weights... if (param_owners_[target_net_param_id] != -1) { @@ -912,16 +969,17 @@ void Net::ToProto(NetParameter* param, bool write_diff) const { param->Clear(); param->set_name(name_); // Add bottom and top - for (int i = 0; i < net_input_blob_indices_.size(); ++i) { + for (int_tp i = 0; i < net_input_blob_indices_.size(); ++i) { param->add_input(blob_names_[net_input_blob_indices_[i]]); } - DLOG(INFO) << "Serializing " << layers_.size() << " layers"; - for (int i = 0; i < layers_.size(); ++i) { + DLOG(INFO)<< "Serializing " << layers_.size() << " layers"; + for (int_tp i = 0; i < layers_.size(); ++i) { LayerParameter* layer_param = param->add_layer(); layers_[i]->ToProto(layer_param, write_diff); } } + template void Net::ToHDF5(const string& filename, bool write_diff) const { hid_t file_hid = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, @@ -937,7 +995,7 @@ void Net::ToHDF5(const string& filename, bool write_diff) const { H5P_DEFAULT); CHECK_GE(diff_hid, 0) << "Error saving weights to " << filename << "."; } - for (int layer_id = 0; layer_id < layers_.size(); ++layer_id) { + for (int_tp layer_id = 0; layer_id < layers_.size(); ++layer_id) { const LayerParameter& layer_param = layers_[layer_id]->layer_param(); string layer_name = layer_param.name(); hid_t layer_data_hid = H5Gcreate2(data_hid, layer_name.c_str(), @@ -951,11 +1009,11 @@ void Net::ToHDF5(const string& filename, bool write_diff) const { CHECK_GE(layer_diff_hid, 0) << "Error saving weights to " << filename << "."; } - int num_params = layers_[layer_id]->blobs().size(); - for (int param_id = 0; param_id < num_params; ++param_id) { + int_tp num_params = layers_[layer_id]->blobs().size(); + for (int_tp param_id = 0; param_id < num_params; ++param_id) { ostringstream dataset_name; dataset_name << param_id; - const int net_param_id = param_id_vecs_[layer_id][param_id]; + const int_tp net_param_id = param_id_vecs_[layer_id][param_id]; if (param_owners_[net_param_id] == -1) { // Only save params that own themselves hdf5_save_nd_dataset(layer_data_hid, dataset_name.str(), @@ -981,14 +1039,14 @@ void Net::ToHDF5(const string& filename, bool write_diff) const { template void Net::Update() { - for (int i = 0; i < learnable_params_.size(); ++i) { + for (int_tp i = 0; i < learnable_params_.size(); ++i) { learnable_params_[i]->Update(); } } template void Net::ClearParamDiffs() { - for (int i = 0; i < learnable_params_.size(); ++i) { + for (int_tp i = 0; i < learnable_params_.size(); ++i) { Blob* blob = learnable_params_[i]; switch (Caffe::mode()) { case Caffe::CPU: @@ -997,10 +1055,20 @@ void Net::ClearParamDiffs() { break; case Caffe::GPU: #ifndef CPU_ONLY + if (device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_set(blob->count(), static_cast(0), blob->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_set(device_->id(), + blob->count(), static_cast(0), + (cl_mem)(blob->mutable_gpu_diff()), 0); +#endif // USE_GREENTEA + } #else - NO_GPU; + NO_GPU; #endif break; } @@ -1009,45 +1077,45 @@ void Net::ClearParamDiffs() { template void Net::ShareWeights() { - for (int i = 0; i < params_.size(); ++i) { + for (int_tp i = 0; i < params_.size(); ++i) { if (param_owners_[i] < 0) { continue; } params_[i]->ShareData(*params_[param_owners_[i]]); params_[i]->ShareDiff(*params_[param_owners_[i]]); } } -template +template bool Net::has_blob(const string& blob_name) const { return blob_names_index_.find(blob_name) != blob_names_index_.end(); } -template +template const shared_ptr > Net::blob_by_name( const string& blob_name) const { shared_ptr > blob_ptr; if (has_blob(blob_name)) { blob_ptr = blobs_[blob_names_index_.find(blob_name)->second]; } else { - blob_ptr.reset((Blob*)(NULL)); - LOG(WARNING) << "Unknown blob name " << blob_name; + blob_ptr.reset((Blob*) (NULL)); + LOG(WARNING)<< "Unknown blob name " << blob_name; } return blob_ptr; } -template +template bool Net::has_layer(const string& layer_name) const { return layer_names_index_.find(layer_name) != layer_names_index_.end(); } -template +template const shared_ptr > Net::layer_by_name( const string& layer_name) const { shared_ptr > layer_ptr; if (has_layer(layer_name)) { layer_ptr = layers_[layer_names_index_.find(layer_name)->second]; } else { - layer_ptr.reset((Layer*)(NULL)); - LOG(WARNING) << "Unknown layer name " << layer_name; + layer_ptr.reset((Layer*) (NULL)); + LOG(WARNING)<< "Unknown layer name " << layer_name; } return layer_ptr; } diff --git a/src/caffe/opencl/ocl_dev_ptr.cpp b/src/caffe/opencl/ocl_dev_ptr.cpp new file mode 100644 index 00000000000..361acb4c471 --- /dev/null +++ b/src/caffe/opencl/ocl_dev_ptr.cpp @@ -0,0 +1,24 @@ +#include "caffe/opencl/ocl_dev_ptr.hpp" + +#ifdef USE_GREENTEA + +namespace caffe { + +template +ocl_dev_ptr::ocl_dev_ptr(cl_mem ocl_mem) + : ocl_mem_(ocl_mem) { +} + +template +Type* ocl_dev_ptr::get() { + return nullptr; +} + +template +std::size_t ocl_dev_ptr::off() { + return 0; +} + +} // namespace caffe + +#endif // USE_GREENTEA diff --git a/src/caffe/parallel.cpp b/src/caffe/parallel.cpp index 62f5d738593..f3c9e064b49 100644 --- a/src/caffe/parallel.cpp +++ b/src/caffe/parallel.cpp @@ -1,6 +1,12 @@ +#ifdef CMAKE_BUILD + #include "caffe_config.h" +#endif + #ifndef CPU_ONLY +#ifdef USE_CUDA #include -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY #include #include @@ -23,11 +29,11 @@ enum Op { }; template -static void apply_buffers(const vector*>& blobs, - Dtype* buffer, size_t total_size, Op op) { +static void apply_buffers(const vector*>& blobs, Dtype* buffer, + uint_tp total_size, Op op) { Dtype* ptr = buffer; for (int i = 0; i < blobs.size(); ++i) { - int size = blobs[i]->count(); + int_tp size = blobs[i]->count(); switch (op) { case copy: { // Init buffer to current values of blobs @@ -57,8 +63,8 @@ static void apply_buffers(const vector*>& blobs, // Buffer size necessary to store given blobs template -static size_t total_size(const vector*>& params) { - size_t size = 0; +static uint_tp total_size(const vector*>& params) { + uint_tp size = 0; for (int i = 0; i < params.size(); ++i) size += params[i]->count(); // Size have at least one byte, otherwise cudaMalloc fails if net has no @@ -68,8 +74,7 @@ static size_t total_size(const vector*>& params) { template Params::Params(shared_ptr > root_solver) - : size_(total_size(root_solver->net()->learnable_params())), - data_(), + : size_(total_size(root_solver->net()->learnable_params())), data_(), diff_() { } @@ -77,6 +82,7 @@ template GPUParams::GPUParams(shared_ptr > root_solver, int device) : Params(root_solver) { #ifndef CPU_ONLY +#ifdef USE_CUDA int initial_device; CUDA_CHECK(cudaGetDevice(&initial_device)); @@ -85,14 +91,14 @@ GPUParams::GPUParams(shared_ptr > root_solver, int device) CUDA_CHECK(cudaMalloc(&data_, size_ * sizeof(Dtype))); // Copy blob values - const vector*>& net = - root_solver->net()->learnable_params(); + const vector*>& net = root_solver->net()->learnable_params(); apply_buffers(net, data_, size_, copy); CUDA_CHECK(cudaMalloc(&diff_, size_ * sizeof(Dtype))); caffe_gpu_set(size_, Dtype(0), diff_); CUDA_CHECK(cudaSetDevice(initial_device)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -101,22 +107,24 @@ GPUParams::GPUParams(shared_ptr > root_solver, int device) template GPUParams::~GPUParams() { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaFree(data_)); CUDA_CHECK(cudaFree(diff_)); -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY } template void GPUParams::configure(Solver* solver) const { - const vector*>& net = - solver->net()->learnable_params(); + const vector*>& net = solver->net()->learnable_params(); apply_buffers(net, data_, size_, replace_gpu); apply_buffers(net, diff_, size_, replace_gpu_diff); } -void DevicePair::compute(const vector devices, vector* pairs) { +void DevicePair::compute(const vector devices, + vector* pairs) { #ifndef CPU_ONLY - vector remaining(devices); + vector remaining(devices); // Depth for reduction tree int remaining_depth = static_cast(ceil(log2(remaining.size()))); @@ -125,16 +133,22 @@ void DevicePair::compute(const vector devices, vector* pairs) { for (int d = 0; d < remaining_depth; ++d) { for (int i = 0; i < remaining.size(); ++i) { for (int j = i + 1; j < remaining.size(); ++j) { - cudaDeviceProp a, b; - CUDA_CHECK(cudaGetDeviceProperties(&a, remaining[i])); - CUDA_CHECK(cudaGetDeviceProperties(&b, remaining[j])); - if (a.isMultiGpuBoard && b.isMultiGpuBoard) { - if (a.multiGpuBoardGroupID == b.multiGpuBoardGroupID) { - pairs->push_back(DevicePair(remaining[i], remaining[j])); - DLOG(INFO) << "GPU board: " << remaining[i] << ":" << remaining[j]; - remaining.erase(remaining.begin() + j); - break; + // Currently, dual-chip device only on CUDA + if (remaining[i]->backend() == BACKEND_CUDA + && remaining[j]->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + cudaDeviceProp a, b; + CUDA_CHECK(cudaGetDeviceProperties(&a, remaining[i]->id())); + CUDA_CHECK(cudaGetDeviceProperties(&b, remaining[j]->id())); + if (a.isMultiGpuBoard && b.isMultiGpuBoard) { + if (a.multiGpuBoardGroupID == b.multiGpuBoardGroupID) { + pairs->push_back(DevicePair(remaining[i], remaining[j])); + DLOG(INFO)<< "GPU board: " << remaining[i] << ":" << remaining[j]; + remaining.erase(remaining.begin() + j); + break; + } } +#endif // USE_CUDA } } } @@ -143,19 +157,26 @@ void DevicePair::compute(const vector devices, vector* pairs) { for (int i = 0; i < remaining.size(); ++i) { s << (i ? ", " : "") << remaining[i]; } - DLOG(INFO) << "GPUs paired by boards, remaining: " << s.str(); + DLOG(INFO)<< "GPUs paired by boards, remaining: " << s.str(); // Group by P2P accessibility remaining_depth = ceil(log2(remaining.size())); for (int d = 0; d < remaining_depth; ++d) { for (int i = 0; i < remaining.size(); ++i) { for (int j = i + 1; j < remaining.size(); ++j) { - int access; - CUDA_CHECK( - cudaDeviceCanAccessPeer(&access, remaining[i], remaining[j])); + int access = 0; + // Currently, P2P access only on CUDA + if (remaining[i]->backend() == BACKEND_CUDA + && remaining[j]->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + CUDA_CHECK( + cudaDeviceCanAccessPeer(&access, remaining[i]->id(), + remaining[j]->id())); +#endif // USE_CUDA + } if (access) { pairs->push_back(DevicePair(remaining[i], remaining[j])); - DLOG(INFO) << "P2P pair: " << remaining[i] << ":" << remaining[j]; + DLOG(INFO)<< "P2P pair: " << remaining[i] << ":" << remaining[j]; remaining.erase(remaining.begin() + j); break; } @@ -166,15 +187,15 @@ void DevicePair::compute(const vector devices, vector* pairs) { for (int i = 0; i < remaining.size(); ++i) { s << (i ? ", " : "") << remaining[i]; } - DLOG(INFO) << "GPUs paired by P2P access, remaining: " << s.str(); + DLOG(INFO)<< "GPUs paired by P2P access, remaining: " << s.str(); // Group remaining remaining_depth = ceil(log2(remaining.size())); for (int d = 0; d < remaining_depth; ++d) { for (int i = 0; i < remaining.size(); ++i) { pairs->push_back(DevicePair(remaining[i], remaining[i + 1])); - DLOG(INFO) << "Remaining pair: " << remaining[i] << ":" - << remaining[i + 1]; + DLOG(INFO)<< "Remaining pair: " << remaining[i] << ":" + << remaining[i + 1]; remaining.erase(remaining.begin() + i + 1); } } @@ -182,13 +203,14 @@ void DevicePair::compute(const vector devices, vector* pairs) { // Should only be the parent node remaining CHECK_EQ(remaining.size(), 1); - pairs->insert(pairs->begin(), DevicePair(-1, remaining[0])); + pairs->insert(pairs->begin(), + DevicePair(Caffe::Get().GetCPUDevice(), remaining[0])); CHECK(pairs->size() == devices.size()); for (int i = 0; i < pairs->size(); ++i) { - CHECK((*pairs)[i].parent() != (*pairs)[i].device()); + CHECK((*pairs)[i].get_parent() != (*pairs)[i].get_device()); for (int j = i + 1; j < pairs->size(); ++j) { - CHECK((*pairs)[i].device() != (*pairs)[j].device()); + CHECK((*pairs)[i].get_device() != (*pairs)[j].get_device()); } } #else @@ -201,13 +223,10 @@ void DevicePair::compute(const vector devices, vector* pairs) { template P2PSync::P2PSync(shared_ptr > root_solver, P2PSync* parent, const SolverParameter& param) - : GPUParams(root_solver, param.device_id()), - parent_(parent), - children_(), - queue_(), - initial_iter_(root_solver->iter()), - solver_() { + : GPUParams(root_solver, param.device_id()), parent_(parent), + children_(), queue_(), initial_iter_(root_solver->iter()), solver_() { #ifndef CPU_ONLY +#ifdef USE_CUDA int initial_device; CUDA_CHECK(cudaGetDevice(&initial_device)); const int self = param.device_id(); @@ -240,6 +259,7 @@ P2PSync::P2PSync(shared_ptr > root_solver, } CUDA_CHECK(cudaSetDevice(initial_device)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -248,6 +268,7 @@ P2PSync::P2PSync(shared_ptr > root_solver, template P2PSync::~P2PSync() { #ifndef CPU_ONLY +#ifdef USE_CUDA int initial_device; CUDA_CHECK(cudaGetDevice(&initial_device)); const int self = solver_->param().device_id(); @@ -264,7 +285,8 @@ P2PSync::~P2PSync() { } CUDA_CHECK(cudaSetDevice(initial_device)); -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY } template @@ -278,7 +300,8 @@ void P2PSync::InternalThreadEntry() { // everyone doesn't have the same seed. We seem to have some // solver instability if we have everyone with the same seed Caffe::set_random_seed( - solver_->param().random_seed() + solver_->param().device_id()); + solver_->param().random_seed() + solver_->param().device_id(), + solver_->get_device()); } solver_->Step(solver_->param().max_iter() - initial_iter_); } @@ -286,6 +309,7 @@ void P2PSync::InternalThreadEntry() { template void P2PSync::on_start() { #ifndef CPU_ONLY +#ifdef USE_CUDA #ifdef DEBUG int device; CUDA_CHECK(cudaGetDevice(&device)); @@ -313,17 +337,21 @@ void P2PSync::on_start() { CHECK(attributes.device == children_[i]->solver_->param().device_id()); #endif - CUDA_CHECK(cudaMemcpyAsync(dst, src, size_ * sizeof(Dtype), - cudaMemcpyDeviceToDevice, cudaStreamDefault)); + CUDA_CHECK( + cudaMemcpyAsync(dst, src, size_ * sizeof(Dtype), + cudaMemcpyDeviceToDevice, cudaStreamDefault)); CUDA_CHECK(cudaStreamSynchronize(cudaStreamDefault)); children_[i]->queue_.push(this); } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY } +// TODO: Rewrite this function for OpenCL template void P2PSync::on_gradients_ready() { #ifndef CPU_ONLY +#ifdef USE_CUDA #ifdef DEBUG int device; CUDA_CHECK(cudaGetDevice(&device)); @@ -376,17 +404,19 @@ void P2PSync::on_gradients_ready() { // for split batch, the root solver divides by number of solvers. caffe_gpu_scal(size_, Dtype(1.0 / Caffe::solver_count()), diff_); } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY } template -void P2PSync::run(const vector& gpus) { +void P2PSync::run(const vector& gpus) { // Pair devices for map-reduce synchronization vector pairs; DevicePair::compute(gpus, &pairs); ostringstream s; for (int i = 1; i < pairs.size(); ++i) { - s << (i == 1 ? "" : ", ") << pairs[i].parent() << ":" << pairs[i].device(); + s << (i == 1 ? "" : ", ") << pairs[i].get_parent() << ":" + << pairs[i].get_device(); } LOG(INFO)<< "GPUs pairs " << s.str(); @@ -402,13 +432,13 @@ void P2PSync::run(const vector& gpus) { P2PSync* sync = j == 0 ? this : syncs[j].get(); if (sync) { const SolverParameter& p = sync->solver()->param(); - if (p.device_id() == pairs[i].parent()) { + if (p.device_id() == pairs[i].get_parent()->list_id()) { parent = sync; } } } if (parent) { - param.set_device_id(pairs[i].device()); + param.set_device_id(pairs[i].get_device()->list_id()); syncs[i].reset(new P2PSync(solver_, parent, param)); parent->children_.push_back((P2PSync*) syncs[i].get()); } @@ -419,7 +449,7 @@ void P2PSync::run(const vector& gpus) { LOG(INFO)<< "Starting Optimization"; for (int i = 1; i < syncs.size(); ++i) { - syncs[i]->StartInternalThread(); + syncs[i]->StartInternalThread(solver_->get_device()); } // Run root solver on current thread diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index 6493a72d778..4c8c9b2dc06 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -15,10 +15,10 @@ message BlobProto { repeated double double_diff = 9 [packed = true]; // 4D dimensions -- deprecated. Use "shape" instead. - optional int32 num = 1 [default = 0]; - optional int32 channels = 2 [default = 0]; - optional int32 height = 3 [default = 0]; - optional int32 width = 4 [default = 0]; + optional int64 num = 1 [default = 0]; + optional int64 channels = 2 [default = 0]; + optional int64 height = 3 [default = 0]; + optional int64 width = 4 [default = 0]; } // The BlobProtoVector is simply a way to pass multiple blobproto instances @@ -28,12 +28,12 @@ message BlobProtoVector { } message Datum { - optional int32 channels = 1; - optional int32 height = 2; - optional int32 width = 3; + optional int64 channels = 1; + optional int64 height = 2; + optional int64 width = 3; // the actual image data, in bytes optional bytes data = 4; - optional int32 label = 5; + optional int64 label = 5; // Optionally, the datum could also hold float data. repeated float float_data = 6; // If true data contains an encoded image that need to be decoded @@ -50,7 +50,7 @@ message FillerParameter { optional float std = 6 [default = 1]; // the std value in Gaussian filler // The expected number of non-zero output weights for a given input in // Gaussian filler -- the default -1 means don't perform sparsification. - optional int32 sparse = 7 [default = -1]; + optional int64 sparse = 7 [default = -1]; // Normalize the filler variance by fan_in, fan_out, or their average. // Applies to 'xavier' and 'msra' fillers. enum VarianceNorm { @@ -67,13 +67,12 @@ message NetParameter { repeated string input = 3; // The shape of the input blobs. repeated BlobShape input_shape = 8; - - // 4D input dimensions -- deprecated. Use "shape" instead. + + // 4D input dimensions -- deprecated. Use "shape" instead // If specified, for each input blob there should be four // values specifying the num, channels, height and width of the input blob. // Thus, there should be a total of (4 * #input) numbers. - repeated int32 input_dim = 4; - + repeated int64 input_dim = 4; // Whether the network will force every layer to carry out backward operation. // If set False, then whether to carry out backward is determined // automatically according to the net structure and learning rates. @@ -136,10 +135,10 @@ message SolverParameter { repeated NetState test_state = 27; // The number of iterations for each test net. - repeated int32 test_iter = 3; + repeated int64 test_iter = 3; // The number of iterations between two testing phases. - optional int32 test_interval = 4 [default = 0]; + optional int64 test_interval = 4 [default = 0]; optional bool test_compute_loss = 19 [default = false]; // If true, run an initial test pass before the first iteration, // ensuring memory availability and printing the starting value of the loss. @@ -147,12 +146,12 @@ message SolverParameter { optional float base_lr = 5; // The base learning rate // the number of iterations between displaying info. If display = 0, no info // will be displayed. - optional int32 display = 6; + optional int64 display = 6; // Display the loss averaged over the last average_loss iterations - optional int32 average_loss = 33 [default = 1]; - optional int32 max_iter = 7; // the maximum number of iterations + optional int64 average_loss = 33 [default = 1]; + optional int64 max_iter = 7; // the maximum number of iterations // accumulate gradients over `iter_size` x `batch_size` instances - optional int32 iter_size = 36 [default = 1]; + optional int64 iter_size = 36 [default = 1]; // The learning rate decay policy. The currently implemented learning rate // policies are as follows: @@ -178,15 +177,15 @@ message SolverParameter { // controlled by weight_decay optional string regularization_type = 29 [default = "L2"]; // the stepsize for learning rate policy "step" - optional int32 stepsize = 13; + optional int64 stepsize = 13; // the stepsize for learning rate policy "multistep" - repeated int32 stepvalue = 34; + repeated int64 stepvalue = 34; // Set clip_gradients to >= 0 to clip parameter gradients to that L2 norm, // whenever their actual L2 norm is larger. optional float clip_gradients = 35 [default = -1]; - optional int32 snapshot = 14 [default = 0]; // The snapshot interval + optional int64 snapshot = 14 [default = 0]; // The snapshot interval optional string snapshot_prefix = 15; // The prefix for the snapshot. // whether to snapshot diff in the results or not. Snapshotting diff will help // debugging but the final protocol buffer size will be much larger. @@ -203,7 +202,7 @@ message SolverParameter { } optional SolverMode solver_mode = 17 [default = GPU]; // the device_id will that be used in GPU mode. Use device_id = 0 in default. - optional int32 device_id = 18 [default = 0]; + optional int64 device_id = 18 [default = 0]; // If non-negative, the seed with which the Solver will initialize the Caffe // random number generator -- useful for reproducible results. Otherwise, // (and by default) initialize using a seed derived from the system clock. @@ -211,7 +210,7 @@ message SolverParameter { // type of the solver optional string type = 40 [default = "SGD"]; - + // numerical stability for RMSProp, AdaGrad and AdaDelta and Adam optional float delta = 31 [default = 1e-8]; // parameters for the Adam solver @@ -227,7 +226,7 @@ message SolverParameter { // If false, don't save a snapshot after training finishes. optional bool snapshot_after_train = 28 [default = true]; - + // DEPRECATED: old solver enum types, use string instead enum SolverType { SGD = 0; @@ -243,10 +242,10 @@ message SolverParameter { // A message that stores the solver snapshots message SolverState { - optional int32 iter = 1; // The current iteration + optional int64 iter = 1; // The current iteration optional string learned_net = 2; // The file that stores the learned net. repeated BlobProto history = 3; // The history for sgd solvers - optional int32 current_step = 4 [default = 0]; // The current step for learning rate + optional int64 current_step = 4 [default = 0]; // The current step for learning rate } enum Phase { @@ -256,7 +255,7 @@ enum Phase { message NetState { optional Phase phase = 1 [default = TEST]; - optional int32 level = 2 [default = 0]; + optional int64 level = 2 [default = 0]; repeated string stage = 3; } @@ -267,8 +266,8 @@ message NetStateRule { // Set the minimum and/or maximum levels in which the layer should be used. // Leave undefined to meet the rule regardless of level. - optional int32 min_level = 2; - optional int32 max_level = 3; + optional int64 min_level = 2; + optional int64 max_level = 3; // Customizable sets of stages to include or exclude. // The net must have ALL of the specified stages and NONE of the specified @@ -340,6 +339,11 @@ message LayerParameter { // included/excluded. repeated NetStateRule include = 8; repeated NetStateRule exclude = 9; + + // Parameters for Greentea + optional int64 device = 95 [default = -1]; + // Parameters for Splitnet + optional int64 buffer = 96 [default = -1]; // Parameters for data pre-processing. optional TransformationParameter transform_param = 100; @@ -394,6 +398,8 @@ message LayerParameter { optional ThresholdParameter threshold_param = 128; optional TileParameter tile_param = 138; optional WindowDataParameter window_data_param = 129; + optional MergeCropParameter mergecrop_param = 143; + optional AffinityParameter affinity_param = 144; } // Message that stores parameters used to apply transformation @@ -406,7 +412,7 @@ message TransformationParameter { // Specify if we want to randomly mirror data. optional bool mirror = 2 [default = false]; // Specify if we would like to randomly crop an image. - optional uint32 crop_size = 3 [default = 0]; + optional uint64 crop_size = 3 [default = 0]; // mean_file and mean_value cannot be specified at the same time optional string mean_file = 4; // if specified can be repeated once (would substract it from all the channels) @@ -422,7 +428,7 @@ message TransformationParameter { // Message that stores parameters shared by loss layers message LossParameter { // If specified, ignore instances with the given label. - optional int32 ignore_label = 1; + optional int64 ignore_label = 1; // How to normalize the loss for loss layers that aggregate across batches, // spatial dimensions, or other dimensions. Currently only implemented in // SoftmaxWithLoss layer. @@ -453,39 +459,39 @@ message AccuracyParameter { // When computing accuracy, count as correct by comparing the true label to // the top k scoring classes. By default, only compare to the top scoring // class (i.e. argmax). - optional uint32 top_k = 1 [default = 1]; - + optional uint64 top_k = 1 [default = 1]; + // The "label" axis of the prediction blob, whose argmax corresponds to the // predicted label -- may be negative to index from the end (e.g., -1 for the // last axis). For example, if axis == 1 and the predictions are // (N x C x H x W), the label blob is expected to contain N*H*W ground truth // labels with integer values in {0, 1, ..., C-1}. - optional int32 axis = 2 [default = 1]; - + optional int64 axis = 2 [default = 1]; + // If specified, ignore instances with the given label. - optional int32 ignore_label = 3; + optional int64 ignore_label = 3; } message ArgMaxParameter { // If true produce pairs (argmax, maxval) optional bool out_max_val = 1 [default = false]; - optional uint32 top_k = 2 [default = 1]; + optional uint64 top_k = 2 [default = 1]; // The axis along which to maximise -- may be negative to index from the // end (e.g., -1 for the last axis). // By default ArgMaxLayer maximizes over the flattened trailing dimensions // for each index of the first / num dimension. - optional int32 axis = 3; + optional int64 axis = 3; } message ConcatParameter { // The axis along which to concatenate -- may be negative to index from the // end (e.g., -1 for the last axis). Other axes must have the // same dimension for all the bottom blobs. - // By default, ConcatLayer concatenates blobs along the "channels" axis (1). - optional int32 axis = 2 [default = 1]; - + // By default, ConcatLayer concatenates blobs along the "channels" axis ( + optional int64 axis = 2 [default = 1]; + // DEPRECATED: alias for "axis" -- does not support negative indexing. - optional uint32 concat_dim = 1 [default = 1]; + optional uint64 concat_dim = 1 [default = 1]; } message BatchNormParameter { @@ -514,7 +520,7 @@ message BiasParameter { // (axis == 3 == -1) 60 // Furthermore, bottom[1] may have the empty shape (regardless of the value of // "axis") -- a scalar bias. - optional int32 axis = 1 [default = 1]; + optional int64 axis = 1 [default = 1]; // (num_axes is ignored unless just one bottom is given and the bias is // a learned parameter of the layer. Otherwise, num_axes is determined by the @@ -522,7 +528,7 @@ message BiasParameter { // The number of axes of the input (bottom[0]) covered by the bias // parameter, or -1 to cover all axes of bottom[0] starting from `axis`. // Set num_axes := 0, to add a zero-axis Blob: a scalar. - optional int32 num_axes = 2 [default = 1]; + optional int64 num_axes = 2 [default = 1]; // (filler is ignored unless just one bottom is given and the bias is // a learned parameter of the layer.) @@ -545,29 +551,29 @@ message ContrastiveLossParameter { } message ConvolutionParameter { - optional uint32 num_output = 1; // The number of outputs for the layer + optional uint64 num_output = 1; // The number of outputs for the layer optional bool bias_term = 2 [default = true]; // whether to have bias terms // Pad, kernel size, and stride are all given as a single value for equal // dimensions in all spatial dimensions, or once per spatial dimension. - repeated uint32 pad = 3; // The padding size; defaults to 0 - repeated uint32 kernel_size = 4; // The kernel size - repeated uint32 stride = 6; // The stride; defaults to 1 + repeated uint64 pad = 3; // The padding size; defaults to 0 + repeated uint64 kernel_size = 4; // The kernel size + repeated uint64 stride = 6; // The stride; defaults to 1 // Factor used to dilate the kernel, (implicitly) zero-filling the resulting // holes. (Kernel dilation is sometimes referred to by its use in the // algorithme à trous from Holschneider et al. 1987.) - repeated uint32 dilation = 18; // The dilation; defaults to 1 + repeated uint64 dilation = 18; // The dilation; defaults to 1 // For 2D convolution only, the *_h and *_w versions may also be used to // specify both spatial dimensions. - optional uint32 pad_h = 9 [default = 0]; // The padding height (2D only) - optional uint32 pad_w = 10 [default = 0]; // The padding width (2D only) - optional uint32 kernel_h = 11; // The kernel height (2D only) - optional uint32 kernel_w = 12; // The kernel width (2D only) - optional uint32 stride_h = 13; // The stride height (2D only) - optional uint32 stride_w = 14; // The stride width (2D only) + optional uint64 pad_h = 9 [default = 0]; // The padding height (2D only) + optional uint64 pad_w = 10 [default = 0]; // The padding width (2D only) + optional uint64 kernel_h = 11; // The kernel height (2D only) + optional uint64 kernel_w = 12; // The kernel width (2D only) + optional uint64 stride_h = 13; // The stride height (2D only) + optional uint64 stride_w = 14; // The stride width (2D only) - optional uint32 group = 5 [default = 1]; // The group size for group conv + optional uint64 group = 5 [default = 1]; // The group size for group conv optional FillerParameter weight_filler = 7; // The filler for the weight optional FillerParameter bias_filler = 8; // The filler for the bias @@ -577,7 +583,7 @@ message ConvolutionParameter { CUDNN = 2; } optional Engine engine = 15 [default = DEFAULT]; - + // The axis to interpret as "channels" when performing convolution. // Preceding dimensions are treated as independent inputs; // succeeding dimensions are treated as "spatial". @@ -587,7 +593,7 @@ message ConvolutionParameter { // With (N, C, D, H, W) inputs, and axis == 1, we perform // N independent 3D convolutions, sliding (C/g)-channels // filters across the spatial axes (D, H, W) of the input. - optional int32 axis = 16 [default = 1]; + optional int64 axis = 16 [default = 1]; // Whether to force use of the general ND convolution, even if a specific // implementation for blobs of the appropriate number of spatial dimensions @@ -605,13 +611,13 @@ message DataParameter { // Specify the data source. optional string source = 1; // Specify the batch size. - optional uint32 batch_size = 4; + optional uint64 batch_size = 4; // The rand_skip variable is for the data layer to skip a few data points // to avoid all asynchronous sgd clients to start at the same point. The skip // point would be set as rand_skip * rand(0,1). Note that rand_skip should not // be larger than the number of keys in the database. // DEPRECATED. Each solver accesses a different subset of the database. - optional uint32 rand_skip = 7 [default = 0]; + optional uint64 rand_skip = 7 [default = 0]; optional DB backend = 8 [default = LEVELDB]; // DEPRECATED. See TransformationParameter. For data pre-processing, we can do // simple scaling and subtracting the data mean, if provided. Note that the @@ -620,7 +626,7 @@ message DataParameter { optional string mean_file = 3; // DEPRECATED. See TransformationParameter. Specify if we would like to randomly // crop an image. - optional uint32 crop_size = 5 [default = 0]; + optional uint64 crop_size = 5 [default = 0]; // DEPRECATED. See TransformationParameter. Specify if we want to randomly mirror // data. optional bool mirror = 6 [default = false]; @@ -628,7 +634,7 @@ message DataParameter { optional bool force_encoded_color = 9 [default = false]; // Prefetch queue (Number of batches to prefetch to host memory, increase if // data access bandwidth varies). - optional uint32 prefetch = 10 [default = 4]; + optional uint64 prefetch = 10 [default = 4]; } message DropoutParameter { @@ -639,19 +645,20 @@ message DropoutParameter { // (or constant) data generated by "Fillers" (see "message FillerParameter"). message DummyDataParameter { // This layer produces N >= 1 top blobs. DummyDataParameter must specify 1 or N - // shape fields, and 0, 1 or N data_fillers. + // num, N channels, N height, and N width fields, and must specify 0, 1 or N + // data_fillers. // // If 0 data_fillers are specified, ConstantFiller with a value of 0 is used. // If 1 data_filler is specified, it is applied to all top blobs. If N are // specified, the ith is applied to the ith top blob. repeated FillerParameter data_filler = 1; repeated BlobShape shape = 6; - + // 4D dimensions -- deprecated. Use "shape" instead. - repeated uint32 num = 2; - repeated uint32 channels = 3; - repeated uint32 height = 4; - repeated uint32 width = 5; + repeated uint64 num = 2; + repeated uint64 channels = 3; + repeated uint64 height = 4; + repeated uint64 width = 5; } message EltwiseParameter { @@ -678,11 +685,11 @@ message ELUParameter { // Message that stores parameters used by EmbedLayer message EmbedParameter { - optional uint32 num_output = 1; // The number of outputs for the layer + optional uint64 num_output = 1; // The number of outputs for the layer // The input is given as integers to be interpreted as one-hot // vector indices with dimension num_input. Hence num_input should be // 1 greater than the maximum possible input value. - optional uint32 input_dim = 2; + optional uint64 input_dim = 2; optional bool bias_term = 3 [default = true]; // Whether to use a bias term optional FillerParameter weight_filler = 4; // The filler for the weight @@ -704,12 +711,12 @@ message ExpParameter { message FlattenParameter { // The first axis to flatten: all preceding axes are retained in the output. // May be negative to index from the end (e.g., -1 for the last axis). - optional int32 axis = 1 [default = 1]; + optional int64 axis = 1 [default = 1]; // The last axis to flatten: all following axes are retained in the output. // May be negative to index from the end (e.g., the default -1 for the last // axis). - optional int32 end_axis = 2 [default = -1]; + optional int64 end_axis = 2 [default = -1]; } // Message that stores parameters used by HDF5DataLayer @@ -717,12 +724,12 @@ message HDF5DataParameter { // Specify the data source. optional string source = 1; // Specify the batch size. - optional uint32 batch_size = 2; - + optional uint64 batch_size = 2; + // Specify whether to shuffle the data. // If shuffle == true, the ordering of the HDF5 files is shuffled, - // and the ordering of data within any given HDF5 file is shuffled, - // but data between different files are not interleaved; all of a file's + // and the ordering of data within any given HDF5 file is shuffl + // but data between different files are not interleaved; all of a file' // data are output (in a random order) before moving onto another file. optional bool shuffle = 3 [default = false]; } @@ -744,17 +751,17 @@ message ImageDataParameter { // Specify the data source. optional string source = 1; // Specify the batch size. - optional uint32 batch_size = 4 [default = 1]; + optional uint64 batch_size = 4 [default = 1]; // The rand_skip variable is for the data layer to skip a few data points // to avoid all asynchronous sgd clients to start at the same point. The skip // point would be set as rand_skip * rand(0,1). Note that rand_skip should not // be larger than the number of keys in the database. - optional uint32 rand_skip = 7 [default = 0]; + optional uint64 rand_skip = 7 [default = 0]; // Whether or not ImageLayer should shuffle the list of files at every epoch. optional bool shuffle = 8 [default = false]; // It will also resize images if new_height or new_width are not zero. - optional uint32 new_height = 9 [default = 0]; - optional uint32 new_width = 10 [default = 0]; + optional uint64 new_height = 9 [default = 0]; + optional uint64 new_width = 10 [default = 0]; // Specify if the images are color or gray optional bool is_color = 11 [default = true]; // DEPRECATED. See TransformationParameter. For data pre-processing, we can do @@ -764,7 +771,7 @@ message ImageDataParameter { optional string mean_file = 3; // DEPRECATED. See TransformationParameter. Specify if we would like to randomly // crop an image. - optional uint32 crop_size = 5 [default = 0]; + optional uint64 crop_size = 5 [default = 0]; // DEPRECATED. See TransformationParameter. Specify if we want to randomly mirror // data. optional bool mirror = 6 [default = false]; @@ -777,15 +784,15 @@ message InfogainLossParameter { } message InnerProductParameter { - optional uint32 num_output = 1; // The number of outputs for the layer + optional uint64 num_output = 1; // The number of outputs for the layer optional bool bias_term = 2 [default = true]; // whether to have bias terms optional FillerParameter weight_filler = 3; // The filler for the weight optional FillerParameter bias_filler = 4; // The filler for the bias - + // The first axis to be lumped into a single inner product computation; // all preceding axes are retained in the output. // May be negative to index from the end (e.g., -1 for the last axis). - optional int32 axis = 5 [default = 1]; + optional int64 axis = 5 [default = 1]; } // Message that stores parameters used by LogLayer @@ -800,7 +807,7 @@ message LogParameter { // Message that stores parameters used by LRNLayer message LRNParameter { - optional uint32 local_size = 1 [default = 5]; + optional uint64 local_size = 1 [default = 5]; optional float alpha = 2 [default = 1.]; optional float beta = 3 [default = 0.75]; enum NormRegion { @@ -818,10 +825,14 @@ message LRNParameter { } message MemoryDataParameter { - optional uint32 batch_size = 1; - optional uint32 channels = 2; - optional uint32 height = 3; - optional uint32 width = 4; + optional uint64 batch_size = 1; + optional uint64 channels = 2; + optional uint64 height = 3; + optional uint64 width = 4; + // Dim works in the following order (examples): + // batch_size, channels, height, width + // batch_size, channels, Z, Y, X + repeated uint64 dim = 5; } message MVNParameter { @@ -844,15 +855,15 @@ message PoolingParameter { optional PoolMethod pool = 1 [default = MAX]; // The pooling method // Pad, kernel size, and stride are all given as a single value for equal // dimensions in height and width or as Y, X pairs. - optional uint32 pad = 4 [default = 0]; // The padding size (equal in Y, X) - optional uint32 pad_h = 9 [default = 0]; // The padding height - optional uint32 pad_w = 10 [default = 0]; // The padding width - optional uint32 kernel_size = 2; // The kernel size (square) - optional uint32 kernel_h = 5; // The kernel height - optional uint32 kernel_w = 6; // The kernel width - optional uint32 stride = 3 [default = 1]; // The stride (equal in Y, X) - optional uint32 stride_h = 7; // The stride height - optional uint32 stride_w = 8; // The stride width + repeated uint64 pad = 4; // The padding size (equal in Y, X), default 0 + optional uint64 pad_h = 9 [default = 0]; // The padding height + optional uint64 pad_w = 10 [default = 0]; // The padding width + repeated uint64 kernel_size = 2; // The kernel size (square) + optional uint64 kernel_h = 5; // The kernel height + optional uint64 kernel_w = 6; // The kernel width + repeated uint64 stride = 3; // The stride (equal in Y, X), default 1 + optional uint64 stride_h = 7; // The stride height + optional uint64 stride_w = 8; // The stride width enum Engine { DEFAULT = 0; CAFFE = 1; @@ -862,6 +873,8 @@ message PoolingParameter { // If global_pooling then it will pool over the size of the bottom by doing // kernel_h = bottom->height and kernel_w = bottom->width optional bool global_pooling = 12 [default = false]; + repeated uint64 dilation = 13; // The kernel stride, default 1 + optional int64 axis = 16 [default = 1]; } message PowerParameter { @@ -909,7 +922,7 @@ message ReductionParameter { // If axis == 0 (the default), the output Blob always has the empty shape // (count 1), performing reduction across the entire input -- // often useful for creating new loss functions. - optional int32 axis = 2 [default = 0]; + optional int64 axis = 2 [default = 0]; optional float coeff = 3 [default = 1.0]; // coefficient for output } @@ -990,8 +1003,8 @@ message ReshapeParameter { // reshape_param { shape { dim: 2 dim: 1 dim: 8 } } // reshape_param { shape { dim: 1 } axis: 1 num_axes: 0 } // - optional int32 axis = 2 [default = 0]; - optional int32 num_axes = 3 [default = -1]; + optional int64 axis = 2 [default = 0]; + optional int64 num_axes = 3 [default = -1]; } message ScaleParameter { @@ -1008,7 +1021,7 @@ message ScaleParameter { // (axis == 3 == -1) 60 // Furthermore, bottom[1] may have the empty shape (regardless of the value of // "axis") -- a scalar multiplier. - optional int32 axis = 1 [default = 1]; + optional int64 axis = 1 [default = 1]; // (num_axes is ignored unless just one bottom is given and the scale is // a learned parameter of the layer. Otherwise, num_axes is determined by the @@ -1016,7 +1029,7 @@ message ScaleParameter { // The number of axes of the input (bottom[0]) covered by the scale // parameter, or -1 to cover all axes of bottom[0] starting from `axis`. // Set num_axes := 0, to multiply with a zero-axis Blob: a scalar. - optional int32 num_axes = 2 [default = 1]; + optional int64 num_axes = 2 [default = 1]; // (filler is ignored unless just one bottom is given and the scale is // a learned parameter of the layer.) @@ -1044,11 +1057,11 @@ message SliceParameter { // The axis along which to slice -- may be negative to index from the end // (e.g., -1 for the last axis). // By default, SliceLayer concatenates blobs along the "channels" axis (1). - optional int32 axis = 3 [default = 1]; - repeated uint32 slice_point = 2; - + optional int64 axis = 3 [default = 1]; + repeated uint64 slice_point = 2; + // DEPRECATED: alias for "axis" -- does not support negative indexing. - optional uint32 slice_dim = 1 [default = 1]; + optional uint64 slice_dim = 1 [default = 1]; } // Message that stores parameters used by SoftmaxLayer, SoftmaxWithLossLayer @@ -1059,11 +1072,11 @@ message SoftmaxParameter { CUDNN = 2; } optional Engine engine = 1 [default = DEFAULT]; - - // The axis along which to perform the softmax -- may be negative to index + + // The axis along which to perform the softmax -- may be negative to i // from the end (e.g., -1 for the last axis). // Any other axes will be evaluated as independent softmaxes. - optional int32 axis = 2 [default = 1]; + optional int64 axis = 2 [default = 1]; } message TanHParameter { @@ -1078,10 +1091,10 @@ message TanHParameter { // Message that stores parameters used by TileLayer message TileParameter { // The index of the axis to tile. - optional int32 axis = 1 [default = 1]; + optional int64 axis = 1 [default = 1]; // The number of copies (tiles) of the blob to output. - optional int32 tiles = 2; + optional int64 tiles = 2; } // Message that stores parameters used by ThresholdLayer @@ -1098,9 +1111,9 @@ message WindowDataParameter { optional float scale = 2 [default = 1]; optional string mean_file = 3; // Specify the batch size. - optional uint32 batch_size = 4; + optional uint64 batch_size = 4; // Specify if we would like to randomly crop an image. - optional uint32 crop_size = 5 [default = 0]; + optional uint64 crop_size = 5 [default = 0]; // Specify if we want to randomly mirror data. optional bool mirror = 6 [default = false]; // Foreground (object) overlap threshold @@ -1111,7 +1124,7 @@ message WindowDataParameter { optional float fg_fraction = 9 [default = 0.25]; // Amount of contextual padding to add around a window // (used only by the window_data_layer) - optional uint32 context_pad = 10 [default = 0]; + optional uint64 context_pad = 10 [default = 0]; // Mode for cropping out a detection window // warp: cropped window is warped to a fixed size and aspect ratio // square: the tightest square around the window is cropped @@ -1128,7 +1141,7 @@ message SPPParameter { AVE = 1; STOCHASTIC = 2; } - optional uint32 pyramid_height = 1; + optional uint64 pyramid_height = 1; optional PoolMethod pool = 2 [default = MAX]; // The pooling method enum Engine { DEFAULT = 0; @@ -1229,6 +1242,7 @@ message V1LayerParameter { optional TransformationParameter transform_param = 36; optional LossParameter loss_param = 42; optional V0LayerParameter layer = 1; + optional AffinityParameter affinity_param = 43; } // DEPRECATED: V0LayerParameter is the old way of specifying layer parameters @@ -1238,15 +1252,15 @@ message V0LayerParameter { optional string type = 2; // the string to specify the layer type // Parameters to specify layers with inner products. - optional uint32 num_output = 3; // The number of outputs for the layer + optional uint64 num_output = 3; // The number of outputs for the layer optional bool biasterm = 4 [default = true]; // whether to have bias terms optional FillerParameter weight_filler = 5; // The filler for the weight optional FillerParameter bias_filler = 6; // The filler for the bias - optional uint32 pad = 7 [default = 0]; // The padding size - optional uint32 kernelsize = 8; // The kernel size - optional uint32 group = 9 [default = 1]; // The group size for group conv - optional uint32 stride = 10 [default = 1]; // The stride + optional uint64 pad = 7 [default = 0]; // The padding size + optional uint64 kernelsize = 8; // The kernel size + optional uint64 group = 9 [default = 1]; // The group size for group conv + optional uint64 stride = 10 [default = 1]; // The stride enum PoolMethod { MAX = 0; AVE = 1; @@ -1255,7 +1269,7 @@ message V0LayerParameter { optional PoolMethod pool = 11 [default = MAX]; // The pooling method optional float dropout_ratio = 12 [default = 0.5]; // dropout ratio - optional uint32 local_size = 13 [default = 5]; // for local response norm + optional uint64 local_size = 13 [default = 5]; // for local response norm optional float alpha = 14 [default = 1.]; // for local response norm optional float beta = 15 [default = 0.75]; // for local response norm optional float k = 22 [default = 1.]; @@ -1268,9 +1282,9 @@ message V0LayerParameter { optional float scale = 17 [default = 1]; optional string meanfile = 18; // For data layers, specify the batch size. - optional uint32 batchsize = 19; + optional uint64 batchsize = 19; // For data layers, specify if we would like to randomly crop an image. - optional uint32 cropsize = 20 [default = 0]; + optional uint64 cropsize = 20 [default = 0]; // For data layers, specify if we want to randomly mirror data. optional bool mirror = 21 [default = false]; @@ -1286,7 +1300,7 @@ message V0LayerParameter { // to avoid all asynchronous sgd clients to start at the same point. The skip // point would be set as rand_skip * rand(0,1). Note that rand_skip should not // be larger than the number of keys in the database. - optional uint32 rand_skip = 53 [default = 0]; + optional uint64 rand_skip = 53 [default = 0]; // Fields related to detection (det_*) // foreground (object) overlap threshold @@ -1300,7 +1314,7 @@ message V0LayerParameter { // Amount of contextual padding to add around a window // (used only by the window_data_layer) - optional uint32 det_context_pad = 58 [default = 0]; + optional uint64 det_context_pad = 58 [default = 0]; // Mode for cropping out a detection window // warp: cropped window is warped to a fixed size and aspect ratio @@ -1308,10 +1322,10 @@ message V0LayerParameter { optional string det_crop_mode = 59 [default = "warp"]; // For ReshapeLayer, one needs to specify the new dimensions. - optional int32 new_num = 60 [default = 0]; - optional int32 new_channels = 61 [default = 0]; - optional int32 new_height = 62 [default = 0]; - optional int32 new_width = 63 [default = 0]; + optional int64 new_num = 60 [default = 0]; + optional int64 new_channels = 61 [default = 0]; + optional int64 new_height = 62 [default = 0]; + optional int64 new_width = 63 [default = 0]; // Whether or not ImageLayer should shuffle the list of files at every epoch. // It will also resize images if new_height or new_width are not zero. @@ -1320,7 +1334,7 @@ message V0LayerParameter { // For ConcatLayer, one needs to specify the dimension for concatenation, and // the other dimensions must be the same for all the bottom blobs. // By default it will concatenate blobs along the channels dimension. - optional uint32 concat_dim = 65 [default = 1]; + optional uint64 concat_dim = 65 [default = 1]; optional HDF5OutputParameter hdf5_output_param = 1001; } @@ -1334,3 +1348,16 @@ message PReLUParameter { // Whether or not slope paramters are shared across channels. optional bool channel_shared = 2 [default = false]; } + +message AffinityParameter { + // Offset parameter to change the channel to use for creating an affinity graph + // Defined once per bottom blob + repeated int64 offset = 1; +} + +message MergeCropParameter { + // Forward and backward enable/disable + // Defined once per bottom blob + repeated bool forward = 1; + repeated bool backward = 2; +} diff --git a/src/caffe/solver.cpp b/src/caffe/solver.cpp index a5ccf9c71b1..8307e3d7c25 100644 --- a/src/caffe/solver.cpp +++ b/src/caffe/solver.cpp @@ -1,12 +1,19 @@ #include +#include #include #include +#include "hdf5.h" +#include "hdf5_hl.h" + +#include "caffe/net.hpp" +#include "caffe/proto/caffe.pb.h" #include "caffe/solver.hpp" #include "caffe/util/format.hpp" #include "caffe/util/hdf5.hpp" #include "caffe/util/io.hpp" +#include "caffe/util/math_functions.hpp" #include "caffe/util/upgrade_proto.hpp" namespace caffe { @@ -25,23 +32,25 @@ SolverAction::Enum Solver::GetRequestedAction() { return SolverAction::NONE; } -template +template Solver::Solver(const SolverParameter& param, const Solver* root_solver) - : net_(), callbacks_(), root_solver_(root_solver), - requested_early_exit_(false) { + : net_(), + device_(Caffe::GetDefaultDevice()), callbacks_(), + root_solver_(root_solver), requested_early_exit_(false) { Init(param); } -template +template Solver::Solver(const string& param_file, const Solver* root_solver) - : net_(), callbacks_(), root_solver_(root_solver), - requested_early_exit_(false) { + : net_(), + device_(Caffe::GetDefaultDevice()), callbacks_(), + root_solver_(root_solver), requested_early_exit_(false) { SolverParameter param; ReadSolverParamsFromTextFileOrDie(param_file, ¶m); Init(param); } -template +template void Solver::Init(const SolverParameter& param) { CHECK(Caffe::root_solver() || root_solver_) << "root_solver_ needs to be set for all non-root solvers"; @@ -51,7 +60,7 @@ void Solver::Init(const SolverParameter& param) { CHECK_GE(param_.average_loss(), 1) << "average_loss should be non-negative."; CheckSnapshotWritePermissions(); if (Caffe::root_solver() && param_.random_seed() >= 0) { - Caffe::set_random_seed(param_.random_seed()); + Caffe::set_random_seed(param_.random_seed(), device_); } // Scaffolding code InitTrainNet(); @@ -63,15 +72,26 @@ void Solver::Init(const SolverParameter& param) { current_step_ = 0; } -template + +template +void Solver::UpdateSolverParams(const SolverParameter& param) { + param_ = param; +} + +template +SolverParameter Solver::GetSolverParams() { + return param_; +} + +template void Solver::InitTrainNet() { - const int num_train_nets = param_.has_net() + param_.has_net_param() + - param_.has_train_net() + param_.has_train_net_param(); + const int_tp num_train_nets = param_.has_net() + param_.has_net_param() + + param_.has_train_net() + param_.has_train_net_param(); const string& field_names = "net, net_param, train_net, train_net_param"; - CHECK_GE(num_train_nets, 1) << "SolverParameter must specify a train net " - << "using one of these fields: " << field_names; - CHECK_LE(num_train_nets, 1) << "SolverParameter must not contain more than " - << "one of these fields specifying a train_net: " << field_names; + CHECK_GE(num_train_nets, 1)<< "SolverParameter must specify a train net " + << "using one of these fields: " << field_names; + CHECK_LE(num_train_nets, 1)<< "SolverParameter must not contain more than " + << "one of these fields specifying a train_net: " << field_names; NetParameter net_param; if (param_.has_train_net_param()) { LOG_IF(INFO, Caffe::root_solver()) @@ -102,37 +122,40 @@ void Solver::InitTrainNet() { net_state.MergeFrom(param_.train_state()); net_param.mutable_state()->CopyFrom(net_state); if (Caffe::root_solver()) { - net_.reset(new Net(net_param)); + net_.reset(new Net(net_param, this->device_)); } else { - net_.reset(new Net(net_param, root_solver_->net_.get())); + net_.reset( + new Net(net_param, this->device_, root_solver_->net_.get())); } } -template +template void Solver::InitTestNets() { CHECK(Caffe::root_solver()); const bool has_net_param = param_.has_net_param(); const bool has_net_file = param_.has_net(); - const int num_generic_nets = has_net_param + has_net_file; + const int_tp num_generic_nets = has_net_param + has_net_file; CHECK_LE(num_generic_nets, 1) - << "Both net_param and net_file may not be specified."; - const int num_test_net_params = param_.test_net_param_size(); - const int num_test_net_files = param_.test_net_size(); - const int num_test_nets = num_test_net_params + num_test_net_files; + << "Both net_param and net_file may not be specified."; + const int_tp num_test_net_params = param_.test_net_param_size(); + const int_tp num_test_net_files = param_.test_net_size(); + const int_tp num_test_nets = num_test_net_params + num_test_net_files; if (num_generic_nets) { - CHECK_GE(param_.test_iter_size(), num_test_nets) - << "test_iter must be specified for each test network."; + CHECK_GE(param_.test_iter_size(), num_test_nets) + << "test_iter must be specified for each test network."; } else { - CHECK_EQ(param_.test_iter_size(), num_test_nets) - << "test_iter must be specified for each test network."; + CHECK_EQ(param_.test_iter_size(), num_test_nets) + << "test_iter must be specified for each test network."; } // If we have a generic net (specified by net or net_param, rather than // test_net or test_net_param), we may have an unlimited number of actual // test networks -- the actual number is given by the number of remaining // test_iters after any test nets specified by test_net_param and/or test_net // are evaluated. - const int num_generic_net_instances = param_.test_iter_size() - num_test_nets; - const int num_test_net_instances = num_test_nets + num_generic_net_instances; + const int_tp num_generic_net_instances = param_.test_iter_size() + - num_test_nets; + const int_tp num_test_net_instances = num_test_nets + + num_generic_net_instances; if (param_.test_state_size()) { CHECK_EQ(param_.test_state_size(), num_test_net_instances) << "test_state must be unspecified or specified once per test net."; @@ -140,33 +163,33 @@ void Solver::InitTestNets() { if (num_test_net_instances) { CHECK_GT(param_.test_interval(), 0); } - int test_net_id = 0; + int_tp test_net_id = 0; vector sources(num_test_net_instances); vector net_params(num_test_net_instances); - for (int i = 0; i < num_test_net_params; ++i, ++test_net_id) { - sources[test_net_id] = "test_net_param"; - net_params[test_net_id].CopyFrom(param_.test_net_param(i)); + for (int_tp i = 0; i < num_test_net_params; ++i, ++test_net_id) { + sources[test_net_id] = "test_net_param"; + net_params[test_net_id].CopyFrom(param_.test_net_param(i)); } - for (int i = 0; i < num_test_net_files; ++i, ++test_net_id) { - sources[test_net_id] = "test_net file: " + param_.test_net(i); - ReadNetParamsFromTextFileOrDie(param_.test_net(i), - &net_params[test_net_id]); + for (int_tp i = 0; i < num_test_net_files; ++i, ++test_net_id) { + sources[test_net_id] = "test_net file: " + param_.test_net(i); + ReadNetParamsFromTextFileOrDie(param_.test_net(i), + &net_params[test_net_id]); } - const int remaining_test_nets = param_.test_iter_size() - test_net_id; + const int_tp remaining_test_nets = param_.test_iter_size() - test_net_id; if (has_net_param) { - for (int i = 0; i < remaining_test_nets; ++i, ++test_net_id) { + for (int_tp i = 0; i < remaining_test_nets; ++i, ++test_net_id) { sources[test_net_id] = "net_param"; net_params[test_net_id].CopyFrom(param_.net_param()); } } if (has_net_file) { - for (int i = 0; i < remaining_test_nets; ++i, ++test_net_id) { + for (int_tp i = 0; i < remaining_test_nets; ++i, ++test_net_id) { sources[test_net_id] = "net file: " + param_.net(); ReadNetParamsFromTextFileOrDie(param_.net(), &net_params[test_net_id]); } } test_nets_.resize(num_test_net_instances); - for (int i = 0; i < num_test_net_instances; ++i) { + for (int_tp i = 0; i < num_test_net_instances; ++i) { // Set the correct NetState. We start with the solver defaults (lowest // precedence); then, merge in any NetState specified by the net_param // itself; finally, merge in any NetState specified by the test_state @@ -181,21 +204,21 @@ void Solver::InitTestNets() { LOG(INFO) << "Creating test net (#" << i << ") specified by " << sources[i]; if (Caffe::root_solver()) { - test_nets_[i].reset(new Net(net_params[i])); + test_nets_[i].reset(new Net(net_params[i], this->device_)); } else { - test_nets_[i].reset(new Net(net_params[i], + test_nets_[i].reset(new Net(net_params[i], this->device_, root_solver_->test_nets_[i].get())); } test_nets_[i]->set_debug_info(param_.debug_info()); } } -template -void Solver::Step(int iters) { +template +Dtype Solver::Step(int_tp iters) { vector*> bottom_vec; - const int start_iter = iter_; - const int stop_iter = iter_ + iters; - int average_loss = this->param_.average_loss(); + const int_tp start_iter = iter_; + const int_tp stop_iter = iter_ + iters; + int_tp average_loss = this->param_.average_loss(); losses_.clear(); smoothed_loss_ = 0; @@ -212,14 +235,14 @@ void Solver::Step(int iters) { } } - for (int i = 0; i < callbacks_.size(); ++i) { + for (int_tp i = 0; i < callbacks_.size(); ++i) { callbacks_[i]->on_start(); } const bool display = param_.display() && iter_ % param_.display() == 0; net_->set_debug_info(display && param_.debug_info()); // accumulate the loss and gradient Dtype loss = 0; - for (int i = 0; i < param_.iter_size(); ++i) { + for (int_tp i = 0; i < param_.iter_size(); ++i) { loss += net_->ForwardBackward(bottom_vec); } loss /= param_.iter_size(); @@ -229,18 +252,18 @@ void Solver::Step(int iters) { LOG_IF(INFO, Caffe::root_solver()) << "Iteration " << iter_ << ", loss = " << smoothed_loss_; const vector*>& result = net_->output_blobs(); - int score_index = 0; - for (int j = 0; j < result.size(); ++j) { + int_tp score_index = 0; + for (int_tp j = 0; j < result.size(); ++j) { const Dtype* result_vec = result[j]->cpu_data(); const string& output_name = - net_->blob_names()[net_->output_blob_indices()[j]]; + net_->blob_names()[net_->output_blob_indices()[j]]; const Dtype loss_weight = - net_->blob_loss_weights()[net_->output_blob_indices()[j]]; - for (int k = 0; k < result[j]->count(); ++k) { + net_->blob_loss_weights()[net_->output_blob_indices()[j]]; + for (int_tp k = 0; k < result[j]->count(); ++k) { ostringstream loss_msg_stream; if (loss_weight) { loss_msg_stream << " (* " << loss_weight - << " = " << loss_weight * result_vec[k] << " loss)"; + << " = " << loss_weight * result_vec[k] << " loss)"; } LOG_IF(INFO, Caffe::root_solver()) << " Train net output #" << score_index++ << ": " << output_name << " = " @@ -248,7 +271,7 @@ void Solver::Step(int iters) { } } } - for (int i = 0; i < callbacks_.size(); ++i) { + for (int_tp i = 0; i < callbacks_.size(); ++i) { callbacks_[i]->on_gradients_ready(); } ApplyUpdate(); @@ -272,9 +295,10 @@ void Solver::Step(int iters) { break; } } + return smoothed_loss_; } -template +template void Solver::Solve(const char* resume_file) { CHECK(Caffe::root_solver()); LOG(INFO) << "Solving " << net_->name(); @@ -323,28 +347,29 @@ void Solver::Solve(const char* resume_file) { LOG(INFO) << "Optimization Done."; } + template void Solver::TestAll() { - for (int test_net_id = 0; + for (int_tp test_net_id = 0; test_net_id < test_nets_.size() && !requested_early_exit_; ++test_net_id) { Test(test_net_id); } } -template -void Solver::Test(const int test_net_id) { +template +void Solver::Test(const int_tp test_net_id) { CHECK(Caffe::root_solver()); LOG(INFO) << "Iteration " << iter_ << ", Testing net (#" << test_net_id << ")"; CHECK_NOTNULL(test_nets_[test_net_id].get())-> - ShareTrainedLayersWith(net_.get()); + ShareTrainedLayersWith(net_.get()); vector test_score; - vector test_score_output_id; + vector test_score_output_id; vector*> bottom_vec; const shared_ptr >& test_net = test_nets_[test_net_id]; Dtype loss = 0; - for (int i = 0; i < param_.test_iter(test_net_id); ++i) { + for (int_tp i = 0; i < param_.test_iter(test_net_id); ++i) { SolverAction::Enum request = GetRequestedAction(); // Check to see if stoppage of testing/training has been requested. while (request != SolverAction::NONE) { @@ -362,23 +387,23 @@ void Solver::Test(const int test_net_id) { Dtype iter_loss; const vector*>& result = - test_net->Forward(bottom_vec, &iter_loss); + test_net->Forward(bottom_vec, &iter_loss); if (param_.test_compute_loss()) { loss += iter_loss; } if (i == 0) { - for (int j = 0; j < result.size(); ++j) { + for (int_tp j = 0; j < result.size(); ++j) { const Dtype* result_vec = result[j]->cpu_data(); - for (int k = 0; k < result[j]->count(); ++k) { + for (int_tp k = 0; k < result[j]->count(); ++k) { test_score.push_back(result_vec[k]); test_score_output_id.push_back(j); } } } else { - int idx = 0; - for (int j = 0; j < result.size(); ++j) { + int_tp idx = 0; + for (int_tp j = 0; j < result.size(); ++j) { const Dtype* result_vec = result[j]->cpu_data(); - for (int k = 0; k < result[j]->count(); ++k) { + for (int_tp k = 0; k < result[j]->count(); ++k) { test_score[idx++] += result_vec[k]; } } @@ -392,16 +417,16 @@ void Solver::Test(const int test_net_id) { loss /= param_.test_iter(test_net_id); LOG(INFO) << "Test loss: " << loss; } - for (int i = 0; i < test_score.size(); ++i) { - const int output_blob_index = - test_net->output_blob_indices()[test_score_output_id[i]]; + for (int_tp i = 0; i < test_score.size(); ++i) { + const int_tp output_blob_index = + test_net->output_blob_indices()[test_score_output_id[i]]; const string& output_name = test_net->blob_names()[output_blob_index]; const Dtype loss_weight = test_net->blob_loss_weights()[output_blob_index]; ostringstream loss_msg_stream; const Dtype mean_score = test_score[i] / param_.test_iter(test_net_id); if (loss_weight) { loss_msg_stream << " (* " << loss_weight - << " = " << loss_weight * mean_score << " loss)"; + << " = " << loss_weight * mean_score << " loss)"; } LOG(INFO) << " Test net output #" << i << ": " << output_name << " = " << mean_score << loss_msg_stream.str(); @@ -481,14 +506,14 @@ void Solver::Restore(const char* state_file) { } template -void Solver::UpdateSmoothedLoss(Dtype loss, int start_iter, - int average_loss) { +void Solver::UpdateSmoothedLoss(Dtype loss, int_tp start_iter, + int_tp average_loss) { if (losses_.size() < average_loss) { losses_.push_back(loss); - int size = losses_.size(); + int_tp size = losses_.size(); smoothed_loss_ = (smoothed_loss_ * (size - 1) + loss) / size; } else { - int idx = (iter_ - start_iter) % average_loss; + int_tp idx = (iter_ - start_iter) % average_loss; smoothed_loss_ += (loss - losses_[idx]) / average_loss; losses_[idx] = loss; } @@ -497,3 +522,4 @@ void Solver::UpdateSmoothedLoss(Dtype loss, int start_iter, INSTANTIATE_CLASS(Solver); } // namespace caffe + diff --git a/src/caffe/solvers/adadelta_solver.cpp b/src/caffe/solvers/adadelta_solver.cpp index fd30f19acac..8b9b8f05134 100644 --- a/src/caffe/solvers/adadelta_solver.cpp +++ b/src/caffe/solvers/adadelta_solver.cpp @@ -10,16 +10,16 @@ void AdaDeltaSolver::AdaDeltaPreSolve() { // SGDSolver::PreSolve const vector*>& net_params = this->net_->learnable_params(); for (int i = 0; i < net_params.size(); ++i) { - const vector& shape = net_params[i]->shape(); + const vector& shape = net_params[i]->shape(); this->history_.push_back( - shared_ptr >(new Blob(shape))); + shared_ptr >(new Blob(shape, this->device_))); } } #ifndef CPU_ONLY -template -void adadelta_update_gpu(int N, Dtype* g, Dtype* h, Dtype* h2, Dtype momentum, - Dtype delta, Dtype local_rate); +template +void adadelta_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, Dtype* h2, + Dtype momentum, Dtype delta, Dtype local_rate); #endif template @@ -91,7 +91,7 @@ void AdaDeltaSolver::ComputeUpdateValue(int param_id, Dtype rate) { } case Caffe::GPU: { #ifndef CPU_ONLY - adadelta_update_gpu(net_params[param_id]->count(), + adadelta_update_gpu(this->device_, net_params[param_id]->count(), net_params[param_id]->mutable_gpu_diff(), this->history_[param_id]->mutable_gpu_data(), this->history_[update_history_offset + param_id]->mutable_gpu_data(), diff --git a/src/caffe/solvers/adadelta_solver.cu b/src/caffe/solvers/adadelta_solver.cu index 6c94585b89e..97daecf41a9 100644 --- a/src/caffe/solvers/adadelta_solver.cu +++ b/src/caffe/solvers/adadelta_solver.cu @@ -1,10 +1,16 @@ +#include "caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif namespace caffe { +#ifdef USE_CUDA template -__global__ void AdaDeltaUpdate(int N, Dtype* g, Dtype* h, Dtype* h2, +__global__ void AdaDeltaUpdate(int_tp N, Dtype* g, Dtype* h, Dtype* h2, Dtype momentum, Dtype delta, Dtype local_rate) { CUDA_KERNEL_LOOP(i, N) { float gi = g[i]; @@ -14,17 +20,36 @@ __global__ void AdaDeltaUpdate(int N, Dtype* g, Dtype* h, Dtype* h2, g[i] = local_rate * gi; } } +#endif + template -void adadelta_update_gpu(int N, Dtype* g, Dtype* h, Dtype* h2, Dtype momentum, - Dtype delta, Dtype local_rate) { - AdaDeltaUpdate // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - N, g, h, h2, momentum, delta, local_rate); - CUDA_POST_KERNEL_CHECK; +void adadelta_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, Dtype* h2, + Dtype momentum, Dtype delta, Dtype local_rate) { + if (dev->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + AdaDeltaUpdate // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS) ( + N, g, h, h2, momentum, delta, local_rate); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dev->id()); + viennacl::ocl::program &program = dev->program(); + viennacl::ocl::kernel &oclk_ada_delta_update = program.get_kernel( + CL_KERNEL_SELECT("ada_delta_update")); + viennacl::ocl::enqueue( + oclk_ada_delta_update(N, WrapHandle((cl_mem) g, &ctx), + WrapHandle((cl_mem) h, &ctx), + WrapHandle((cl_mem) h2, &ctx), momentum, delta, + local_rate), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template void adadelta_update_gpu(int , float*, float*, float*, - float, float, float); -template void adadelta_update_gpu(int, double*, double*, double*, - double, double, double); +template void adadelta_update_gpu(device*, int_tp, float*, float*, + float*, float, float, float); +template void adadelta_update_gpu(device*, int_tp, double*, double*, + double*, double, double, double); } // namespace caffe diff --git a/src/caffe/solvers/adagrad_solver.cpp b/src/caffe/solvers/adagrad_solver.cpp index e78eadca141..543863bee0f 100644 --- a/src/caffe/solvers/adagrad_solver.cpp +++ b/src/caffe/solvers/adagrad_solver.cpp @@ -5,9 +5,9 @@ namespace caffe { #ifndef CPU_ONLY -template -void adagrad_update_gpu(int N, Dtype* g, Dtype* h, Dtype delta, - Dtype local_rate); +template +void adagrad_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, Dtype delta, + Dtype local_rate); #endif template @@ -18,51 +18,50 @@ void AdaGradSolver::ComputeUpdateValue(int param_id, Dtype rate) { Dtype delta = this->param_.delta(); Dtype local_rate = rate * net_params_lr[param_id]; switch (Caffe::mode()) { - case Caffe::CPU: { - // compute square of gradient in update - caffe_powx(net_params[param_id]->count(), - net_params[param_id]->cpu_diff(), Dtype(2), - this->update_[param_id]->mutable_cpu_data()); + case Caffe::CPU: { + // compute square of gradient in update + caffe_powx(net_params[param_id]->count(), + net_params[param_id]->cpu_diff(), Dtype(2), + this->update_[param_id]->mutable_cpu_data()); - // update history - caffe_add(net_params[param_id]->count(), - this->update_[param_id]->cpu_data(), - this->history_[param_id]->cpu_data(), - this->history_[param_id]->mutable_cpu_data()); + // update history + caffe_add(net_params[param_id]->count(), + this->update_[param_id]->cpu_data(), + this->history_[param_id]->cpu_data(), + this->history_[param_id]->mutable_cpu_data()); - // prepare update - caffe_powx(net_params[param_id]->count(), - this->history_[param_id]->cpu_data(), Dtype(0.5), - this->update_[param_id]->mutable_cpu_data()); + // prepare update + caffe_powx(net_params[param_id]->count(), + this->history_[param_id]->cpu_data(), Dtype(0.5), + this->update_[param_id]->mutable_cpu_data()); - caffe_add_scalar(net_params[param_id]->count(), - delta, this->update_[param_id]->mutable_cpu_data()); + caffe_add_scalar(net_params[param_id]->count(), delta, + this->update_[param_id]->mutable_cpu_data()); - caffe_div(net_params[param_id]->count(), - net_params[param_id]->cpu_diff(), - this->update_[param_id]->cpu_data(), - this->update_[param_id]->mutable_cpu_data()); + caffe_div(net_params[param_id]->count(), net_params[param_id]->cpu_diff(), + this->update_[param_id]->cpu_data(), + this->update_[param_id]->mutable_cpu_data()); - // scale and copy - caffe_cpu_axpby(net_params[param_id]->count(), local_rate, - this->update_[param_id]->cpu_data(), Dtype(0), - net_params[param_id]->mutable_cpu_diff()); - break; - } - case Caffe::GPU: { + // scale and copy + caffe_cpu_axpby(net_params[param_id]->count(), local_rate, + this->update_[param_id]->cpu_data(), Dtype(0), + net_params[param_id]->mutable_cpu_diff()); + break; + } + case Caffe::GPU: { #ifndef CPU_ONLY - adagrad_update_gpu(net_params[param_id]->count(), + adagrad_update_gpu(this->device_, net_params[param_id]->count(), net_params[param_id]->mutable_gpu_diff(), this->history_[param_id]->mutable_gpu_data(), delta, local_rate); #else - NO_GPU; + NO_GPU; #endif - break; - } - default: - LOG(FATAL) << "Unknown caffe mode: " << Caffe::mode(); + break; + } + default: + LOG(FATAL)<< "Unknown caffe mode: " << Caffe::mode(); + } } -} INSTANTIATE_CLASS(AdaGradSolver); REGISTER_SOLVER_CLASS(AdaGrad); diff --git a/src/caffe/solvers/adagrad_solver.cu b/src/caffe/solvers/adagrad_solver.cu index adefd554bbd..347285807c7 100644 --- a/src/caffe/solvers/adagrad_solver.cu +++ b/src/caffe/solvers/adagrad_solver.cu @@ -1,8 +1,14 @@ +#include "caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif namespace caffe { +#ifdef USE_CUDA template __global__ void AdaGradUpdate(int N, Dtype* g, Dtype* h, Dtype delta, Dtype local_rate) { @@ -12,15 +18,35 @@ __global__ void AdaGradUpdate(int N, Dtype* g, Dtype* h, Dtype delta, g[i] = local_rate * gi / (sqrt(hi) + delta); } } +#endif + template -void adagrad_update_gpu(int N, Dtype* g, Dtype* h, Dtype delta, +void adagrad_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, Dtype delta, Dtype local_rate) { - AdaGradUpdate // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - N, g, h, delta, local_rate); - CUDA_POST_KERNEL_CHECK; + if (dev->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + AdaGradUpdate // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS) ( + N, g, h, delta, local_rate); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dev->id()); + viennacl::ocl::program &program = dev->program(); + viennacl::ocl::kernel &oclk_ada_grad_update = program.get_kernel( + CL_KERNEL_SELECT("ada_grad_update")); + viennacl::ocl::enqueue( + oclk_ada_grad_update(N, WrapHandle((cl_mem) g, &ctx), + WrapHandle((cl_mem) h, &ctx), delta, local_rate), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template void adagrad_update_gpu(int, float*, float*, float, float); -template void adagrad_update_gpu(int, double*, double*, double, double); + +template void adagrad_update_gpu(device*, int_tp, float*, float*, float, + float); +template void adagrad_update_gpu(device*, int_tp, double*, double*, + double, double); } // namespace caffe diff --git a/src/caffe/solvers/adam_solver.cpp b/src/caffe/solvers/adam_solver.cpp index 4a91f00bd49..651fc0177e5 100644 --- a/src/caffe/solvers/adam_solver.cpp +++ b/src/caffe/solvers/adam_solver.cpp @@ -9,17 +9,18 @@ void AdamSolver::AdamPreSolve() { // Add the extra history entries for Adam after those from // SGDSolver::PreSolve const vector*>& net_params = this->net_->learnable_params(); - for (int i = 0; i < net_params.size(); ++i) { - const vector& shape = net_params[i]->shape(); + for (uint_tp i = 0; i < net_params.size(); ++i) { + const vector& shape = net_params[i]->shape(); this->history_.push_back( - shared_ptr >(new Blob(shape))); + shared_ptr >(new Blob(shape, this->device_))); } } #ifndef CPU_ONLY -template -void adam_update_gpu(int N, Dtype* g, Dtype* m, Dtype* v, Dtype beta1, - Dtype beta2, Dtype eps_hat, Dtype corrected_local_rate); +template +void adam_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* m, Dtype* v, + Dtype beta1, Dtype beta2, Dtype eps_hat, + Dtype corrected_local_rate); #endif template @@ -31,15 +32,15 @@ void AdamSolver::ComputeUpdateValue(int param_id, Dtype rate) { const Dtype beta2 = this->param_.momentum2(); // we create aliases for convenience - size_t update_history_offset = net_params.size(); + uint_tp update_history_offset = net_params.size(); Blob* val_m = this->history_[param_id].get(); Blob* val_v = this->history_[param_id + update_history_offset].get(); Blob* val_t = this->temp_[param_id].get(); - const int t = this->iter_ + 1; + const uint_tp t = this->iter_ + 1; const Dtype correction = std::sqrt(Dtype(1) - pow(beta2, t)) / (Dtype(1.) - pow(beta1, t)); - const int N = net_params[param_id]->count(); + const uint_tp N = net_params[param_id]->count(); const Dtype eps_hat = this->param_.delta(); switch (Caffe::mode()) { @@ -75,9 +76,10 @@ void AdamSolver::ComputeUpdateValue(int param_id, Dtype rate) { } case Caffe::GPU: { #ifndef CPU_ONLY - adam_update_gpu(N, net_params[param_id]->mutable_gpu_diff(), - val_m->mutable_gpu_data(), val_v->mutable_gpu_data(), beta1, beta2, - eps_hat, local_rate*correction); + adam_update_gpu(this->device_, N, + net_params[param_id]->mutable_gpu_diff(), + val_m->mutable_gpu_data(), val_v->mutable_gpu_data(), + beta1, beta2, eps_hat, local_rate * correction); #else NO_GPU; #endif diff --git a/src/caffe/solvers/adam_solver.cu b/src/caffe/solvers/adam_solver.cu index 917ae100246..5fc35918ad5 100644 --- a/src/caffe/solvers/adam_solver.cu +++ b/src/caffe/solvers/adam_solver.cu @@ -1,8 +1,14 @@ +#include "caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif namespace caffe { +#ifdef USE_CUDA template __global__ void AdamUpdate(int N, Dtype* g, Dtype* m, Dtype* v, Dtype beta1, Dtype beta2, Dtype eps_hat, Dtype corrected_local_rate) { @@ -13,17 +19,40 @@ __global__ void AdamUpdate(int N, Dtype* g, Dtype* m, Dtype* v, g[i] = corrected_local_rate * mi / (sqrt(vi) + eps_hat); } } -template -void adam_update_gpu(int N, Dtype* g, Dtype* m, Dtype* v, Dtype beta1, - Dtype beta2, Dtype eps_hat, Dtype corrected_local_rate) { - AdamUpdate // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - N, g, m, v, beta1, beta2, eps_hat, corrected_local_rate); - CUDA_POST_KERNEL_CHECK; +#endif + + +template +void adam_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* m, Dtype* v, + Dtype beta1, Dtype beta2, Dtype eps_hat, + Dtype corrected_local_rate) { + if (dev->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + AdamUpdate // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS) ( + N, g, m, v, beta1, beta2, eps_hat, corrected_local_rate); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dev->id()); + viennacl::ocl::program &program = dev->program(); + viennacl::ocl::kernel &oclk_adam_update = program.get_kernel( + CL_KERNEL_SELECT("adam_update")); + viennacl::ocl::enqueue( + oclk_adam_update(N, WrapHandle((cl_mem) g, &ctx), + WrapHandle((cl_mem) m, &ctx), + WrapHandle((cl_mem) v, &ctx), beta1, beta2, eps_hat, + corrected_local_rate), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template void adam_update_gpu(int, float*, float*, float*, - float, float, float, float); -template void adam_update_gpu(int, double*, double*, double*, - double, double, double, double); + + +template void adam_update_gpu(device*, int_tp, float*, float*, float*, + float, float, float, float); +template void adam_update_gpu(device*, int_tp, double*, double*, + double*, double, double, double, double); } // namespace caffe diff --git a/src/caffe/solvers/nesterov_solver.cpp b/src/caffe/solvers/nesterov_solver.cpp index 23ab2d4369a..13cb6f5af72 100644 --- a/src/caffe/solvers/nesterov_solver.cpp +++ b/src/caffe/solvers/nesterov_solver.cpp @@ -5,9 +5,9 @@ namespace caffe { #ifndef CPU_ONLY -template -void nesterov_update_gpu(int N, Dtype* g, Dtype* h, Dtype momentum, - Dtype local_rate); +template +void nesterov_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, + Dtype momentum, Dtype local_rate); #endif template @@ -18,41 +18,42 @@ void NesterovSolver::ComputeUpdateValue(int param_id, Dtype rate) { Dtype momentum = this->param_.momentum(); Dtype local_rate = rate * net_params_lr[param_id]; switch (Caffe::mode()) { - case Caffe::CPU: { - // save history momentum for stepping back - caffe_copy(net_params[param_id]->count(), - this->history_[param_id]->cpu_data(), - this->update_[param_id]->mutable_cpu_data()); - - // update history - caffe_cpu_axpby(net_params[param_id]->count(), local_rate, - net_params[param_id]->cpu_diff(), momentum, - this->history_[param_id]->mutable_cpu_data()); - - // compute update: step back then over step - caffe_cpu_axpby(net_params[param_id]->count(), Dtype(1) + momentum, - this->history_[param_id]->cpu_data(), -momentum, - this->update_[param_id]->mutable_cpu_data()); - - // copy - caffe_copy(net_params[param_id]->count(), - this->update_[param_id]->cpu_data(), - net_params[param_id]->mutable_cpu_diff()); - break; - } - case Caffe::GPU: { + case Caffe::CPU: { + // save history momentum for stepping back + caffe_cpu_copy(net_params[param_id]->count(), + this->history_[param_id]->cpu_data(), + this->update_[param_id]->mutable_cpu_data()); + + // update history + caffe_cpu_axpby(net_params[param_id]->count(), local_rate, + net_params[param_id]->cpu_diff(), momentum, + this->history_[param_id]->mutable_cpu_data()); + + // compute update: step back then over step + caffe_cpu_axpby(net_params[param_id]->count(), Dtype(1) + momentum, + this->history_[param_id]->cpu_data(), -momentum, + this->update_[param_id]->mutable_cpu_data()); + + // copy + caffe_cpu_copy(net_params[param_id]->count(), + this->update_[param_id]->cpu_data(), + net_params[param_id]->mutable_cpu_diff()); + break; + } + case Caffe::GPU: { #ifndef CPU_ONLY - nesterov_update_gpu(net_params[param_id]->count(), + nesterov_update_gpu(this->device_, net_params[param_id]->count(), net_params[param_id]->mutable_gpu_diff(), this->history_[param_id]->mutable_gpu_data(), momentum, local_rate); #else - NO_GPU; + NO_GPU; #endif - break; - } - default: - LOG(FATAL) << "Unknown caffe mode: " << Caffe::mode(); + break; + } + default: { + LOG(FATAL)<< "Unknown caffe mode: " << Caffe::mode(); + } } } diff --git a/src/caffe/solvers/nesterov_solver.cu b/src/caffe/solvers/nesterov_solver.cu index 57a456b8252..9a0d491a59e 100644 --- a/src/caffe/solvers/nesterov_solver.cu +++ b/src/caffe/solvers/nesterov_solver.cu @@ -1,8 +1,14 @@ +#include "caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif namespace caffe { +#ifdef USE_CUDA template __global__ void NesterovUpdate(int N, Dtype* g, Dtype* h, Dtype momentum, Dtype local_rate) { @@ -12,16 +18,37 @@ __global__ void NesterovUpdate(int N, Dtype* g, Dtype* h, g[i] = (1+momentum) * hi_new - momentum * hi; } } -template -void nesterov_update_gpu(int N, Dtype* g, Dtype* h, Dtype momentum, - Dtype local_rate) { - NesterovUpdate // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - N, g, h, momentum, local_rate); - CUDA_POST_KERNEL_CHECK; +#endif + +template +void nesterov_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, + Dtype momentum, Dtype local_rate) { + if (dev->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + NesterovUpdate // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS) ( + N, g, h, momentum, local_rate); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dev->id()); + viennacl::ocl::program &program = dev->program(); + viennacl::ocl::kernel &oclk_nesterov_update = program.get_kernel( + CL_KERNEL_SELECT("nesterov_update")); + viennacl::ocl::enqueue( + oclk_nesterov_update(N, WrapHandle((cl_mem) g, &ctx), + WrapHandle((cl_mem) h, &ctx), momentum, + local_rate), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template void nesterov_update_gpu(int, float*, float*, float, float); -template void nesterov_update_gpu(int, double*, double*, double, - double); + +template void nesterov_update_gpu(device*, int_tp, float*, float*, float, + float); +template void nesterov_update_gpu(device*, int_tp, double*, double*, + double, double); + } // namespace caffe diff --git a/src/caffe/solvers/rmsprop_solver.cpp b/src/caffe/solvers/rmsprop_solver.cpp index 3251ee423a7..46dcaf4443e 100644 --- a/src/caffe/solvers/rmsprop_solver.cpp +++ b/src/caffe/solvers/rmsprop_solver.cpp @@ -5,9 +5,9 @@ namespace caffe { #ifndef CPU_ONLY -template -void rmsprop_update_gpu(int N, Dtype* g, Dtype* h, Dtype rms_decay, - Dtype delta, Dtype local_rate); +template +void rmsprop_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, + Dtype rms_decay, Dtype delta, Dtype local_rate); #endif template @@ -51,7 +51,7 @@ void RMSPropSolver::ComputeUpdateValue(int param_id, Dtype rate) { break; case Caffe::GPU: #ifndef CPU_ONLY - rmsprop_update_gpu(net_params[param_id]->count(), + rmsprop_update_gpu(this->device_, net_params[param_id]->count(), net_params[param_id]->mutable_gpu_diff(), this->history_[param_id]->mutable_gpu_data(), rms_decay, delta, local_rate); diff --git a/src/caffe/solvers/rmsprop_solver.cu b/src/caffe/solvers/rmsprop_solver.cu index c5ffd329d77..dc62df571f0 100644 --- a/src/caffe/solvers/rmsprop_solver.cu +++ b/src/caffe/solvers/rmsprop_solver.cu @@ -1,28 +1,54 @@ +#include "caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif namespace caffe { -template -__global__ void RMSPropUpdate(int N, Dtype* g, Dtype* h, - Dtype rms_decay, Dtype delta, Dtype local_rate) { +#ifdef USE_CUDA +template +__global__ void RMSPropUpdate(int_tp N, Dtype* g, Dtype* h, Dtype rms_decay, + Dtype delta, Dtype local_rate) { CUDA_KERNEL_LOOP(i, N) { float gi = g[i]; - float hi = h[i] = rms_decay*h[i] + (1-rms_decay)*gi*gi; + float hi = h[i] = rms_decay * h[i] + (1 - rms_decay) * gi * gi; g[i] = local_rate * g[i] / (sqrt(hi) + delta); } } +#endif + template -void rmsprop_update_gpu(int N, Dtype* g, Dtype* h, Dtype rms_decay, - Dtype delta, Dtype local_rate) { - RMSPropUpdate // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - N, g, h, rms_decay, delta, local_rate); - CUDA_POST_KERNEL_CHECK; +void rmsprop_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, + Dtype rms_decay, Dtype delta, Dtype local_rate) { + if (dev->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + RMSPropUpdate // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( + N, g, h, rms_decay, delta, local_rate); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dev->id()); + viennacl::ocl::program &program = dev->program(); + viennacl::ocl::kernel &oclk_rms_prop_update = program.get_kernel( + CL_KERNEL_SELECT("rms_prop_update")); + viennacl::ocl::enqueue( + oclk_rms_prop_update(N, WrapHandle((cl_mem) g, &ctx), + WrapHandle((cl_mem) h, &ctx), + rms_decay, delta, + local_rate), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template void rmsprop_update_gpu(int, float*, float*, float, float, - float); -template void rmsprop_update_gpu(int, double*, double*, double, double, - double); + +template void rmsprop_update_gpu(device*, int_tp, float*, float*, float, + float, float); +template void rmsprop_update_gpu(device*, int_tp, double*, double*, + double, double, double); } // namespace caffe diff --git a/src/caffe/solvers/sgd_solver.cpp b/src/caffe/solvers/sgd_solver.cpp index f30f316d1a0..86dfa2b3ebe 100644 --- a/src/caffe/solvers/sgd_solver.cpp +++ b/src/caffe/solvers/sgd_solver.cpp @@ -23,7 +23,7 @@ namespace caffe { // // where base_lr, max_iter, gamma, step, stepvalue and power are defined // in the solver parameter protocol buffer, and iter is the current iteration. -template +template Dtype SGDSolver::GetLearningRate() { Dtype rate; const string& lr_policy = this->param_.lr_policy(); @@ -31,23 +31,23 @@ Dtype SGDSolver::GetLearningRate() { rate = this->param_.base_lr(); } else if (lr_policy == "step") { this->current_step_ = this->iter_ / this->param_.stepsize(); - rate = this->param_.base_lr() * - pow(this->param_.gamma(), this->current_step_); + rate = this->param_.base_lr() + * pow(this->param_.gamma(), this->current_step_); } else if (lr_policy == "exp") { rate = this->param_.base_lr() * pow(this->param_.gamma(), this->iter_); } else if (lr_policy == "inv") { - rate = this->param_.base_lr() * - pow(Dtype(1) + this->param_.gamma() * this->iter_, - - this->param_.power()); + rate = this->param_.base_lr() + * pow(Dtype(1) + this->param_.gamma() * this->iter_, + -this->param_.power()); } else if (lr_policy == "multistep") { - if (this->current_step_ < this->param_.stepvalue_size() && - this->iter_ >= this->param_.stepvalue(this->current_step_)) { + if (this->current_step_ < this->param_.stepvalue_size() + && this->iter_ >= this->param_.stepvalue(this->current_step_)) { this->current_step_++; - LOG(INFO) << "MultiStep Status: Iteration " << + LOG(INFO)<< "MultiStep Status: Iteration " << this->iter_ << ", step = " << this->current_step_; } rate = this->param_.base_lr() * - pow(this->param_.gamma(), this->current_step_); + pow(this->param_.gamma(), this->current_step_); } else if (lr_policy == "poly") { rate = this->param_.base_lr() * pow(Dtype(1.) - (Dtype(this->iter_) / Dtype(this->param_.max_iter())), @@ -55,58 +55,64 @@ Dtype SGDSolver::GetLearningRate() { } else if (lr_policy == "sigmoid") { rate = this->param_.base_lr() * (Dtype(1.) / (Dtype(1.) + exp(-this->param_.gamma() * (Dtype(this->iter_) - - Dtype(this->param_.stepsize()))))); + Dtype(this->param_.stepsize()))))); } else { LOG(FATAL) << "Unknown learning rate policy: " << lr_policy; } return rate; } -template +template void SGDSolver::PreSolve() { // Initialize the history const vector*>& net_params = this->net_->learnable_params(); history_.clear(); update_.clear(); temp_.clear(); - for (int i = 0; i < net_params.size(); ++i) { - const vector& shape = net_params[i]->shape(); - history_.push_back(shared_ptr >(new Blob(shape))); - update_.push_back(shared_ptr >(new Blob(shape))); - temp_.push_back(shared_ptr >(new Blob(shape))); + for (uint_tp i = 0; i < net_params.size(); ++i) { + const vector& shape = net_params[i]->shape(); + history_.push_back( + shared_ptr>( + new Blob(shape, this->device_))); + update_.push_back( + shared_ptr>( + new Blob(shape, this->device_))); + temp_.push_back( + shared_ptr>( + new Blob(shape, this->device_))); } } -template +template void SGDSolver::ClipGradients() { const Dtype clip_gradients = this->param_.clip_gradients(); if (clip_gradients < 0) { return; } const vector*>& net_params = this->net_->learnable_params(); Dtype sumsq_diff = 0; - for (int i = 0; i < net_params.size(); ++i) { + for (uint_tp i = 0; i < net_params.size(); ++i) { sumsq_diff += net_params[i]->sumsq_diff(); } const Dtype l2norm_diff = std::sqrt(sumsq_diff); if (l2norm_diff > clip_gradients) { Dtype scale_factor = clip_gradients / l2norm_diff; - LOG(INFO) << "Gradient clipping: scaling down gradients (L2 norm " - << l2norm_diff << " > " << clip_gradients << ") " - << "by scale factor " << scale_factor; - for (int i = 0; i < net_params.size(); ++i) { + LOG(INFO)<< "Gradient clipping: scaling down gradients (L2 norm " + << l2norm_diff << " > " << clip_gradients << ") " + << "by scale factor " << scale_factor; + for (uint_tp i = 0; i < net_params.size(); ++i) { net_params[i]->scale_diff(scale_factor); } } } -template +template void SGDSolver::ApplyUpdate() { CHECK(Caffe::root_solver()); Dtype rate = GetLearningRate(); if (this->param_.display() && this->iter_ % this->param_.display() == 0) { - LOG(INFO) << "Iteration " << this->iter_ << ", lr = " << rate; + LOG(INFO)<< "Iteration " << this->iter_ << ", lr = " << rate; } ClipGradients(); - for (int param_id = 0; param_id < this->net_->learnable_params().size(); + for (uint_tp param_id = 0; param_id < this->net_->learnable_params().size(); ++param_id) { Normalize(param_id); Regularize(param_id); @@ -115,33 +121,46 @@ void SGDSolver::ApplyUpdate() { this->net_->Update(); } -template +template void SGDSolver::Normalize(int param_id) { - if (this->param_.iter_size() == 1) { return; } + if (this->param_.iter_size() == 1) { + return; + } // Scale gradient to counterbalance accumulation. const vector*>& net_params = this->net_->learnable_params(); const Dtype accum_normalization = Dtype(1.) / this->param_.iter_size(); switch (Caffe::mode()) { - case Caffe::CPU: { - caffe_scal(net_params[param_id]->count(), accum_normalization, - net_params[param_id]->mutable_cpu_diff()); - break; - } - case Caffe::GPU: { + case Caffe::CPU: { + caffe_scal(net_params[param_id]->count(), accum_normalization, + net_params[param_id]->mutable_cpu_diff()); + break; + } + case Caffe::GPU: { #ifndef CPU_ONLY - caffe_gpu_scal(net_params[param_id]->count(), accum_normalization, - net_params[param_id]->mutable_gpu_diff()); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_scal(net_params[param_id]->count(), accum_normalization, + net_params[param_id]->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_scal(this->device_->id(), + net_params[param_id]->count(), accum_normalization, + (cl_mem) (net_params[param_id]->mutable_gpu_diff()), + 0); +#endif // USE_GREENTEA + } #else - NO_GPU; + NO_GPU; #endif - break; - } - default: - LOG(FATAL) << "Unknown caffe mode: " << Caffe::mode(); + break; + } + default: + LOG(FATAL)<< "Unknown caffe mode: " << Caffe::mode(); + } } -} -template +template void SGDSolver::Regularize(int param_id) { const vector*>& net_params = this->net_->learnable_params(); const vector& net_params_weight_decay = @@ -150,63 +169,93 @@ void SGDSolver::Regularize(int param_id) { string regularization_type = this->param_.regularization_type(); Dtype local_decay = weight_decay * net_params_weight_decay[param_id]; switch (Caffe::mode()) { - case Caffe::CPU: { - if (local_decay) { - if (regularization_type == "L2") { - // add weight decay - caffe_axpy(net_params[param_id]->count(), - local_decay, - net_params[param_id]->cpu_data(), - net_params[param_id]->mutable_cpu_diff()); - } else if (regularization_type == "L1") { - caffe_cpu_sign(net_params[param_id]->count(), - net_params[param_id]->cpu_data(), - temp_[param_id]->mutable_cpu_data()); - caffe_axpy(net_params[param_id]->count(), - local_decay, - temp_[param_id]->cpu_data(), - net_params[param_id]->mutable_cpu_diff()); - } else { - LOG(FATAL) << "Unknown regularization type: " << regularization_type; + case Caffe::CPU: { + if (local_decay) { + if (regularization_type == "L2") { + // add weight decay + caffe_axpy(net_params[param_id]->count(), local_decay, + net_params[param_id]->cpu_data(), + net_params[param_id]->mutable_cpu_diff()); + } else if (regularization_type == "L1") { + caffe_cpu_sign(net_params[param_id]->count(), + net_params[param_id]->cpu_data(), + temp_[param_id]->mutable_cpu_data()); + caffe_axpy(net_params[param_id]->count(), local_decay, + temp_[param_id]->cpu_data(), + net_params[param_id]->mutable_cpu_diff()); + } else { + LOG(FATAL)<< "Unknown regularization type: " << regularization_type; + } } + break; } - break; - } - case Caffe::GPU: { + case Caffe::GPU: { #ifndef CPU_ONLY - if (local_decay) { - if (regularization_type == "L2") { - // add weight decay - caffe_gpu_axpy(net_params[param_id]->count(), - local_decay, - net_params[param_id]->gpu_data(), - net_params[param_id]->mutable_gpu_diff()); - } else if (regularization_type == "L1") { - caffe_gpu_sign(net_params[param_id]->count(), - net_params[param_id]->gpu_data(), - temp_[param_id]->mutable_gpu_data()); - caffe_gpu_axpy(net_params[param_id]->count(), - local_decay, - temp_[param_id]->gpu_data(), - net_params[param_id]->mutable_gpu_diff()); + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + if (local_decay) { + if (regularization_type == "L2") { + // add weight decay + caffe_gpu_axpy(net_params[param_id]->count(), + local_decay, + net_params[param_id]->gpu_data(), + net_params[param_id]->mutable_gpu_diff()); + } else if (regularization_type == "L1") { + caffe_gpu_sign(net_params[param_id]->count(), + net_params[param_id]->gpu_data(), + temp_[param_id]->mutable_gpu_data()); + caffe_gpu_axpy(net_params[param_id]->count(), + local_decay, + temp_[param_id]->gpu_data(), + net_params[param_id]->mutable_gpu_diff()); + } else { + LOG(FATAL)<< "Unknown regularization type: " + << regularization_type; + } + } +#endif // USE_CUDA } else { - LOG(FATAL) << "Unknown regularization type: " << regularization_type; +#ifdef USE_GREENTEA + if (local_decay) { + if (regularization_type == "L2") { + // add weight decay + greentea_gpu_axpy(this->device_->id(), + net_params[param_id]->count(), + local_decay, + (cl_mem)(net_params[param_id]->gpu_data()), 0, + (cl_mem)(net_params[param_id]->mutable_gpu_diff()), 0); + } else if (regularization_type == "L1") { + greentea_gpu_sign(this->device_->id(), + net_params[param_id]->count(), + (cl_mem)(net_params[param_id]->gpu_data()), 0, + (cl_mem)(temp_[param_id]->mutable_gpu_data()), 0); + greentea_gpu_axpy(this->device_->id(), + net_params[param_id]->count(), + local_decay, + (cl_mem)(temp_[param_id]->gpu_data()), 0, + (cl_mem)(net_params[param_id]->mutable_gpu_diff()), 0); + } else { + LOG(FATAL)<< "Unknown regularization type: " + << regularization_type; + } + } +#endif // USE_GREENTEA } - } #else - NO_GPU; + NO_GPU; #endif - break; - } - default: - LOG(FATAL) << "Unknown caffe mode: " << Caffe::mode(); + break; + } + default: { + LOG(FATAL) << "Unknown caffe mode: " << Caffe::mode(); + } } } #ifndef CPU_ONLY -template -void sgd_update_gpu(int N, Dtype* g, Dtype* h, Dtype momentum, - Dtype local_rate); +template +void sgd_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, Dtype momentum, + Dtype local_rate); #endif template @@ -217,28 +266,29 @@ void SGDSolver::ComputeUpdateValue(int param_id, Dtype rate) { Dtype local_rate = rate * net_params_lr[param_id]; // Compute the update to history, then copy it to the parameter diff. switch (Caffe::mode()) { - case Caffe::CPU: { - caffe_cpu_axpby(net_params[param_id]->count(), local_rate, - net_params[param_id]->cpu_diff(), momentum, - history_[param_id]->mutable_cpu_data()); - caffe_copy(net_params[param_id]->count(), - history_[param_id]->cpu_data(), - net_params[param_id]->mutable_cpu_diff()); - break; - } - case Caffe::GPU: { + case Caffe::CPU: { + caffe_cpu_axpby(net_params[param_id]->count(), local_rate, + net_params[param_id]->cpu_diff(), momentum, + history_[param_id]->mutable_cpu_data()); + caffe_cpu_copy(net_params[param_id]->count(), + history_[param_id]->cpu_data(), + net_params[param_id]->mutable_cpu_diff()); + break; + } + case Caffe::GPU: { #ifndef CPU_ONLY - sgd_update_gpu(net_params[param_id]->count(), + sgd_update_gpu(this->device_, net_params[param_id]->count(), net_params[param_id]->mutable_gpu_diff(), history_[param_id]->mutable_gpu_data(), momentum, local_rate); #else - NO_GPU; + NO_GPU; #endif - break; - } - default: - LOG(FATAL) << "Unknown caffe mode: " << Caffe::mode(); + break; + } + default: { + LOG(FATAL)<< "Unknown caffe mode: " << Caffe::mode(); + } } } @@ -264,7 +314,7 @@ void SGDSolver::SnapshotSolverStateToBinaryProto( state.set_learned_net(model_filename); state.set_current_step(this->current_step_); state.clear_history(); - for (int i = 0; i < history_.size(); ++i) { + for (uint_tp i = 0; i < history_.size(); ++i) { // Add history BlobProto* history_blob = state.add_history(); history_[i]->ToProto(history_blob); @@ -292,7 +342,7 @@ void SGDSolver::SnapshotSolverStateToHDF5( H5P_DEFAULT); CHECK_GE(history_hid, 0) << "Error saving solver state to " << snapshot_filename << "."; - for (int i = 0; i < history_.size(); ++i) { + for (uint_tp i = 0; i < history_.size(); ++i) { ostringstream oss; oss << i; hdf5_save_nd_dataset(history_hid, oss.str(), *history_[i]); @@ -316,7 +366,7 @@ void SGDSolver::RestoreSolverStateFromBinaryProto( CHECK_EQ(state.history_size(), history_.size()) << "Incorrect length of history blobs."; LOG(INFO) << "SGDSolver: restoring history"; - for (int i = 0; i < history_.size(); ++i) { + for (uint_tp i = 0; i < history_.size(); ++i) { history_[i]->FromProto(state.history(i)); } } @@ -333,10 +383,10 @@ void SGDSolver::RestoreSolverStateFromHDF5(const string& state_file) { this->current_step_ = hdf5_load_int(file_hid, "current_step"); hid_t history_hid = H5Gopen2(file_hid, "history", H5P_DEFAULT); CHECK_GE(history_hid, 0) << "Error reading history from " << state_file; - int state_history_size = hdf5_get_num_links(history_hid); + uint_tp state_history_size = hdf5_get_num_links(history_hid); CHECK_EQ(state_history_size, history_.size()) << "Incorrect length of history blobs."; - for (int i = 0; i < history_.size(); ++i) { + for (uint_tp i = 0; i < history_.size(); ++i) { ostringstream oss; oss << i; hdf5_load_nd_dataset(history_hid, oss.str().c_str(), 0, diff --git a/src/caffe/solvers/sgd_solver.cu b/src/caffe/solvers/sgd_solver.cu index e5410352140..d0cd2cb26f0 100644 --- a/src/caffe/solvers/sgd_solver.cu +++ b/src/caffe/solvers/sgd_solver.cu @@ -1,8 +1,14 @@ +#include "caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif namespace caffe { +#ifdef USE_CUDA template __global__ void SGDUpdate(int N, Dtype* g, Dtype* h, Dtype momentum, Dtype local_rate) { @@ -10,15 +16,34 @@ __global__ void SGDUpdate(int N, Dtype* g, Dtype* h, g[i] = h[i] = momentum*h[i] + local_rate*g[i]; } } +#endif + template -void sgd_update_gpu(int N, Dtype* g, Dtype* h, Dtype momentum, +void sgd_update_gpu(device* dev, int_tp N, Dtype* g, Dtype* h, Dtype momentum, Dtype local_rate) { - SGDUpdate // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( - N, g, h, momentum, local_rate); - CUDA_POST_KERNEL_CHECK; + if (dev->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + SGDUpdate // NOLINT_NEXT_LINE(whitespace/operators) + CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS) ( + N, g, h, momentum, local_rate); + CUDA_POST_KERNEL_CHECK; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dev->id()); + viennacl::ocl::program &program = dev->program(); + viennacl::ocl::kernel &oclk_sgd_update = program.get_kernel( + CL_KERNEL_SELECT("sgd_update")); + viennacl::ocl::enqueue( + oclk_sgd_update(N, WrapHandle((cl_mem) g, &ctx), + WrapHandle((cl_mem) h, &ctx), momentum, local_rate), + ctx.get_queue()); +#endif // USE_GREENTEA + } } -template void sgd_update_gpu(int, float*, float*, float, float); -template void sgd_update_gpu(int, double*, double*, double, double); +template void sgd_update_gpu(device*, int_tp, float*, float*, float, + float); +template void sgd_update_gpu(device*, int_tp, double*, double*, double, + double); } // namespace caffe diff --git a/src/caffe/syncedmem.cpp b/src/caffe/syncedmem.cpp index 4d3564172ab..d24a99b2a4c 100644 --- a/src/caffe/syncedmem.cpp +++ b/src/caffe/syncedmem.cpp @@ -1,75 +1,219 @@ #include "caffe/common.hpp" +#include "caffe/greentea/greentea.hpp" #include "caffe/syncedmem.hpp" + +#include "../../include/caffe/device.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea_im2col.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -SyncedMemory::~SyncedMemory() { - if (cpu_ptr_ && own_cpu_data_) { - CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_); +// If CUDA is available and in GPU mode, host memory will be allocated pinned, +// using cudaMallocHost. It avoids dynamic pinning for transfers (DMA). +// The improvement in performance seems negligible in the single GPU case, +// but might be more significant for parallel training. Most importantly, +// it improved stability for large models on many GPUs. + +void CaffeMallocHost(void** ptr, int_tp size, device* device_context) { +#ifndef CPU_ONLY + if (Caffe::mode() == Caffe::GPU) { + if (device_context->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + CUDA_CHECK(cudaMallocHost(ptr, size)); + return; +#endif // USE_CUDA + } else { + // Make sure the memory is zero-copy usable in OpenCL + CHECK_EQ(0, posix_memalign(ptr, OPENCL_PAGE_ALIGN, + ((size - 1)/OPENCL_CACHE_ALIGN + 1) * OPENCL_CACHE_ALIGN)) + << "Host memory allocation error of size: " + << size << " B"; + return; + } + } +#endif + *ptr = malloc(size); + CHECK(*ptr) << "host allocation of size " << size << " failed"; +} + +void CaffeFreeHost(void* ptr, device* device_context) { +#ifndef CPU_ONLY + if (Caffe::mode() == Caffe::GPU) { + if (device_context->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + cudaFreeHost(ptr); + return; +#endif // USE_CUDA + } } +#endif + free(ptr); +} + +SyncedMemory::~SyncedMemory() { #ifndef CPU_ONLY if (gpu_ptr_ && own_gpu_data_) { - int initial_device; - cudaGetDevice(&initial_device); - if (gpu_device_ != -1) { - CUDA_CHECK(cudaSetDevice(gpu_device_)); + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + // Free device memory + // Get current device active during call of destructor + int initial_device; + cudaGetDevice(&initial_device); + // We know that this memory blob belongs to the device_ + cudaSetDevice(device_->id()); + cudaFree(gpu_ptr_); + // Restore current device + cudaSetDevice(initial_device); + gpu_ptr_ = nullptr; + device_->DecreaseMemoryUsage(size_); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + // Free device memory + viennacl::ocl::context ctx = viennacl::ocl::get_context( + device_->id()); + ctx.get_queue().finish(); + CHECK_EQ(CL_SUCCESS, clReleaseMemObject(cl_gpu_mem_)) + << "OpenCL memory corruption"; + gpu_ptr_ = nullptr; + cl_gpu_mem_ = nullptr; + ctx.get_queue().finish(); + device_->DecreaseMemoryUsage(size_); +#endif // USE_GREENTEA } - CUDA_CHECK(cudaFree(gpu_ptr_)); - cudaSetDevice(initial_device); } -#endif // CPU_ONLY +#endif // !CPU_ONLY + // Free host memory + if (cpu_ptr_ && own_cpu_data_) { + CaffeFreeHost(cpu_ptr_, device_); + cpu_ptr_ = nullptr; + } } inline void SyncedMemory::to_cpu() { switch (head_) { - case UNINITIALIZED: - CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_); - caffe_memset(size_, 0, cpu_ptr_); - head_ = HEAD_AT_CPU; - own_cpu_data_ = true; - break; - case HEAD_AT_GPU: -#ifndef CPU_ONLY - if (cpu_ptr_ == NULL) { - CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_); + case UNINITIALIZED: { + CaffeMallocHost(&cpu_ptr_, size_, device_); + caffe_memset(size_, 0, cpu_ptr_); + head_ = HEAD_AT_CPU; own_cpu_data_ = true; + break; } - caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_); - head_ = SYNCED; -#else - NO_GPU; + case HEAD_AT_GPU: { +#ifndef CPU_ONLY + if (cpu_ptr_ == nullptr) { + CaffeMallocHost(&cpu_ptr_, size_, device_); + own_cpu_data_ = true; + } + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context ctx = viennacl::ocl::get_context( + device_->id()); + greentea_gpu_memcpy(size_, (cl_mem) gpu_ptr_, 0, cpu_ptr_, &ctx); + ctx.get_queue().finish(); #endif - break; - case HEAD_AT_CPU: - case SYNCED: - break; + } + head_ = SYNCED; +#else + NO_GPU; +#endif // !CPU_ONLY + break; + } + case HEAD_AT_CPU: + case SYNCED: + break; } } inline void SyncedMemory::to_gpu() { #ifndef CPU_ONLY switch (head_) { - case UNINITIALIZED: - CUDA_CHECK(cudaGetDevice(&gpu_device_)); - CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); - caffe_gpu_memset(size_, 0, gpu_ptr_); - head_ = HEAD_AT_GPU; - own_gpu_data_ = true; - break; - case HEAD_AT_CPU: - if (gpu_ptr_ == NULL) { - CUDA_CHECK(cudaGetDevice(&gpu_device_)); - CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); - own_gpu_data_ = true; + case UNINITIALIZED: { + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); + device_->IncreaseMemoryUsage(size_); + caffe_gpu_memset(size_, 0, gpu_ptr_); + own_gpu_data_ = true; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context ctx = viennacl::ocl::get_context( + device_->id()); + ctx.get_queue().finish(); + cl_int err; + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + cl_gpu_mem_ = clCreateBuffer(ctx.handle().get(), + CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, + size_, nullptr, &err); + } else { + cl_gpu_mem_ = clCreateBuffer(ctx.handle().get(), CL_MEM_READ_WRITE, + size_, nullptr, &err); + } + CHECK_EQ(0, err) << "OpenCL buffer allocation of size " + << size_ << " failed."; + device_->IncreaseMemoryUsage(size_); + int_tp alpha = 0; + greentea_memset(device_->id(), size_, alpha, cl_gpu_mem_, 0); + gpu_ptr_ = reinterpret_cast(cl_gpu_mem_); + ctx.get_queue().finish(); + own_gpu_data_ = true; +#endif // USE_GREENTEA + } + head_ = HEAD_AT_GPU; + break; + } + case HEAD_AT_CPU: { + if (device_->backend() == Backend::BACKEND_CUDA) { +#ifdef USE_CUDA + if (gpu_ptr_ == nullptr) { + CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); + device_->IncreaseMemoryUsage(size_); + } + caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_); + own_gpu_data_ = true; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context ctx = viennacl::ocl::get_context( + device_->id()); + ctx.get_queue().finish(); + if (gpu_ptr_ == nullptr) { + cl_int err; + if (ctx.devices()[0].type() == CL_DEVICE_TYPE_CPU) { + cl_gpu_mem_ = clCreateBuffer( + ctx.handle().get(), CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, + size_, nullptr, &err); + } else { + cl_gpu_mem_ = clCreateBuffer(ctx.handle().get(), CL_MEM_READ_WRITE, + size_, nullptr, &err); + } + CHECK_EQ(0, err) << "OpenCL buffer allocation of size " + << size_ << " failed."; + device_->IncreaseMemoryUsage(size_); + gpu_ptr_ = reinterpret_cast(cl_gpu_mem_); + ctx.get_queue().finish(); + } + greentea_gpu_memcpy(size_, cpu_ptr_, (cl_mem) gpu_ptr_, 0, &ctx); + ctx.get_queue().finish(); + own_gpu_data_ = true; +#endif // USE_GREENTEA + } + head_ = SYNCED; + break; } - caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_); - head_ = SYNCED; - break; - case HEAD_AT_GPU: - case SYNCED: - break; + case HEAD_AT_GPU: + case SYNCED: + break; } #else NO_GPU; @@ -78,13 +222,13 @@ inline void SyncedMemory::to_gpu() { const void* SyncedMemory::cpu_data() { to_cpu(); - return (const void*)cpu_ptr_; + return (const void*) cpu_ptr_; } void SyncedMemory::set_cpu_data(void* data) { CHECK(data); - if (own_cpu_data_) { - CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_); + if (cpu_ptr_ && own_cpu_data_) { + CaffeFreeHost(cpu_ptr_, device_); } cpu_ptr_ = data; head_ = HEAD_AT_CPU; @@ -94,7 +238,7 @@ void SyncedMemory::set_cpu_data(void* data) { const void* SyncedMemory::gpu_data() { #ifndef CPU_ONLY to_gpu(); - return (const void*)gpu_ptr_; + return (const void*) gpu_ptr_; #else NO_GPU; return NULL; @@ -103,19 +247,25 @@ const void* SyncedMemory::gpu_data() { void SyncedMemory::set_gpu_data(void* data) { #ifndef CPU_ONLY + if (this->device_->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA CHECK(data); if (own_gpu_data_) { int initial_device; cudaGetDevice(&initial_device); - if (gpu_device_ != -1) { - CUDA_CHECK(cudaSetDevice(gpu_device_)); - } + CUDA_CHECK(cudaSetDevice(device_->id())); CUDA_CHECK(cudaFree(gpu_ptr_)); cudaSetDevice(initial_device); } gpu_ptr_ = data; head_ = HEAD_AT_GPU; own_gpu_data_ = false; +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + // TODO: Implement OpenCL - OpenCL and OpenCL - CUDA data sharing +#endif // USE_GREENTEA + } #else NO_GPU; #endif @@ -138,11 +288,12 @@ void* SyncedMemory::mutable_gpu_data() { #endif } +// TODO: Implement this function device abstracted #ifndef CPU_ONLY +#ifdef USE_CUDA void SyncedMemory::async_gpu_push(const cudaStream_t& stream) { CHECK(head_ == HEAD_AT_CPU); if (gpu_ptr_ == NULL) { - CUDA_CHECK(cudaGetDevice(&gpu_device_)); CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); own_gpu_data_ = true; } @@ -151,7 +302,8 @@ void SyncedMemory::async_gpu_push(const cudaStream_t& stream) { // Assume caller will synchronize on the stream before use head_ = SYNCED; } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY } // namespace caffe diff --git a/src/caffe/test/CMakeLists.txt b/src/caffe/test/CMakeLists.txt index 35a803f2f41..b8212fb7e86 100644 --- a/src/caffe/test/CMakeLists.txt +++ b/src/caffe/test/CMakeLists.txt @@ -18,11 +18,15 @@ caffe_leave_only_selected_tests(test_cuda ${BUILD_only_tests}) set(the_target test.testbin) set(test_args --gtest_shuffle) -if(HAVE_CUDA) +if(HAVE_CUDA AND USE_CUDA) caffe_cuda_compile(test_cuda_objs ${test_cuda}) list(APPEND test_srcs ${test_cuda_objs} ${test_cuda}) else() - list(APPEND test_args --gtest_filter="-*GPU*") + if(USE_GREENTEA) + list(APPEND test_srcs ${test_cuda_objs} ${test_cuda}) + else() + list(APPEND test_args --gtest_filter="-*GPU*") + endif() endif() # ---[ Adding test target diff --git a/src/caffe/test/test_accuracy_layer.cpp b/src/caffe/test/test_accuracy_layer.cpp index 6fe808bd5c5..45aa94349c0 100644 --- a/src/caffe/test/test_accuracy_layer.cpp +++ b/src/caffe/test/test_accuracy_layer.cpp @@ -22,7 +22,7 @@ class AccuracyLayerTest : public CPUDeviceTest { blob_top_(new Blob()), blob_top_per_class_(new Blob()), top_k_(3) { - vector shape(2); + vector shape(2); shape[0] = 100; shape[1] = 10; blob_bottom_data_->Reshape(shape); @@ -43,12 +43,12 @@ class AccuracyLayerTest : public CPUDeviceTest { GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_data_); - const unsigned int prefetch_rng_seed = caffe_rng_rand(); + const uint_tp prefetch_rng_seed = caffe_rng_rand(); shared_ptr rng(new Caffe::RNG(prefetch_rng_seed)); caffe::rng_t* prefetch_rng = static_cast(rng->generator()); Dtype* label_data = blob_bottom_label_->mutable_cpu_data(); - for (int i = 0; i < blob_bottom_label_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_label_->count(); ++i) { label_data[i] = (*prefetch_rng)() % 10; } } @@ -66,7 +66,7 @@ class AccuracyLayerTest : public CPUDeviceTest { vector*> blob_bottom_vec_; vector*> blob_top_vec_; vector*> blob_top_per_class_vec_; - int top_k_; + int_tp top_k_; }; TYPED_TEST_CASE(AccuracyLayerTest, TestDtypes); @@ -115,12 +115,12 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPU) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); TypeParam max_value; - int max_id; - int num_correct_labels = 0; - for (int i = 0; i < 100; ++i) { + int_tp max_id; + int_tp num_correct_labels = 0; + for (int_tp i = 0; i < 100; ++i) { max_value = -FLT_MAX; max_id = 0; - for (int j = 0; j < 10; ++j) { + for (int_tp j = 0; j < 10; ++j) { if (this->blob_bottom_data_->data_at(i, j, 0, 0) > max_value) { max_value = this->blob_bottom_data_->data_at(i, j, 0, 0); max_id = j; @@ -136,7 +136,7 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPU) { TYPED_TEST(AccuracyLayerTest, TestForwardWithSpatialAxes) { this->blob_bottom_data_->Reshape(2, 10, 4, 5); - vector label_shape(3); + vector label_shape(3); label_shape[0] = 2; label_shape[1] = 4; label_shape[2] = 5; this->blob_bottom_label_->Reshape(label_shape); this->FillBottoms(); @@ -147,16 +147,16 @@ TYPED_TEST(AccuracyLayerTest, TestForwardWithSpatialAxes) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); TypeParam max_value; - const int num_labels = this->blob_bottom_label_->count(); - int max_id; - int num_correct_labels = 0; - vector label_offset(3); - for (int n = 0; n < this->blob_bottom_data_->num(); ++n) { - for (int h = 0; h < this->blob_bottom_data_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_data_->width(); ++w) { + const int_tp num_labels = this->blob_bottom_label_->count(); + int_tp max_id; + int_tp num_correct_labels = 0; + vector label_offset(3); + for (int_tp n = 0; n < this->blob_bottom_data_->num(); ++n) { + for (int_tp h = 0; h < this->blob_bottom_data_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_data_->width(); ++w) { max_value = -FLT_MAX; max_id = 0; - for (int c = 0; c < this->blob_bottom_data_->channels(); ++c) { + for (int_tp c = 0; c < this->blob_bottom_data_->channels(); ++c) { const TypeParam pred_value = this->blob_bottom_data_->data_at(n, c, h, w); if (pred_value > max_value) { @@ -165,8 +165,9 @@ TYPED_TEST(AccuracyLayerTest, TestForwardWithSpatialAxes) { } } label_offset[0] = n; label_offset[1] = h; label_offset[2] = w; - const int correct_label = - static_cast(this->blob_bottom_label_->data_at(label_offset)); + const int_tp correct_label = + static_cast(this->blob_bottom_label_ + ->data_at(label_offset)); if (max_id == correct_label) { ++num_correct_labels; } @@ -190,17 +191,17 @@ TYPED_TEST(AccuracyLayerTest, TestForwardIgnoreLabel) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); TypeParam max_value; - int max_id; - int num_correct_labels = 0; - int count = 0; - for (int i = 0; i < 100; ++i) { + int_tp max_id; + int_tp num_correct_labels = 0; + int_tp count = 0; + for (int_tp i = 0; i < 100; ++i) { if (kIgnoreLabelValue == this->blob_bottom_label_->data_at(i, 0, 0, 0)) { continue; } ++count; max_value = -FLT_MAX; max_id = 0; - for (int j = 0; j < 10; ++j) { + for (int_tp j = 0; j < 10; ++j) { if (this->blob_bottom_data_->data_at(i, j, 0, 0) > max_value) { max_value = this->blob_bottom_data_->data_at(i, j, 0, 0); max_id = j; @@ -224,13 +225,13 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPUTopK) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); TypeParam current_value; - int current_rank; - int num_correct_labels = 0; - for (int i = 0; i < 100; ++i) { - for (int j = 0; j < 10; ++j) { + int_tp current_rank; + int_tp num_correct_labels = 0; + for (int_tp i = 0; i < 100; ++i) { + for (int_tp j = 0; j < 10; ++j) { current_value = this->blob_bottom_data_->data_at(i, j, 0, 0); current_rank = 0; - for (int k = 0; k < 10; ++k) { + for (int_tp k = 0; k < 10; ++k) { if (this->blob_bottom_data_->data_at(i, k, 0, 0) > current_value) { ++current_rank; } @@ -253,15 +254,15 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPUPerClass) { layer.Forward(this->blob_bottom_vec_, this->blob_top_per_class_vec_); TypeParam max_value; - int max_id; - int num_correct_labels = 0; - const int num_class = this->blob_top_per_class_->num(); - vector correct_per_class(num_class, 0); - vector num_per_class(num_class, 0); - for (int i = 0; i < 100; ++i) { + int_tp max_id; + int_tp num_correct_labels = 0; + const int_tp num_class = this->blob_top_per_class_->num(); + vector correct_per_class(num_class, 0); + vector num_per_class(num_class, 0); + for (int_tp i = 0; i < 100; ++i) { max_value = -FLT_MAX; max_id = 0; - for (int j = 0; j < 10; ++j) { + for (int_tp j = 0; j < 10; ++j) { if (this->blob_bottom_data_->data_at(i, j, 0, 0) > max_value) { max_value = this->blob_bottom_data_->data_at(i, j, 0, 0); max_id = j; @@ -275,7 +276,7 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPUPerClass) { } EXPECT_NEAR(this->blob_top_->data_at(0, 0, 0, 0), num_correct_labels / 100.0, 1e-4); - for (int i = 0; i < num_class; ++i) { + for (int_tp i = 0; i < num_class; ++i) { TypeParam accuracy_per_class = (num_per_class[i] > 0 ? static_cast(correct_per_class[i]) / num_per_class[i] : 0); EXPECT_NEAR(this->blob_top_per_class_->data_at(i, 0, 0, 0), @@ -297,20 +298,20 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPUPerClassWithIgnoreLabel) { layer.Forward(this->blob_bottom_vec_, this->blob_top_per_class_vec_); TypeParam max_value; - int max_id; - int num_correct_labels = 0; - const int num_class = this->blob_top_per_class_->num(); - vector correct_per_class(num_class, 0); - vector num_per_class(num_class, 0); - int count = 0; - for (int i = 0; i < 100; ++i) { + int_tp max_id; + int_tp num_correct_labels = 0; + const int_tp num_class = this->blob_top_per_class_->num(); + vector correct_per_class(num_class, 0); + vector num_per_class(num_class, 0); + int_tp count = 0; + for (int_tp i = 0; i < 100; ++i) { if (kIgnoreLabelValue == this->blob_bottom_label_->data_at(i, 0, 0, 0)) { continue; } ++count; max_value = -FLT_MAX; max_id = 0; - for (int j = 0; j < 10; ++j) { + for (int_tp j = 0; j < 10; ++j) { if (this->blob_bottom_data_->data_at(i, j, 0, 0) > max_value) { max_value = this->blob_bottom_data_->data_at(i, j, 0, 0); max_id = j; @@ -325,7 +326,7 @@ TYPED_TEST(AccuracyLayerTest, TestForwardCPUPerClassWithIgnoreLabel) { EXPECT_EQ(count, 97); EXPECT_NEAR(this->blob_top_->data_at(0, 0, 0, 0), num_correct_labels / TypeParam(count), 1e-4); - for (int i = 0; i < 10; ++i) { + for (int_tp i = 0; i < 10; ++i) { TypeParam accuracy_per_class = (num_per_class[i] > 0 ? static_cast(correct_per_class[i]) / num_per_class[i] : 0); EXPECT_NEAR(this->blob_top_per_class_->data_at(i, 0, 0, 0), diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp index 472e6652239..4153c1eb68f 100644 --- a/src/caffe/test/test_argmax_layer.cpp +++ b/src/caffe/test/test_argmax_layer.cpp @@ -19,7 +19,7 @@ class ArgMaxLayerTest : public CPUDeviceTest { : blob_bottom_(new Blob(10, 10, 20, 20)), blob_top_(new Blob()), top_k_(5) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -32,7 +32,7 @@ class ArgMaxLayerTest : public CPUDeviceTest { Blob* const blob_top_; vector*> blob_bottom_vec_; vector*> blob_top_vec_; - size_t top_k_; + uint_tp top_k_; }; TYPED_TEST_CASE(ArgMaxLayerTest, TestDtypes); @@ -100,16 +100,16 @@ TYPED_TEST(ArgMaxLayerTest, TestCPU) { // Now, check values const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); const TypeParam* top_data = this->blob_top_->cpu_data(); - int max_ind; + int_tp max_ind; TypeParam max_val; - int num = this->blob_bottom_->num(); - int dim = this->blob_bottom_->count() / num; - for (int i = 0; i < num; ++i) { + int_tp num = this->blob_bottom_->num(); + int_tp dim = this->blob_bottom_->count() / num; + for (int_tp i = 0; i < num; ++i) { EXPECT_GE(top_data[i], 0); EXPECT_LE(top_data[i], dim); max_ind = top_data[i]; max_val = bottom_data[i * dim + max_ind]; - for (int j = 0; j < dim; ++j) { + for (int_tp j = 0; j < dim; ++j) { EXPECT_LE(bottom_data[i * dim + j], max_val); } } @@ -125,17 +125,17 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) { // Now, check values const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); const TypeParam* top_data = this->blob_top_->cpu_data(); - int max_ind; + int_tp max_ind; TypeParam max_val; - int num = this->blob_bottom_->num(); - int dim = this->blob_bottom_->count() / num; - for (int i = 0; i < num; ++i) { + int_tp num = this->blob_bottom_->num(); + int_tp dim = this->blob_bottom_->count() / num; + for (int_tp i = 0; i < num; ++i) { EXPECT_GE(top_data[i], 0); EXPECT_LE(top_data[i], dim); max_ind = top_data[i * 2]; max_val = top_data[i * 2 + 1]; EXPECT_EQ(bottom_data[i * dim + max_ind], max_val); - for (int j = 0; j < dim; ++j) { + for (int_tp j = 0; j < dim; ++j) { EXPECT_LE(bottom_data[i * dim + j], max_val); } } @@ -150,18 +150,18 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUTopK) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Now, check values const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); - int max_ind; + int_tp max_ind; TypeParam max_val; - int num = this->blob_bottom_->num(); - int dim = this->blob_bottom_->count() / num; - for (int i = 0; i < num; ++i) { + int_tp num = this->blob_bottom_->num(); + int_tp dim = this->blob_bottom_->count() / num; + for (int_tp i = 0; i < num; ++i) { EXPECT_GE(this->blob_top_->data_at(i, 0, 0, 0), 0); EXPECT_LE(this->blob_top_->data_at(i, 0, 0, 0), dim); - for (int j = 0; j < this->top_k_; ++j) { + for (int_tp j = 0; j < this->top_k_; ++j) { max_ind = this->blob_top_->data_at(i, 0, j, 0); max_val = bottom_data[i * dim + max_ind]; - int count = 0; - for (int k = 0; k < dim; ++k) { + int_tp count = 0; + for (int_tp k = 0; k < dim; ++k) { if (bottom_data[i * dim + k] > max_val) { ++count; } @@ -181,19 +181,19 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUMaxValTopK) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Now, check values const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); - int max_ind; + int_tp max_ind; TypeParam max_val; - int num = this->blob_bottom_->num(); - int dim = this->blob_bottom_->count() / num; - for (int i = 0; i < num; ++i) { + int_tp num = this->blob_bottom_->num(); + int_tp dim = this->blob_bottom_->count() / num; + for (int_tp i = 0; i < num; ++i) { EXPECT_GE(this->blob_top_->data_at(i, 0, 0, 0), 0); EXPECT_LE(this->blob_top_->data_at(i, 0, 0, 0), dim); - for (int j = 0; j < this->top_k_; ++j) { + for (int_tp j = 0; j < this->top_k_; ++j) { max_ind = this->blob_top_->data_at(i, 0, j, 0); max_val = this->blob_top_->data_at(i, 1, j, 0); EXPECT_EQ(bottom_data[i * dim + max_ind], max_val); - int count = 0; - for (int k = 0; k < dim; ++k) { + int_tp count = 0; + for (int_tp k = 0; k < dim; ++k) { if (bottom_data[i * dim + k] > max_val) { ++count; } @@ -211,17 +211,17 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUAxis) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Now, check values - int max_ind; + int_tp max_ind; TypeParam max_val; - std::vector shape = this->blob_bottom_->shape(); - for (int i = 0; i < shape[1]; ++i) { - for (int j = 0; j < shape[2]; ++j) { - for (int k = 0; k < shape[3]; ++k) { + std::vector shape = this->blob_bottom_->shape(); + for (int_tp i = 0; i < shape[1]; ++i) { + for (int_tp j = 0; j < shape[2]; ++j) { + for (int_tp k = 0; k < shape[3]; ++k) { max_ind = this->blob_top_->data_at(0, i, j, k); max_val = this->blob_bottom_->data_at(max_ind, i, j, k); EXPECT_GE(max_ind, 0); EXPECT_LE(max_ind, shape[0]); - for (int l = 0; l < shape[0]; ++l) { + for (int_tp l = 0; l < shape[0]; ++l) { EXPECT_LE(this->blob_bottom_->data_at(l, i, j, k), max_val); } } @@ -238,19 +238,19 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUAxisTopK) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Now, check values - int max_ind; + int_tp max_ind; TypeParam max_val; - std::vector shape = this->blob_bottom_->shape(); - for (int i = 0; i < shape[0]; ++i) { - for (int j = 0; j < shape[1]; ++j) { - for (int k = 0; k < shape[3]; ++k) { - for (int m = 0; m < this->top_k_; ++m) { + std::vector shape = this->blob_bottom_->shape(); + for (int_tp i = 0; i < shape[0]; ++i) { + for (int_tp j = 0; j < shape[1]; ++j) { + for (int_tp k = 0; k < shape[3]; ++k) { + for (int_tp m = 0; m < this->top_k_; ++m) { max_ind = this->blob_top_->data_at(i, j, m, k); max_val = this->blob_bottom_->data_at(i, j, max_ind, k); EXPECT_GE(max_ind, 0); EXPECT_LE(max_ind, shape[2]); - int count = 0; - for (int l = 0; l < shape[2]; ++l) { + int_tp count = 0; + for (int_tp l = 0; l < shape[2]; ++l) { if (this->blob_bottom_->data_at(i, j, l, k) > max_val) { ++count; } @@ -273,14 +273,14 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUAxisMaxValTopK) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Now, check values TypeParam max_val; - std::vector shape = this->blob_bottom_->shape(); - for (int i = 0; i < shape[0]; ++i) { - for (int j = 0; j < shape[1]; ++j) { - for (int k = 0; k < shape[2]; ++k) { - for (int m = 0; m < this->top_k_; ++m) { + std::vector shape = this->blob_bottom_->shape(); + for (int_tp i = 0; i < shape[0]; ++i) { + for (int_tp j = 0; j < shape[1]; ++j) { + for (int_tp k = 0; k < shape[2]; ++k) { + for (int_tp m = 0; m < this->top_k_; ++m) { max_val = this->blob_top_->data_at(i, j, k, m); - int count = 0; - for (int l = 0; l < shape[3]; ++l) { + int_tp count = 0; + for (int_tp l = 0; l < shape[3]; ++l) { if (this->blob_bottom_->data_at(i, j, k, l) > max_val) { ++count; } diff --git a/src/caffe/test/test_batch_reindex_layer.cpp b/src/caffe/test/test_batch_reindex_layer.cpp index 9ea1a2f6f47..fd6b3d4355a 100644 --- a/src/caffe/test/test_batch_reindex_layer.cpp +++ b/src/caffe/test/test_batch_reindex_layer.cpp @@ -23,14 +23,14 @@ class BatchReindexLayerTest : public MultiDeviceTest { blob_top_(new Blob()) { } virtual void SetUp() { - Caffe::set_random_seed(1701); - vector sz; + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); + vector sz; sz.push_back(5); sz.push_back(4); sz.push_back(3); sz.push_back(2); blob_bottom_->Reshape(sz); - vector permsz; + vector permsz; permsz.push_back(6); blob_bottom_permute_->Reshape(permsz); @@ -38,8 +38,8 @@ class BatchReindexLayerTest : public MultiDeviceTest { FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_); - int perm[] = { 4, 0, 4, 0, 1, 2 }; - for (int i = 0; i < blob_bottom_permute_->count(); ++i) { + int_tp perm[] = { 4, 0, 4, 0, 1, 2 }; + for (int_tp i = 0; i < blob_bottom_permute_->count(); ++i) { blob_bottom_permute_->mutable_cpu_data()[i] = perm[i]; } @@ -61,21 +61,21 @@ class BatchReindexLayerTest : public MultiDeviceTest { void TestForward() { LayerParameter layer_param; - vector sz; + vector sz; sz.push_back(5); sz.push_back(4); sz.push_back(3); sz.push_back(2); blob_bottom_->Reshape(sz); - for (int i = 0; i < blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_->count(); ++i) { blob_bottom_->mutable_cpu_data()[i] = i; } - vector permsz; + vector permsz; permsz.push_back(6); blob_bottom_permute_->Reshape(permsz); - int perm[] = { 4, 0, 4, 0, 1, 2 }; - for (int i = 0; i < blob_bottom_permute_->count(); ++i) { + int_tp perm[] = { 4, 0, 4, 0, 1, 2 }; + for (int_tp i = 0; i < blob_bottom_permute_->count(); ++i) { blob_bottom_permute_->mutable_cpu_data()[i] = perm[i]; } BatchReindexLayer layer(layer_param); @@ -86,12 +86,12 @@ class BatchReindexLayerTest : public MultiDeviceTest { EXPECT_EQ(blob_top_->width(), blob_bottom_->width()); layer.Forward(blob_bottom_vec_, blob_top_vec_); - int channels = blob_top_->channels(); - int height = blob_top_->height(); - int width = blob_top_->width(); - for (int i = 0; i < blob_top_->count(); ++i) { - int n = i / (channels * width * height); - int inner_idx = (i % (channels * width * height)); + int_tp channels = blob_top_->channels(); + int_tp height = blob_top_->height(); + int_tp width = blob_top_->width(); + for (int_tp i = 0; i < blob_top_->count(); ++i) { + int_tp n = i / (channels * width * height); + int_tp inner_idx = (i % (channels * width * height)); EXPECT_EQ( blob_top_->cpu_data()[i], blob_bottom_->cpu_data()[perm[n] * channels * width * height diff --git a/src/caffe/test/test_bias_layer.cpp b/src/caffe/test/test_bias_layer.cpp index 3862e763e28..42bd342d7ea 100644 --- a/src/caffe/test/test_bias_layer.cpp +++ b/src/caffe/test/test_bias_layer.cpp @@ -24,10 +24,10 @@ class BiasLayerTest : public MultiDeviceTest { blob_bottom_broadcast_0_(new Blob()), blob_bottom_broadcast_1_(new Blob()), blob_bottom_broadcast_2_(new Blob()), - blob_bottom_bias_(new Blob(vector())), + blob_bottom_bias_(new Blob(vector())), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); - vector broadcast_shape(2); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); + vector broadcast_shape(2); broadcast_shape[0] = 2; broadcast_shape[1] = 3; this->blob_bottom_broadcast_0_->Reshape(broadcast_shape); broadcast_shape[0] = 3; broadcast_shape[1] = 4; @@ -79,10 +79,10 @@ TYPED_TEST(BiasLayerTest, TestForwardEltwise) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_->cpu_data(); const Dtype* in_data_b = this->blob_bottom_eltwise_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] + in_data_b[i], 1e-5); } } @@ -99,10 +99,10 @@ TYPED_TEST(BiasLayerTest, TestForwardEltwiseInPlace) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_bottom_->cpu_data(); - const int count = this->blob_bottom_->count(); + const int_tp count = this->blob_bottom_->count(); const Dtype* in_data_a = orig_bottom.cpu_data(); const Dtype* in_data_b = this->blob_bottom_eltwise_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] + in_data_b[i], 1e-5); } } @@ -143,11 +143,11 @@ TYPED_TEST(BiasLayerTest, TestBackwardEltwiseInPlace) { caffe_copy(top_diff.count(), top_diff.cpu_data(), this->blob_bottom_->mutable_cpu_diff()); layer->Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(orig_bottom_diff.cpu_diff()[i], this->blob_bottom_->cpu_diff()[i], 1e-5); } - for (int i = 0; i < this->blob_bottom_eltwise_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_eltwise_->count(); ++i) { EXPECT_NEAR(orig_bias_diff.cpu_diff()[i], this->blob_bottom_eltwise_->cpu_diff()[i], 1e-5); } @@ -165,10 +165,10 @@ TYPED_TEST(BiasLayerTest, TestForwardEltwiseWithParam) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_->cpu_data(); const Dtype* in_data_b = layer->blobs()[0]->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] + in_data_b[i], 1e-5); } } @@ -182,10 +182,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBroadcastBegin) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) + this->blob_bottom_broadcast_0_->data_at(n, c, 0, 0), @@ -205,10 +205,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBroadcastMiddle) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) + this->blob_bottom_broadcast_1_->data_at(c, h, 0, 0), @@ -230,10 +230,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBroadcastMiddleInPlace) { shared_ptr > layer(new BiasLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_bottom_->data_at(n, c, h, w), orig_bottom.data_at(n, c, h, w) + this->blob_bottom_broadcast_1_->data_at(c, h, 0, 0), @@ -280,11 +280,11 @@ TYPED_TEST(BiasLayerTest, TestBackwardBroadcastMiddleInPlace) { caffe_copy(top_diff.count(), top_diff.cpu_data(), this->blob_bottom_->mutable_cpu_diff()); layer->Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(orig_bottom_diff.cpu_diff()[i], this->blob_bottom_->cpu_diff()[i], 1e-5); } - for (int i = 0; i < this->blob_bottom_broadcast_1_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_broadcast_1_->count(); ++i) { EXPECT_NEAR(orig_bias_diff.cpu_diff()[i], this->blob_bottom_broadcast_1_->cpu_diff()[i], 1e-5); } @@ -301,10 +301,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBroadcastMiddleWithParam) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) + layer->blobs()[0]->data_at(c, h, 0, 0), 1e-5); @@ -323,10 +323,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBroadcastEnd) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) + this->blob_bottom_broadcast_2_->data_at(h, w, 0, 0), @@ -346,10 +346,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBias) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data = this->blob_bottom_->cpu_data(); const Dtype bias = *this->blob_bottom_bias_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data[i] + bias, 1e-5); } } @@ -364,10 +364,10 @@ TYPED_TEST(BiasLayerTest, TestForwardBiasAxis2) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data = this->blob_bottom_->cpu_data(); const Dtype bias = *this->blob_bottom_bias_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data[i] + bias, 1e-5); } } diff --git a/src/caffe/test/test_blob.cpp b/src/caffe/test/test_blob.cpp index a9d7d519e45..9fc810c9ec0 100644 --- a/src/caffe/test/test_blob.cpp +++ b/src/caffe/test/test_blob.cpp @@ -55,7 +55,7 @@ TYPED_TEST(BlobSimpleTest, TestLegacyBlobProtoShapeEquals) { BlobProto blob_proto; // Reshape to (3 x 2). - vector shape(2); + vector shape(2); shape[0] = 3; shape[1] = 2; this->blob_->Reshape(shape); @@ -132,7 +132,7 @@ TYPED_TEST(BlobMathTest, TestSumOfSquares) { filler.Fill(this->blob_); Dtype expected_sumsq = 0; const Dtype* data = this->blob_->cpu_data(); - for (int i = 0; i < this->blob_->count(); ++i) { + for (int_tp i = 0; i < this->blob_->count(); ++i) { expected_sumsq += data[i] * data[i]; } // Do a mutable access on the current device, @@ -187,7 +187,7 @@ TYPED_TEST(BlobMathTest, TestAsum) { filler.Fill(this->blob_); Dtype expected_asum = 0; const Dtype* data = this->blob_->cpu_data(); - for (int i = 0; i < this->blob_->count(); ++i) { + for (int_tp i = 0; i < this->blob_->count(); ++i) { expected_asum += std::fabs(data[i]); } // Do a mutable access on the current device, diff --git a/src/caffe/test/test_caffe_main.cpp b/src/caffe/test/test_caffe_main.cpp index c8caf5ac58e..fb6df8cf17b 100644 --- a/src/caffe/test/test_caffe_main.cpp +++ b/src/caffe/test/test_caffe_main.cpp @@ -1,39 +1,46 @@ // The main caffe test code. Your test cpp code should include this hpp // to allow a main function to be compiled into the binary. +#include + #include "caffe/caffe.hpp" #include "caffe/test/test_caffe_main.hpp" +#ifndef TEST_DEVICE +#define TEST_DEVICE 0 +#endif + namespace caffe { #ifndef CPU_ONLY - cudaDeviceProp CAFFE_TEST_CUDA_PROP; +#ifdef USE_CUDA +cudaDeviceProp CAFFE_TEST_CUDA_PROP; +#endif // USE_CUDA #endif } #ifndef CPU_ONLY +#ifdef USE_CUDA using caffe::CAFFE_TEST_CUDA_PROP; +#endif // USE_CUDA #endif +using caffe::Caffe; + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); caffe::GlobalInit(&argc, &argv); #ifndef CPU_ONLY - // Before starting testing, let's first print out a few cuda defice info. - int device; - cudaGetDeviceCount(&device); - cout << "Cuda number of devices: " << device << endl; + int device = 0; if (argc > 1) { // Use the given device device = atoi(argv[1]); - cudaSetDevice(device); - cout << "Setting to use device " << device << endl; - } else if (CUDA_TEST_DEVICE >= 0) { + } else if (TEST_DEVICE >= 0) { // Use the device assigned in build configuration; but with a lower priority - device = CUDA_TEST_DEVICE; + device = TEST_DEVICE; } - cudaGetDevice(&device); - cout << "Current device id: " << device << endl; - cudaGetDeviceProperties(&CAFFE_TEST_CUDA_PROP, device); + cout << "Setting to use device " << device << endl; + Caffe::SetDevices(std::vector{device}); + Caffe::SetDevice(device); #endif // invoke the test. return RUN_ALL_TESTS(); diff --git a/src/caffe/test/test_common.cpp b/src/caffe/test/test_common.cpp index 58ae5c60a4f..5663a9b1845 100644 --- a/src/caffe/test/test_common.cpp +++ b/src/caffe/test/test_common.cpp @@ -13,9 +13,13 @@ class CommonTest : public ::testing::Test {}; #ifndef CPU_ONLY // GPU Caffe singleton test. TEST_F(CommonTest, TestCublasHandlerGPU) { - int cuda_device_id; - CUDA_CHECK(cudaGetDevice(&cuda_device_id)); - EXPECT_TRUE(Caffe::cublas_handle()); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + int cuda_device_id; + CUDA_CHECK(cudaGetDevice(&cuda_device_id)); + EXPECT_TRUE(Caffe::cublas_handle()); +#endif // USE_CUDA + } } #endif @@ -28,12 +32,12 @@ TEST_F(CommonTest, TestBrewMode) { } TEST_F(CommonTest, TestRandSeedCPU) { - SyncedMemory data_a(10 * sizeof(int)); - SyncedMemory data_b(10 * sizeof(int)); - Caffe::set_random_seed(1701); + SyncedMemory data_a(10 * sizeof(int), Caffe::GetDefaultDevice()); + SyncedMemory data_b(10 * sizeof(int), Caffe::GetDefaultDevice()); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); caffe_rng_bernoulli(10, 0.5, static_cast(data_a.mutable_cpu_data())); - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); caffe_rng_bernoulli(10, 0.5, static_cast(data_b.mutable_cpu_data())); for (int i = 0; i < 10; ++i) { @@ -45,17 +49,25 @@ TEST_F(CommonTest, TestRandSeedCPU) { #ifndef CPU_ONLY // GPU Caffe singleton test. TEST_F(CommonTest, TestRandSeedGPU) { - SyncedMemory data_a(10 * sizeof(unsigned int)); - SyncedMemory data_b(10 * sizeof(unsigned int)); - Caffe::set_random_seed(1701); - CURAND_CHECK(curandGenerate(Caffe::curand_generator(), - static_cast(data_a.mutable_gpu_data()), 10)); - Caffe::set_random_seed(1701); - CURAND_CHECK(curandGenerate(Caffe::curand_generator(), - static_cast(data_b.mutable_gpu_data()), 10)); - for (int i = 0; i < 10; ++i) { - EXPECT_EQ(((const unsigned int*)(data_a.cpu_data()))[i], - ((const unsigned int*)(data_b.cpu_data()))[i]); + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + SyncedMemory data_a(10 * sizeof(unsigned int), + Caffe::GetDefaultDevice()); + SyncedMemory data_b(10 * sizeof(unsigned int), + Caffe::GetDefaultDevice()); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); + CURAND_CHECK(curandGenerate(Caffe::curand_generator(), + static_cast(data_a.mutable_gpu_data()), 10)); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); + CURAND_CHECK(curandGenerate(Caffe::curand_generator(), + static_cast(data_b.mutable_gpu_data()), 10)); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(((const unsigned int*)(data_a.cpu_data()))[i], + ((const unsigned int*)(data_b.cpu_data()))[i]); + } +#endif // USE_CUDA } } diff --git a/src/caffe/test/test_concat_layer.cpp b/src/caffe/test/test_concat_layer.cpp index 23c1e8c1d29..e74d4579256 100644 --- a/src/caffe/test/test_concat_layer.cpp +++ b/src/caffe/test/test_concat_layer.cpp @@ -105,7 +105,7 @@ TYPED_TEST(ConcatLayerTest, TestForwardTrivial) { this->blob_bottom_vec_0_.resize(1); layer.SetUp(this->blob_bottom_vec_0_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_0_, this->blob_top_vec_); - for (int i = 0; i < this->blob_bottom_0_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_0_->count(); ++i) { EXPECT_EQ(this->blob_bottom_0_->cpu_data()[i], this->blob_top_->cpu_data()[i]); } @@ -118,20 +118,20 @@ TYPED_TEST(ConcatLayerTest, TestForwardNum) { ConcatLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_1_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_1_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_vec_1_[0]->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_vec_1_[0]->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { EXPECT_EQ(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_vec_1_[0]->data_at(n, c, h, w)); } } } } - for (int n = 0; n < this->blob_bottom_vec_1_[1]->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_vec_1_[1]->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { EXPECT_EQ(this->blob_top_->data_at(n + 2, c, h, w), this->blob_bottom_vec_1_[1]->data_at(n, c, h, w)); } @@ -146,18 +146,18 @@ TYPED_TEST(ConcatLayerTest, TestForwardChannels) { ConcatLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_0_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_0_, this->blob_top_vec_); - for (int n = 0; n < this->blob_top_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_0_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { + for (int_tp n = 0; n < this->blob_top_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_0_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { EXPECT_EQ(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_vec_0_[0]->data_at(n, c, h, w)); } } } - for (int c = 0; c < this->blob_bottom_1_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { + for (int_tp c = 0; c < this->blob_bottom_1_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { EXPECT_EQ(this->blob_top_->data_at(n, c + 3, h, w), this->blob_bottom_vec_0_[1]->data_at(n, c, h, w)); } diff --git a/src/caffe/test/test_contrastive_loss_layer.cpp b/src/caffe/test/test_contrastive_loss_layer.cpp index 2fa055ee0de..9f5ba00f122 100644 --- a/src/caffe/test/test_contrastive_loss_layer.cpp +++ b/src/caffe/test/test_contrastive_loss_layer.cpp @@ -33,7 +33,7 @@ class ContrastiveLossLayerTest : public MultiDeviceTest { blob_bottom_vec_.push_back(blob_bottom_data_i_); filler.Fill(this->blob_bottom_data_j_); blob_bottom_vec_.push_back(blob_bottom_data_j_); - for (int i = 0; i < blob_bottom_y_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_y_->count(); ++i) { blob_bottom_y_->mutable_cpu_data()[i] = caffe_rng_rand() % 2; // 0 or 1 } blob_bottom_vec_.push_back(blob_bottom_y_); @@ -64,12 +64,12 @@ TYPED_TEST(ContrastiveLossLayerTest, TestForward) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // manually compute to compare const Dtype margin = layer_param.contrastive_loss_param().margin(); - const int num = this->blob_bottom_data_i_->num(); - const int channels = this->blob_bottom_data_i_->channels(); + const int_tp num = this->blob_bottom_data_i_->num(); + const int_tp channels = this->blob_bottom_data_i_->channels(); Dtype loss(0); - for (int i = 0; i < num; ++i) { + for (int_tp i = 0; i < num; ++i) { Dtype dist_sq(0); - for (int j = 0; j < channels; ++j) { + for (int_tp j = 0; j < channels; ++j) { Dtype diff = this->blob_bottom_data_i_->cpu_data()[i*channels+j] - this->blob_bottom_data_j_->cpu_data()[i*channels+j]; dist_sq += diff*diff; @@ -82,7 +82,7 @@ TYPED_TEST(ContrastiveLossLayerTest, TestForward) { } } loss /= static_cast(num) * Dtype(2); - EXPECT_NEAR(this->blob_top_loss_->cpu_data()[0], loss, 1e-6); + EXPECT_NEAR(this->blob_top_loss_->cpu_data()[0], loss, 1e-5); } TYPED_TEST(ContrastiveLossLayerTest, TestGradient) { @@ -107,12 +107,12 @@ TYPED_TEST(ContrastiveLossLayerTest, TestForwardLegacy) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // manually compute to compare const Dtype margin = layer_param.contrastive_loss_param().margin(); - const int num = this->blob_bottom_data_i_->num(); - const int channels = this->blob_bottom_data_i_->channels(); + const int_tp num = this->blob_bottom_data_i_->num(); + const int_tp channels = this->blob_bottom_data_i_->channels(); Dtype loss(0); - for (int i = 0; i < num; ++i) { + for (int_tp i = 0; i < num; ++i) { Dtype dist_sq(0); - for (int j = 0; j < channels; ++j) { + for (int_tp j = 0; j < channels; ++j) { Dtype diff = this->blob_bottom_data_i_->cpu_data()[i*channels+j] - this->blob_bottom_data_j_->cpu_data()[i*channels+j]; dist_sq += diff*diff; @@ -124,7 +124,7 @@ TYPED_TEST(ContrastiveLossLayerTest, TestForwardLegacy) { } } loss /= static_cast(num) * Dtype(2); - EXPECT_NEAR(this->blob_top_loss_->cpu_data()[0], loss, 1e-6); + EXPECT_NEAR(this->blob_top_loss_->cpu_data()[0], loss, 1e-5); } TYPED_TEST(ContrastiveLossLayerTest, TestGradientLegacy) { diff --git a/src/caffe/test/test_convolution_layer.cpp b/src/caffe/test/test_convolution_layer.cpp index 9bb19d13592..0724c1bf94c 100644 --- a/src/caffe/test/test_convolution_layer.cpp +++ b/src/caffe/test/test_convolution_layer.cpp @@ -25,31 +25,31 @@ void caffe_conv(const Blob* in, ConvolutionParameter* conv_param, const bool has_depth = (out->num_axes() == 5); if (!has_depth) { CHECK_EQ(4, out->num_axes()); } // Kernel size, stride, and pad - int kernel_h, kernel_w; + int_tp kernel_h, kernel_w; if (conv_param->has_kernel_h() || conv_param->has_kernel_w()) { kernel_h = conv_param->kernel_h(); kernel_w = conv_param->kernel_w(); } else { kernel_h = kernel_w = conv_param->kernel_size(0); } - int pad_h, pad_w; + int_tp pad_h, pad_w; if (conv_param->has_pad_h() || conv_param->has_pad_w()) { pad_h = conv_param->pad_h(); pad_w = conv_param->pad_w(); } else { pad_h = pad_w = conv_param->pad_size() ? conv_param->pad(0) : 0; } - int stride_h, stride_w; + int_tp stride_h, stride_w; if (conv_param->has_stride_h() || conv_param->has_stride_w()) { stride_h = conv_param->stride_h(); stride_w = conv_param->stride_w(); } else { stride_h = stride_w = conv_param->stride_size() ? conv_param->stride(0) : 1; } - int dilation_h, dilation_w; + int_tp dilation_h, dilation_w; dilation_h = dilation_w = conv_param->dilation_size() ? conv_param->dilation(0) : 1; - int kernel_d, pad_d, stride_d, dilation_d; + int_tp kernel_d, pad_d, stride_d, dilation_d; if (has_depth) { kernel_d = kernel_h; stride_d = stride_h; @@ -60,30 +60,30 @@ void caffe_conv(const Blob* in, ConvolutionParameter* conv_param, pad_d = 0; } // Groups - int groups = conv_param->group(); - int o_g = out->shape(1) / groups; - int k_g = in->shape(1) / groups; - int o_head, k_head; + int_tp groups = conv_param->group(); + int_tp o_g = out->shape(1) / groups; + int_tp k_g = in->shape(1) / groups; + int_tp o_head, k_head; // Convolution - vector weight_offset(4 + has_depth); - vector in_offset(4 + has_depth); - vector out_offset(4 + has_depth); + vector weight_offset(4 + has_depth); + vector in_offset(4 + has_depth); + vector out_offset(4 + has_depth); Dtype* out_data = out->mutable_cpu_data(); - for (int n = 0; n < out->shape(0); n++) { - for (int g = 0; g < groups; g++) { + for (int_tp n = 0; n < out->shape(0); n++) { + for (int_tp g = 0; g < groups; g++) { o_head = o_g * g; k_head = k_g * g; - for (int o = 0; o < o_g; o++) { - for (int k = 0; k < k_g; k++) { - for (int z = 0; z < (has_depth ? out->shape(2) : 1); z++) { - for (int y = 0; y < out->shape(2 + has_depth); y++) { - for (int x = 0; x < out->shape(3 + has_depth); x++) { - for (int r = 0; r < kernel_d; r++) { - for (int p = 0; p < kernel_h; p++) { - for (int q = 0; q < kernel_w; q++) { - int in_z = z * stride_d - pad_d + r * dilation_d; - int in_y = y * stride_h - pad_h + p * dilation_h; - int in_x = x * stride_w - pad_w + q * dilation_w; + for (int_tp o = 0; o < o_g; o++) { + for (int_tp k = 0; k < k_g; k++) { + for (int_tp z = 0; z < (has_depth ? out->shape(2) : 1); z++) { + for (int_tp y = 0; y < out->shape(2 + has_depth); y++) { + for (int_tp x = 0; x < out->shape(3 + has_depth); x++) { + for (int_tp r = 0; r < kernel_d; r++) { + for (int_tp p = 0; p < kernel_h; p++) { + for (int_tp q = 0; q < kernel_w; q++) { + int_tp in_z = z * stride_d - pad_d + r * dilation_d; + int_tp in_y = y * stride_h - pad_h + p * dilation_h; + int_tp in_x = x * stride_w - pad_w + q * dilation_w; if (in_z >= 0 && in_z < (has_depth ? in->shape(2) : 1) && in_y >= 0 && in_y < in->shape(2 + has_depth) && in_x >= 0 && in_x < in->shape(3 + has_depth)) { @@ -119,11 +119,11 @@ void caffe_conv(const Blob* in, ConvolutionParameter* conv_param, // Bias if (conv_param->bias_term()) { const Dtype* bias_data = weights[1]->cpu_data(); - for (int n = 0; n < out->shape(0); n++) { - for (int o = 0; o < out->shape(1); o++) { - for (int z = 0; z < (has_depth ? out->shape(2) : 1); z++) { - for (int y = 0; y < out->shape(2 + has_depth); y++) { - for (int x = 0; x < out->shape(3 + has_depth); x++) { + for (int_tp n = 0; n < out->shape(0); n++) { + for (int_tp o = 0; o < out->shape(1); o++) { + for (int_tp z = 0; z < (has_depth ? out->shape(2) : 1); z++) { + for (int_tp y = 0; y < out->shape(2 + has_depth); y++) { + for (int_tp x = 0; x < out->shape(3 + has_depth); x++) { out_offset[0] = n; out_offset[1] = o; if (has_depth) { out_offset[2] = z; } @@ -252,28 +252,28 @@ TYPED_TEST(ConvolutionLayerTest, TestSimpleConvolution) { this->MakeReferenceTop(this->blob_top_)); top_data = this->blob_top_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } caffe_conv(this->blob_bottom_2_, convolution_param, layer->blobs(), this->MakeReferenceTop(this->blob_top_2_)); top_data = this->blob_top_2_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } } TYPED_TEST(ConvolutionLayerTest, TestDilatedConvolution) { typedef typename TypeParam::Dtype Dtype; - vector bottom_shape; + vector bottom_shape; bottom_shape.push_back(2); bottom_shape.push_back(3); bottom_shape.push_back(8); bottom_shape.push_back(7); this->blob_bottom_vec_.push_back(this->blob_bottom_2_); this->blob_top_vec_.push_back(this->blob_top_2_); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); } LayerParameter layer_param; @@ -296,14 +296,14 @@ TYPED_TEST(ConvolutionLayerTest, TestDilatedConvolution) { this->MakeReferenceTop(this->blob_top_)); top_data = this->blob_top_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } caffe_conv(this->blob_bottom_2_, convolution_param, layer->blobs(), this->MakeReferenceTop(this->blob_top_2_)); top_data = this->blob_top_2_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } } @@ -313,30 +313,30 @@ TYPED_TEST(ConvolutionLayerTest, Test0DConvolution) { LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); - const int kNumOutput = 3; + const int_tp kNumOutput = 3; convolution_param->set_num_output(kNumOutput); convolution_param->set_axis(3); convolution_param->mutable_weight_filler()->set_type("gaussian"); convolution_param->mutable_bias_filler()->set_type("gaussian"); shared_ptr > layer( new ConvolutionLayer(layer_param)); - vector top_shape = this->blob_bottom_->shape(); + vector top_shape = this->blob_bottom_->shape(); top_shape[3] = kNumOutput; layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(top_shape, this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Check against reference convolution. - vector weight_offset(2); + vector weight_offset(2); const Blob* weight = layer->blobs()[0].get(); const Blob* bias = layer->blobs()[1].get(); - const int num = this->blob_top_->count(3); - const int dim = this->blob_top_->shape(3); - const int bottom_dim = this->blob_bottom_->shape(3); - for (int n = 0; n < num; ++n) { - for (int d = 0; d < dim; ++d) { + const int_tp num = this->blob_top_->count(3); + const int_tp dim = this->blob_top_->shape(3); + const int_tp bottom_dim = this->blob_bottom_->shape(3); + for (int_tp n = 0; n < num; ++n) { + for (int_tp d = 0; d < dim; ++d) { weight_offset[0] = d; Dtype value = bias->cpu_data()[d]; - for (int bottom_d = 0; bottom_d < bottom_dim; ++bottom_d) { + for (int_tp bottom_d = 0; bottom_d < bottom_dim; ++bottom_d) { weight_offset[1] = bottom_d; value += weight->data_at(weight_offset) * this->blob_bottom_->cpu_data()[n * bottom_dim + bottom_d]; @@ -350,7 +350,7 @@ TYPED_TEST(ConvolutionLayerTest, TestSimple3DConvolution) { typedef typename TypeParam::Dtype Dtype; this->blob_bottom_vec_.push_back(this->blob_bottom_2_); this->blob_top_vec_.push_back(this->blob_top_2_); - vector bottom_shape(5); + vector bottom_shape(5); bottom_shape[0] = this->blob_bottom_vec_[0]->shape(0); bottom_shape[1] = this->blob_bottom_vec_[0]->shape(1); bottom_shape[2] = 5; @@ -358,7 +358,7 @@ TYPED_TEST(ConvolutionLayerTest, TestSimple3DConvolution) { bottom_shape[4] = this->blob_bottom_vec_[0]->shape(3); FillerParameter filler_param; GaussianFiller filler(filler_param); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); filler.Fill(this->blob_bottom_vec_[i]); } @@ -381,14 +381,14 @@ TYPED_TEST(ConvolutionLayerTest, TestSimple3DConvolution) { this->MakeReferenceTop(this->blob_top_)); top_data = this->blob_top_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } caffe_conv(this->blob_bottom_2_, convolution_param, layer->blobs(), this->MakeReferenceTop(this->blob_top_2_)); top_data = this->blob_top_2_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } } @@ -397,7 +397,7 @@ TYPED_TEST(ConvolutionLayerTest, TestDilated3DConvolution) { typedef typename TypeParam::Dtype Dtype; this->blob_bottom_vec_.push_back(this->blob_bottom_2_); this->blob_top_vec_.push_back(this->blob_top_2_); - vector bottom_shape(5); + vector bottom_shape(5); bottom_shape[0] = this->blob_bottom_vec_[0]->shape(0); bottom_shape[1] = this->blob_bottom_vec_[0]->shape(1); bottom_shape[2] = 6; @@ -405,7 +405,7 @@ TYPED_TEST(ConvolutionLayerTest, TestDilated3DConvolution) { bottom_shape[4] = 8; FillerParameter filler_param; GaussianFiller filler(filler_param); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); filler.Fill(this->blob_bottom_vec_[i]); } @@ -428,14 +428,14 @@ TYPED_TEST(ConvolutionLayerTest, TestDilated3DConvolution) { this->MakeReferenceTop(this->blob_top_)); top_data = this->blob_top_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } caffe_conv(this->blob_bottom_2_, convolution_param, layer->blobs(), this->MakeReferenceTop(this->blob_top_2_)); top_data = this->blob_top_2_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } } @@ -462,7 +462,7 @@ TYPED_TEST(ConvolutionLayerTest, Test1x1Convolution) { this->MakeReferenceTop(this->blob_top_)); top_data = this->blob_top_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } } @@ -490,7 +490,7 @@ TYPED_TEST(ConvolutionLayerTest, TestSimpleConvolutionGroup) { this->MakeReferenceTop(this->blob_top_)); top_data = this->blob_top_->cpu_data(); ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); } } @@ -520,8 +520,8 @@ TYPED_TEST(ConvolutionLayerTest, TestSobelConvolution) { layer->blobs().resize(1); layer->blobs()[0].reset(new Blob(1, 3, 3, 3)); Dtype* weights = layer->blobs()[0]->mutable_cpu_data(); - for (int c = 0; c < 3; ++c) { - int i = c * 9; // 3 x 3 filter + for (int_tp c = 0; c < 3; ++c) { + int_tp i = c * 9; // 3 x 3 filter weights[i + 0] = -1; weights[i + 1] = 0; weights[i + 2] = 1; @@ -553,8 +553,8 @@ TYPED_TEST(ConvolutionLayerTest, TestSobelConvolution) { layer->blobs().resize(1); layer->blobs()[0].reset(new Blob(1, 3, 3, 1)); Dtype* weights_1 = layer->blobs()[0]->mutable_cpu_data(); - for (int c = 0; c < 3; ++c) { - int i = c * 3; // 3 x 1 filter + for (int_tp c = 0; c < 3; ++c) { + int_tp i = c * 3; // 3 x 1 filter weights_1[i + 0] = 1; weights_1[i + 1] = 2; weights_1[i + 2] = 1; @@ -583,23 +583,23 @@ TYPED_TEST(ConvolutionLayerTest, TestSobelConvolution) { // Test equivalence of full and separable filters. const Dtype* top_data = this->blob_top_->cpu_data(); const Dtype* sep_top_data = this->blob_top_2_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { EXPECT_NEAR(top_data[i], sep_top_data[i], 1e-4); } } TYPED_TEST(ConvolutionLayerTest, TestNDAgainst2D) { typedef typename TypeParam::Dtype Dtype; - const int kernel_h = 11; - const int kernel_w = 13; - vector bottom_shape(4); + const int_tp kernel_h = 11; + const int_tp kernel_w = 13; + vector bottom_shape(4); bottom_shape[0] = 15; bottom_shape[1] = 18; bottom_shape[2] = kernel_h * 2; bottom_shape[3] = kernel_w * 2; FillerParameter filler_param; GaussianFiller filler(filler_param); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); filler.Fill(this->blob_bottom_vec_[i]); } @@ -650,7 +650,7 @@ TYPED_TEST(ConvolutionLayerTest, TestNDAgainst2D) { // Copy pre-generated top diff into actual top diff; // do Backward and save result in backward_result_2d. ASSERT_EQ(this->blob_top_->shape(), top_diff.shape()); - caffe_copy(top_diff.count(), top_diff.cpu_data(), + caffe_cpu_copy(top_diff.count(), top_diff.cpu_data(), this->blob_top_->mutable_cpu_diff()); layer_2d.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); @@ -681,7 +681,7 @@ TYPED_TEST(ConvolutionLayerTest, TestNDAgainst2D) { // Copy pre-generated top diff into actual top diff; // do Backward and save result in backward_result_nd. ASSERT_EQ(this->blob_top_->shape(), top_diff.shape()); - caffe_copy(top_diff.count(), top_diff.cpu_data(), + caffe_cpu_copy(top_diff.count(), top_diff.cpu_data(), this->blob_top_->mutable_cpu_diff()); layer_nd.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); @@ -690,17 +690,17 @@ TYPED_TEST(ConvolutionLayerTest, TestNDAgainst2D) { backward_weight_result_nd.CopyFrom(weights, copy_diff, reshape); } ASSERT_EQ(result_nd.count(), result_2d.count()); - for (int i = 0; i < result_2d.count(); ++i) { + for (int_tp i = 0; i < result_2d.count(); ++i) { EXPECT_EQ(result_2d.cpu_data()[i], result_nd.cpu_data()[i]); } ASSERT_EQ(backward_result_nd.count(), backward_result_2d.count()); - for (int i = 0; i < backward_result_2d.count(); ++i) { + for (int_tp i = 0; i < backward_result_2d.count(); ++i) { EXPECT_EQ(backward_result_2d.cpu_diff()[i], backward_result_nd.cpu_diff()[i]); } ASSERT_EQ(backward_weight_result_nd.count(), backward_weight_result_2d.count()); - for (int i = 0; i < backward_weight_result_2d.count(); ++i) { + for (int_tp i = 0; i < backward_weight_result_2d.count(); ++i) { EXPECT_EQ(backward_weight_result_2d.cpu_diff()[i], backward_weight_result_nd.cpu_diff()[i]); } @@ -729,12 +729,12 @@ TYPED_TEST(ConvolutionLayerTest, TestDilatedGradient) { LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); - vector bottom_shape; + vector bottom_shape; bottom_shape.push_back(2); bottom_shape.push_back(3); bottom_shape.push_back(5); bottom_shape.push_back(6); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); } convolution_param->add_kernel_size(3); @@ -753,7 +753,7 @@ TYPED_TEST(ConvolutionLayerTest, TestGradient3D) { LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); - vector bottom_shape(5); + vector bottom_shape(5); bottom_shape[0] = this->blob_bottom_vec_[0]->shape(0); bottom_shape[1] = this->blob_bottom_vec_[0]->shape(1); bottom_shape[2] = 5; @@ -761,7 +761,7 @@ TYPED_TEST(ConvolutionLayerTest, TestGradient3D) { bottom_shape[4] = this->blob_bottom_vec_[0]->shape(3); FillerParameter filler_param; GaussianFiller filler(filler_param); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); filler.Fill(this->blob_bottom_vec_[i]); } @@ -857,230 +857,239 @@ class CuDNNConvolutionLayerTest : public GPUDeviceTest { TYPED_TEST_CASE(CuDNNConvolutionLayerTest, TestDtypes); TYPED_TEST(CuDNNConvolutionLayerTest, TestSetupCuDNN) { - this->blob_bottom_vec_.push_back(this->blob_bottom_2_); - this->blob_top_vec_.push_back(this->blob_top_2_); - LayerParameter layer_param; - ConvolutionParameter* convolution_param = - layer_param.mutable_convolution_param(); - convolution_param->add_kernel_size(3); - convolution_param->add_stride(2); - convolution_param->set_num_output(4); - this->blob_bottom_vec_.push_back(this->blob_bottom_2_); - this->blob_top_vec_.push_back(this->blob_top_2_); - shared_ptr > layer( - new CuDNNConvolutionLayer(layer_param)); - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_->num(), 2); - EXPECT_EQ(this->blob_top_->channels(), 4); - EXPECT_EQ(this->blob_top_->height(), 2); - EXPECT_EQ(this->blob_top_->width(), 1); - EXPECT_EQ(this->blob_top_2_->num(), 2); - EXPECT_EQ(this->blob_top_2_->channels(), 4); - EXPECT_EQ(this->blob_top_2_->height(), 2); - EXPECT_EQ(this->blob_top_2_->width(), 1); - // setting group should not change the shape - convolution_param->set_num_output(3); - convolution_param->set_group(3); - layer.reset(new CuDNNConvolutionLayer(layer_param)); - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_->num(), 2); - EXPECT_EQ(this->blob_top_->channels(), 3); - EXPECT_EQ(this->blob_top_->height(), 2); - EXPECT_EQ(this->blob_top_->width(), 1); - EXPECT_EQ(this->blob_top_2_->num(), 2); - EXPECT_EQ(this->blob_top_2_->channels(), 3); - EXPECT_EQ(this->blob_top_2_->height(), 2); - EXPECT_EQ(this->blob_top_2_->width(), 1); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + this->blob_bottom_vec_.push_back(this->blob_bottom_2_); + this->blob_top_vec_.push_back(this->blob_top_2_); + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + convolution_param->add_kernel_size(3); + convolution_param->add_stride(2); + convolution_param->set_num_output(4); + this->blob_bottom_vec_.push_back(this->blob_bottom_2_); + this->blob_top_vec_.push_back(this->blob_top_2_); + shared_ptr > layer( + new CuDNNConvolutionLayer(layer_param)); + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_->num(), 2); + EXPECT_EQ(this->blob_top_->channels(), 4); + EXPECT_EQ(this->blob_top_->height(), 2); + EXPECT_EQ(this->blob_top_->width(), 1); + EXPECT_EQ(this->blob_top_2_->num(), 2); + EXPECT_EQ(this->blob_top_2_->channels(), 4); + EXPECT_EQ(this->blob_top_2_->height(), 2); + EXPECT_EQ(this->blob_top_2_->width(), 1); + // setting group should not change the shape + convolution_param->set_num_output(3); + convolution_param->set_group(3); + layer.reset(new CuDNNConvolutionLayer(layer_param)); + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_->num(), 2); + EXPECT_EQ(this->blob_top_->channels(), 3); + EXPECT_EQ(this->blob_top_->height(), 2); + EXPECT_EQ(this->blob_top_->width(), 1); + EXPECT_EQ(this->blob_top_2_->num(), 2); + EXPECT_EQ(this->blob_top_2_->channels(), 3); + EXPECT_EQ(this->blob_top_2_->height(), 2); + EXPECT_EQ(this->blob_top_2_->width(), 1); + } } TYPED_TEST(CuDNNConvolutionLayerTest, TestSimpleConvolutionCuDNN) { - this->blob_bottom_vec_.push_back(this->blob_bottom_2_); - this->blob_top_vec_.push_back(this->blob_top_2_); - LayerParameter layer_param; - ConvolutionParameter* convolution_param = - layer_param.mutable_convolution_param(); - convolution_param->add_kernel_size(3); - convolution_param->add_stride(2); - convolution_param->set_num_output(4); - convolution_param->mutable_weight_filler()->set_type("gaussian"); - convolution_param->mutable_bias_filler()->set_type("constant"); - convolution_param->mutable_bias_filler()->set_value(0.1); - shared_ptr > layer( - new CuDNNConvolutionLayer(layer_param)); - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Check against reference convolution. - const TypeParam* top_data; - const TypeParam* ref_top_data; - caffe_conv(this->blob_bottom_, convolution_param, layer->blobs(), - this->MakeReferenceTop(this->blob_top_)); - top_data = this->blob_top_->cpu_data(); - ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { - EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); - } - caffe_conv(this->blob_bottom_2_, convolution_param, layer->blobs(), - this->MakeReferenceTop(this->blob_top_2_)); - top_data = this->blob_top_2_->cpu_data(); - ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { - EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + this->blob_bottom_vec_.push_back(this->blob_bottom_2_); + this->blob_top_vec_.push_back(this->blob_top_2_); + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + convolution_param->add_kernel_size(3); + convolution_param->add_stride(2); + convolution_param->set_num_output(4); + convolution_param->mutable_weight_filler()->set_type("gaussian"); + convolution_param->mutable_bias_filler()->set_type("constant"); + convolution_param->mutable_bias_filler()->set_value(0.1); + shared_ptr > layer( + new CuDNNConvolutionLayer(layer_param)); + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Check against reference convolution. + const TypeParam* top_data; + const TypeParam* ref_top_data; + caffe_conv(this->blob_bottom_, convolution_param, layer->blobs(), + this->MakeReferenceTop(this->blob_top_)); + top_data = this->blob_top_->cpu_data(); + ref_top_data = this->ref_blob_top_->cpu_data(); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); + } + caffe_conv(this->blob_bottom_2_, convolution_param, layer->blobs(), + this->MakeReferenceTop(this->blob_top_2_)); + top_data = this->blob_top_2_->cpu_data(); + ref_top_data = this->ref_blob_top_->cpu_data(); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); + } } } TYPED_TEST(CuDNNConvolutionLayerTest, TestSimpleConvolutionGroupCuDNN) { - LayerParameter layer_param; - ConvolutionParameter* convolution_param = - layer_param.mutable_convolution_param(); - convolution_param->add_kernel_size(3); - convolution_param->add_stride(2); - convolution_param->set_num_output(3); - convolution_param->set_group(3); - convolution_param->mutable_weight_filler()->set_type("gaussian"); - convolution_param->mutable_bias_filler()->set_type("constant"); - convolution_param->mutable_bias_filler()->set_value(0.1); - shared_ptr > layer( - new CuDNNConvolutionLayer(layer_param)); - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Check against reference convolution. - const TypeParam* top_data; - const TypeParam* ref_top_data; - caffe_conv(this->blob_bottom_, convolution_param, layer->blobs(), - this->MakeReferenceTop(this->blob_top_)); - top_data = this->blob_top_->cpu_data(); - ref_top_data = this->ref_blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { - EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + convolution_param->add_kernel_size(3); + convolution_param->add_stride(2); + convolution_param->set_num_output(3); + convolution_param->set_group(3); + convolution_param->mutable_weight_filler()->set_type("gaussian"); + convolution_param->mutable_bias_filler()->set_type("constant"); + convolution_param->mutable_bias_filler()->set_value(0.1); + shared_ptr > layer( + new CuDNNConvolutionLayer(layer_param)); + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Check against reference convolution. + const TypeParam* top_data; + const TypeParam* ref_top_data; + caffe_conv(this->blob_bottom_, convolution_param, layer->blobs(), + this->MakeReferenceTop(this->blob_top_)); + top_data = this->blob_top_->cpu_data(); + ref_top_data = this->ref_blob_top_->cpu_data(); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + EXPECT_NEAR(top_data[i], ref_top_data[i], 1e-4); + } } } TYPED_TEST(CuDNNConvolutionLayerTest, TestSobelConvolutionCuDNN) { - // Test separable convolution by computing the Sobel operator - // as a single filter then comparing the result - // as the convolution of two rectangular filters. - - // Fill bottoms with identical Gaussian noise. - shared_ptr > filler; - FillerParameter filler_param; - filler_param.set_value(1.); - filler.reset(new GaussianFiller(filler_param)); - filler->Fill(this->blob_bottom_); - this->blob_bottom_2_->CopyFrom(*this->blob_bottom_); - // Compute Sobel G_x operator as 3 x 3 convolution. - LayerParameter layer_param; - ConvolutionParameter* convolution_param = - layer_param.mutable_convolution_param(); - convolution_param->add_kernel_size(3); - convolution_param->add_stride(2); - convolution_param->set_num_output(1); - convolution_param->set_bias_term(false); - shared_ptr > layer( - new CuDNNConvolutionLayer(layer_param)); - layer->blobs().resize(1); - layer->blobs()[0].reset(new Blob(1, 3, 3, 3)); - TypeParam* weights = layer->blobs()[0]->mutable_cpu_data(); - for (int c = 0; c < 3; ++c) { - int i = c * 9; // 3 x 3 filter - weights[i + 0] = -1; - weights[i + 1] = 0; - weights[i + 2] = 1; - weights[i + 3] = -2; - weights[i + 4] = 0; - weights[i + 5] = 2; - weights[i + 6] = -1; - weights[i + 7] = 0; - weights[i + 8] = 1; - } - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Compute Sobel G_x operator as separable 3 x 1 and 1 x 3 convolutions. - // (1) the [1 2 1] column filter - vector*> sep_blob_bottom_vec; - vector*> sep_blob_top_vec; - shared_ptr > blob_sep(new Blob()); - sep_blob_bottom_vec.push_back(this->blob_bottom_2_); - sep_blob_top_vec.push_back(this->blob_top_2_); - convolution_param->clear_kernel_size(); - convolution_param->clear_stride(); - convolution_param->set_kernel_h(3); - convolution_param->set_kernel_w(1); - convolution_param->set_stride_h(2); - convolution_param->set_stride_w(1); - convolution_param->set_num_output(1); - convolution_param->set_bias_term(false); - layer.reset(new CuDNNConvolutionLayer(layer_param)); - layer->blobs().resize(1); - layer->blobs()[0].reset(new Blob(1, 3, 3, 1)); - TypeParam* weights_1 = layer->blobs()[0]->mutable_cpu_data(); - for (int c = 0; c < 3; ++c) { - int i = c * 3; // 3 x 1 filter - weights_1[i + 0] = 1; - weights_1[i + 1] = 2; - weights_1[i + 2] = 1; - } - layer->SetUp(sep_blob_bottom_vec, sep_blob_top_vec); - layer->Forward(sep_blob_bottom_vec, sep_blob_top_vec); - // (2) the [-1 0 1] row filter - blob_sep->CopyFrom(*this->blob_top_2_, false, true); - sep_blob_bottom_vec.clear(); - sep_blob_bottom_vec.push_back(blob_sep.get()); - convolution_param->set_kernel_h(1); - convolution_param->set_kernel_w(3); - convolution_param->set_stride_h(1); - convolution_param->set_stride_w(2); - convolution_param->set_num_output(1); - convolution_param->set_bias_term(false); - layer.reset(new CuDNNConvolutionLayer(layer_param)); - layer->blobs().resize(1); - layer->blobs()[0].reset(new Blob(1, 1, 1, 3)); - TypeParam* weights_2 = layer->blobs()[0]->mutable_cpu_data(); - weights_2[0] = -1; - weights_2[1] = 0; - weights_2[2] = 1; - layer->SetUp(sep_blob_bottom_vec, sep_blob_top_vec); - layer->Forward(sep_blob_bottom_vec, sep_blob_top_vec); - // Test equivalence of full and separable filters. - const TypeParam* top_data = this->blob_top_->cpu_data(); - const TypeParam* sep_top_data = this->blob_top_2_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { - EXPECT_NEAR(top_data[i], sep_top_data[i], 1e-4); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + // Test separable convolution by computing the Sobel operator + // as a single filter then comparing the result + // as the convolution of two rectangular filters. + // Fill bottoms with identical Gaussian noise. + shared_ptr > filler; + FillerParameter filler_param; + filler_param.set_value(1.); + filler.reset(new GaussianFiller(filler_param)); + filler->Fill(this->blob_bottom_); + this->blob_bottom_2_->CopyFrom(*this->blob_bottom_); + // Compute Sobel G_x operator as 3 x 3 convolution. + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + convolution_param->add_kernel_size(3); + convolution_param->add_stride(2); + convolution_param->set_num_output(1); + convolution_param->set_bias_term(false); + shared_ptr > layer( + new CuDNNConvolutionLayer(layer_param)); + layer->blobs().resize(1); + layer->blobs()[0].reset(new Blob(1, 3, 3, 3)); + TypeParam* weights = layer->blobs()[0]->mutable_cpu_data(); + for (int_tp c = 0; c < 3; ++c) { + int_tp i = c * 9; // 3 x 3 filter + weights[i + 0] = -1; + weights[i + 1] = 0; + weights[i + 2] = 1; + weights[i + 3] = -2; + weights[i + 4] = 0; + weights[i + 5] = 2; + weights[i + 6] = -1; + weights[i + 7] = 0; + weights[i + 8] = 1; + } + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Compute Sobel G_x operator as separable 3 x 1 and 1 x 3 convolutions. + // (1) the [1 2 1] column filter + vector*> sep_blob_bottom_vec; + vector*> sep_blob_top_vec; + shared_ptr > blob_sep(new Blob()); + sep_blob_bottom_vec.push_back(this->blob_bottom_2_); + sep_blob_top_vec.push_back(this->blob_top_2_); + convolution_param->clear_kernel_size(); + convolution_param->clear_stride(); + convolution_param->set_kernel_h(3); + convolution_param->set_kernel_w(1); + convolution_param->set_stride_h(2); + convolution_param->set_stride_w(1); + convolution_param->set_num_output(1); + convolution_param->set_bias_term(false); + layer.reset(new CuDNNConvolutionLayer(layer_param)); + layer->blobs().resize(1); + layer->blobs()[0].reset(new Blob(1, 3, 3, 1)); + TypeParam* weights_1 = layer->blobs()[0]->mutable_cpu_data(); + for (int_tp c = 0; c < 3; ++c) { + int_tp i = c * 3; // 3 x 1 filter + weights_1[i + 0] = 1; + weights_1[i + 1] = 2; + weights_1[i + 2] = 1; + } + layer->SetUp(sep_blob_bottom_vec, sep_blob_top_vec); + layer->Forward(sep_blob_bottom_vec, sep_blob_top_vec); + // (2) the [-1 0 1] row filter + blob_sep->CopyFrom(*this->blob_top_2_, false, true); + sep_blob_bottom_vec.clear(); + sep_blob_bottom_vec.push_back(blob_sep.get()); + convolution_param->set_kernel_h(1); + convolution_param->set_kernel_w(3); + convolution_param->set_stride_h(1); + convolution_param->set_stride_w(2); + convolution_param->set_num_output(1); + convolution_param->set_bias_term(false); + layer.reset(new CuDNNConvolutionLayer(layer_param)); + layer->blobs().resize(1); + layer->blobs()[0].reset(new Blob(1, 1, 1, 3)); + TypeParam* weights_2 = layer->blobs()[0]->mutable_cpu_data(); + weights_2[0] = -1; + weights_2[1] = 0; + weights_2[2] = 1; + layer->SetUp(sep_blob_bottom_vec, sep_blob_top_vec); + layer->Forward(sep_blob_bottom_vec, sep_blob_top_vec); + // Test equivalence of full and separable filters. + const TypeParam* top_data = this->blob_top_->cpu_data(); + const TypeParam* sep_top_data = this->blob_top_2_->cpu_data(); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + EXPECT_NEAR(top_data[i], sep_top_data[i], 1e-4); + } } } TYPED_TEST(CuDNNConvolutionLayerTest, TestGradientCuDNN) { - LayerParameter layer_param; - ConvolutionParameter* convolution_param = - layer_param.mutable_convolution_param(); - this->blob_bottom_vec_.push_back(this->blob_bottom_2_); - this->blob_top_vec_.push_back(this->blob_top_2_); - convolution_param->add_kernel_size(3); - convolution_param->add_stride(2); - convolution_param->set_num_output(2); - convolution_param->mutable_weight_filler()->set_type("gaussian"); - convolution_param->mutable_bias_filler()->set_type("gaussian"); - CuDNNConvolutionLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + this->blob_bottom_vec_.push_back(this->blob_bottom_2_); + this->blob_top_vec_.push_back(this->blob_top_2_); + convolution_param->add_kernel_size(3); + convolution_param->add_stride(2); + convolution_param->set_num_output(2); + convolution_param->mutable_weight_filler()->set_type("gaussian"); + convolution_param->mutable_bias_filler()->set_type("gaussian"); + CuDNNConvolutionLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } TYPED_TEST(CuDNNConvolutionLayerTest, TestGradientGroupCuDNN) { - LayerParameter layer_param; - ConvolutionParameter* convolution_param = - layer_param.mutable_convolution_param(); - convolution_param->add_kernel_size(3); - convolution_param->add_stride(2); - convolution_param->set_num_output(3); - convolution_param->set_group(3); - convolution_param->mutable_weight_filler()->set_type("gaussian"); - convolution_param->mutable_bias_filler()->set_type("gaussian"); - CuDNNConvolutionLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + convolution_param->add_kernel_size(3); + convolution_param->add_stride(2); + convolution_param->set_num_output(3); + convolution_param->set_group(3); + convolution_param->mutable_weight_filler()->set_type("gaussian"); + convolution_param->mutable_bias_filler()->set_type("gaussian"); + CuDNNConvolutionLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } - #endif - } // namespace caffe diff --git a/src/caffe/test/test_convolution_nd_layer.cpp b/src/caffe/test/test_convolution_nd_layer.cpp new file mode 100644 index 00000000000..6fe20e52822 --- /dev/null +++ b/src/caffe/test/test_convolution_nd_layer.cpp @@ -0,0 +1,196 @@ +#include +#include + +#include "gtest/gtest.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/layers/conv_layer.hpp" +#include "caffe/test/test_caffe_main.hpp" +#include "caffe/util/math_functions.hpp" + +#ifndef CPU_ONLY // CPU-GPU test + +namespace caffe { + +template +class ConvolutionNDLayerTest : public GPUDeviceTest { + protected: + ConvolutionNDLayerTest() + : blob_bottom_(new Blob()), + blob_top_(new Blob()) { + } + + virtual void SetUp() { + BlobShape shape; + shape.add_dim(1); // Batch + shape.add_dim(1); // Channels + shape.add_dim(5); // Depth + shape.add_dim(5); // Height + shape.add_dim(5); // Width + blob_bottom_->Reshape(shape); + + shape.add_dim(1); // Batch + shape.add_dim(1); // Channels + shape.add_dim(1); // Depth + shape.add_dim(1); // Height + shape.add_dim(1); // Width + blob_top_->Reshape(shape); + + // fill the values + blob_bottom_vec_.push_back(blob_bottom_); + blob_top_vec_.push_back(blob_top_); + } + + virtual ~ConvolutionNDLayerTest() { + delete blob_bottom_; + delete blob_top_; + } + + void TestForward() { + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + + convolution_param->add_kernel_size(3); + convolution_param->add_kernel_size(3); + convolution_param->add_kernel_size(3); + + convolution_param->add_dilation(2); + convolution_param->add_dilation(2); + convolution_param->add_dilation(2); + + convolution_param->set_num_output(1); + + convolution_param->set_axis(1); + + convolution_param->mutable_weight_filler()->set_type("constant"); + convolution_param->mutable_weight_filler()->set_value(1); + convolution_param->mutable_bias_filler()->set_type("constant"); + convolution_param->mutable_bias_filler()->set_value(0); + + ConvolutionLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + int_tp d = blob_bottom_->shape(2); + int_tp h = blob_bottom_->shape(3); + int_tp w = blob_bottom_->shape(4); + + TypeParam *bottom_data = blob_bottom_->mutable_cpu_data(); + + TypeParam checksum = 0; + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + bottom_data[cw + ch * w + cd * w * h] = + cw + ch * w + cd * w * h; + if (cw % 2 == 0 && ch % 2 == 0 && cd % 2 == 0) { + checksum += cw + ch * w + cd * w * h; + } + } + } + } + + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + + const TypeParam *top_data = blob_top_->cpu_data(); + + EXPECT_EQ(checksum, top_data[0]); + } + + void TestBackward() { + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + + convolution_param->add_kernel_size(3); + convolution_param->add_kernel_size(3); + convolution_param->add_kernel_size(3); + + convolution_param->add_dilation(2); + convolution_param->add_dilation(2); + convolution_param->add_dilation(2); + + convolution_param->set_num_output(1); + + convolution_param->set_axis(1); + + convolution_param->mutable_weight_filler()->set_type("constant"); + convolution_param->mutable_weight_filler()->set_value(1); + convolution_param->mutable_bias_filler()->set_type("constant"); + convolution_param->mutable_bias_filler()->set_value(0); + + ConvolutionLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + TypeParam *top_diff = blob_top_->mutable_cpu_diff(); + + *top_diff = 1; + + std::vector prop_down; + prop_down.push_back(true); + + layer.Backward(this->blob_top_vec_, prop_down, this->blob_bottom_vec_); + + const TypeParam *bottom_diff = blob_bottom_->cpu_diff(); + + int_tp d = blob_bottom_->shape(2); + int_tp h = blob_bottom_->shape(3); + int_tp w = blob_bottom_->shape(4); + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + if (cw % 2 == 0 && ch % 2 == 0 && cd % 2 == 0) { + EXPECT_EQ(1, bottom_diff[cw + ch * w + cd * w * h]); + } + } + } + } + } + + Blob* const blob_bottom_; + Blob* const blob_top_; + + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +TYPED_TEST_CASE(ConvolutionNDLayerTest, TestDtypes); + +TYPED_TEST(ConvolutionNDLayerTest, TestSetup) { + LayerParameter layer_param; + ConvolutionParameter* convolution_param = + layer_param.mutable_convolution_param(); + + convolution_param->add_kernel_size(3); + convolution_param->add_kernel_size(3); + convolution_param->add_kernel_size(3); + + convolution_param->add_dilation(2); + convolution_param->add_dilation(2); + convolution_param->add_dilation(2); + + convolution_param->set_num_output(4); + + + ConvolutionLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + EXPECT_EQ(1, this->blob_top_->shape(2)); + EXPECT_EQ(1, this->blob_top_->shape(3)); + EXPECT_EQ(1, this->blob_top_->shape(4)); +} + +TYPED_TEST(ConvolutionNDLayerTest, TestForward) { + this->TestForward(); +} + +TYPED_TEST(ConvolutionNDLayerTest, TestBackward) { + this->TestBackward(); +} + +} // namespace caffe +#endif // !CPU_ONLY diff --git a/src/caffe/test/test_data_layer.cpp b/src/caffe/test/test_data_layer.cpp index 3e8d113d918..c577a0540c9 100644 --- a/src/caffe/test/test_data_layer.cpp +++ b/src/caffe/test/test_data_layer.cpp @@ -46,15 +46,15 @@ class DataLayerTest : public MultiDeviceTest { scoped_ptr db(db::GetDB(backend)); db->Open(*filename_, db::NEW); scoped_ptr txn(db->NewTransaction()); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { Datum datum; datum.set_label(i); datum.set_channels(2); datum.set_height(3); datum.set_width(4); std::string* data = datum.mutable_data(); - for (int j = 0; j < 24; ++j) { - int datum = unique_pixels ? j : i; + for (int_tp j = 0; j < 24; ++j) { + int_tp datum = unique_pixels ? j : i; data->push_back(static_cast(datum)); } stringstream ss; @@ -91,13 +91,13 @@ class DataLayerTest : public MultiDeviceTest { EXPECT_EQ(blob_top_label_->height(), 1); EXPECT_EQ(blob_top_label_->width(), 1); - for (int iter = 0; iter < 100; ++iter) { + for (int_tp iter = 0; iter < 100; ++iter) { layer.Forward(blob_bottom_vec_, blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, blob_top_label_->cpu_data()[i]); } - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 24; ++j) { + for (int_tp i = 0; i < 5; ++i) { + for (int_tp j = 0; j < 24; ++j) { EXPECT_EQ(scale * i, blob_top_data_->cpu_data()[i * 24 + j]) << "debug: iter " << iter << " i " << i << " j " << j; } @@ -106,21 +106,22 @@ class DataLayerTest : public MultiDeviceTest { } void TestReshape(DataParameter_DB backend) { - const int num_inputs = 5; + const int_tp num_inputs = 5; // Save data of varying shapes. LOG(INFO) << "Using temporary dataset " << *filename_; scoped_ptr db(db::GetDB(backend)); db->Open(*filename_, db::NEW); scoped_ptr txn(db->NewTransaction()); - for (int i = 0; i < num_inputs; ++i) { + for (int_tp i = 0; i < num_inputs; ++i) { Datum datum; datum.set_label(i); datum.set_channels(2); datum.set_height(i % 2 + 1); datum.set_width(i % 4 + 1); std::string* data = datum.mutable_data(); - const int data_size = datum.channels() * datum.height() * datum.width(); - for (int j = 0; j < data_size; ++j) { + const int_tp data_size = datum.channels() * datum.height() + * datum.width(); + for (int_tp j = 0; j < data_size; ++j) { data->push_back(static_cast(j)); } stringstream ss; @@ -149,19 +150,19 @@ class DataLayerTest : public MultiDeviceTest { EXPECT_EQ(blob_top_label_->height(), 1); EXPECT_EQ(blob_top_label_->width(), 1); - for (int iter = 0; iter < num_inputs; ++iter) { + for (int_tp iter = 0; iter < num_inputs; ++iter) { layer.Forward(blob_bottom_vec_, blob_top_vec_); EXPECT_EQ(blob_top_data_->height(), iter % 2 + 1); EXPECT_EQ(blob_top_data_->width(), iter % 4 + 1); EXPECT_EQ(iter, blob_top_label_->cpu_data()[0]); - const int channels = blob_top_data_->channels(); - const int height = blob_top_data_->height(); - const int width = blob_top_data_->width(); - for (int c = 0; c < channels; ++c) { - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { - const int idx = (c * height + h) * width + w; - EXPECT_EQ(idx, static_cast(blob_top_data_->cpu_data()[idx])) + const int_tp channels = blob_top_data_->channels(); + const int_tp height = blob_top_data_->height(); + const int_tp width = blob_top_data_->width(); + for (int_tp c = 0; c < channels; ++c) { + for (int_tp h = 0; h < height; ++h) { + for (int_tp w = 0; w < width; ++w) { + const int_tp idx = (c * height + h) * width + w; + EXPECT_EQ(idx, static_cast(blob_top_data_->cpu_data()[idx])) << "debug: iter " << iter << " c " << c << " h " << h << " w " << w; } @@ -174,7 +175,7 @@ class DataLayerTest : public MultiDeviceTest { const Dtype scale = 3; LayerParameter param; param.set_phase(phase); - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); DataParameter* data_param = param.mutable_data_param(); data_param->set_batch_size(5); @@ -197,14 +198,14 @@ class DataLayerTest : public MultiDeviceTest { EXPECT_EQ(blob_top_label_->height(), 1); EXPECT_EQ(blob_top_label_->width(), 1); - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer.Forward(blob_bottom_vec_, blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, blob_top_label_->cpu_data()[i]); } - int num_with_center_value = 0; - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 2; ++j) { + int_tp num_with_center_value = 0; + for (int_tp i = 0; i < 5; ++i) { + for (int_tp j = 0; j < 2; ++j) { const Dtype center_value = scale * (j ? 17 : 5); num_with_center_value += (center_value == blob_top_data_->cpu_data()[i * 2 + j]); @@ -238,19 +239,19 @@ class DataLayerTest : public MultiDeviceTest { transform_param->set_mirror(true); // Get crop sequence with Caffe seed 1701. - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); vector > crop_sequence; { DataLayer layer1(param); layer1.SetUp(blob_bottom_vec_, blob_top_vec_); - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer1.Forward(blob_bottom_vec_, blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, blob_top_label_->cpu_data()[i]); } vector iter_crop_sequence; - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 2; ++j) { + for (int_tp i = 0; i < 5; ++i) { + for (int_tp j = 0; j < 2; ++j) { iter_crop_sequence.push_back( blob_top_data_->cpu_data()[i * 2 + j]); } @@ -261,16 +262,16 @@ class DataLayerTest : public MultiDeviceTest { // Get crop sequence after reseeding Caffe with 1701. // Check that the sequence is the same as the original. - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); DataLayer layer2(param); layer2.SetUp(blob_bottom_vec_, blob_top_vec_); - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer2.Forward(blob_bottom_vec_, blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, blob_top_label_->cpu_data()[i]); } - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 2; ++j) { + for (int_tp i = 0; i < 5; ++i) { + for (int_tp j = 0; j < 2; ++j) { EXPECT_EQ(crop_sequence[iter][i * 2 + j], blob_top_data_->cpu_data()[i * 2 + j]) << "debug: iter " << iter << " i " << i << " j " << j; @@ -293,20 +294,20 @@ class DataLayerTest : public MultiDeviceTest { transform_param->set_mirror(true); // Get crop sequence with Caffe seed 1701, srand seed 1701. - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); srand(seed_); vector > crop_sequence; { DataLayer layer1(param); layer1.SetUp(blob_bottom_vec_, blob_top_vec_); - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer1.Forward(blob_bottom_vec_, blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, blob_top_label_->cpu_data()[i]); } vector iter_crop_sequence; - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 2; ++j) { + for (int_tp i = 0; i < 5; ++i) { + for (int_tp j = 0; j < 2; ++j) { iter_crop_sequence.push_back( blob_top_data_->cpu_data()[i * 2 + j]); } @@ -320,14 +321,14 @@ class DataLayerTest : public MultiDeviceTest { srand(seed_); DataLayer layer2(param); layer2.SetUp(blob_bottom_vec_, blob_top_vec_); - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer2.Forward(blob_bottom_vec_, blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, blob_top_label_->cpu_data()[i]); } - int num_sequence_matches = 0; - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 2; ++j) { + int_tp num_sequence_matches = 0; + for (int_tp i = 0; i < 5; ++i) { + for (int_tp j = 0; j < 2; ++j) { num_sequence_matches += (crop_sequence[iter][i * 2 + j] == blob_top_data_->cpu_data()[i * 2 + j]); } @@ -344,7 +345,7 @@ class DataLayerTest : public MultiDeviceTest { Blob* const blob_top_label_; vector*> blob_bottom_vec_; vector*> blob_top_vec_; - int seed_; + int_tp seed_; }; TYPED_TEST_CASE(DataLayerTest, TestDtypesAndDevices); diff --git a/src/caffe/test/test_data_transformer.cpp b/src/caffe/test/test_data_transformer.cpp index 6103918fda1..c78ea0eb916 100644 --- a/src/caffe/test/test_data_transformer.cpp +++ b/src/caffe/test/test_data_transformer.cpp @@ -16,16 +16,16 @@ namespace caffe { -void FillDatum(const int label, const int channels, const int height, - const int width, const bool unique_pixels, Datum * datum) { +void FillDatum(const int_tp label, const int_tp channels, const int_tp height, + const int_tp width, const bool unique_pixels, Datum * datum) { datum->set_label(label); datum->set_channels(channels); datum->set_height(height); datum->set_width(width); - int size = channels * height * width; + int_tp size = channels * height * width; std::string* data = datum->mutable_data(); - for (int j = 0; j < size; ++j) { - int datum = unique_pixels ? j : label; + for (int_tp j = 0; j < size; ++j) { + int_tp datum = unique_pixels ? j : label; data->push_back(static_cast(datum)); } } @@ -34,15 +34,16 @@ template class DataTransformTest : public ::testing::Test { protected: DataTransformTest() - : seed_(1701), + : seed_(1704), num_iter_(10) {} - int NumSequenceMatches(const TransformationParameter transform_param, + int_tp NumSequenceMatches(const TransformationParameter transform_param, const Datum& datum, Phase phase) { // Get crop sequence with Caffe seed 1701. - DataTransformer transformer(transform_param, phase); - const int crop_size = transform_param.crop_size(); - Caffe::set_random_seed(seed_); + DataTransformer transformer(transform_param, phase, + Caffe::GetDefaultDevice()); + const int_tp crop_size = transform_param.crop_size(); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); transformer.InitRand(); Blob blob(1, datum.channels(), datum.height(), datum.width()); if (transform_param.crop_size() > 0) { @@ -50,28 +51,28 @@ class DataTransformTest : public ::testing::Test { } vector > crop_sequence; - for (int iter = 0; iter < this->num_iter_; ++iter) { + for (int_tp iter = 0; iter < this->num_iter_; ++iter) { vector iter_crop_sequence; transformer.Transform(datum, &blob); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { iter_crop_sequence.push_back(blob.cpu_data()[j]); } crop_sequence.push_back(iter_crop_sequence); } // Check if the sequence differs from the previous - int num_sequence_matches = 0; - for (int iter = 0; iter < this->num_iter_; ++iter) { + int_tp num_sequence_matches = 0; + for (int_tp iter = 0; iter < this->num_iter_; ++iter) { vector iter_crop_sequence = crop_sequence[iter]; transformer.Transform(datum, &blob); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { num_sequence_matches += (crop_sequence[iter][j] == blob.cpu_data()[j]); } } return num_sequence_matches; } - int seed_; - int num_iter_; + int_tp seed_; + int_tp num_iter_; }; TYPED_TEST_CASE(DataTransformTest, TestDtypes); @@ -79,22 +80,23 @@ TYPED_TEST_CASE(DataTransformTest, TestDtypes); TYPED_TEST(DataTransformTest, TestEmptyTransform) { TransformationParameter transform_param; const bool unique_pixels = false; // all pixels the same equal to label - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); Blob blob(1, channels, height, width); - DataTransformer transformer(transform_param, TEST); + DataTransformer transformer(transform_param, TEST, + Caffe::GetDefaultDevice()); transformer.InitRand(); transformer.Transform(datum, &blob); EXPECT_EQ(blob.num(), 1); EXPECT_EQ(blob.channels(), datum.channels()); EXPECT_EQ(blob.height(), datum.height()); EXPECT_EQ(blob.width(), datum.width()); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { EXPECT_EQ(blob.cpu_data()[j], label); } } @@ -102,22 +104,23 @@ TYPED_TEST(DataTransformTest, TestEmptyTransform) { TYPED_TEST(DataTransformTest, TestEmptyTransformUniquePixels) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); Blob blob(1, 3, 4, 5); - DataTransformer transformer(transform_param, TEST); + DataTransformer transformer(transform_param, TEST, + Caffe::GetDefaultDevice()); transformer.InitRand(); transformer.Transform(datum, &blob); EXPECT_EQ(blob.num(), 1); EXPECT_EQ(blob.channels(), datum.channels()); EXPECT_EQ(blob.height(), datum.height()); EXPECT_EQ(blob.width(), datum.width()); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { EXPECT_EQ(blob.cpu_data()[j], j); } } @@ -125,25 +128,26 @@ TYPED_TEST(DataTransformTest, TestEmptyTransformUniquePixels) { TYPED_TEST(DataTransformTest, TestCropSize) { TransformationParameter transform_param; const bool unique_pixels = false; // all pixels the same equal to label - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int crop_size = 2; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp crop_size = 2; transform_param.set_crop_size(crop_size); Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); - DataTransformer transformer(transform_param, TEST); + DataTransformer transformer(transform_param, TEST, + Caffe::GetDefaultDevice()); transformer.InitRand(); Blob blob(1, channels, crop_size, crop_size); - for (int iter = 0; iter < this->num_iter_; ++iter) { + for (int_tp iter = 0; iter < this->num_iter_; ++iter) { transformer.Transform(datum, &blob); EXPECT_EQ(blob.num(), 1); EXPECT_EQ(blob.channels(), datum.channels()); EXPECT_EQ(blob.height(), crop_size); EXPECT_EQ(blob.width(), crop_size); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { EXPECT_EQ(blob.cpu_data()[j], label); } } @@ -152,86 +156,86 @@ TYPED_TEST(DataTransformTest, TestCropSize) { TYPED_TEST(DataTransformTest, TestCropTrain) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int crop_size = 2; - const int size = channels * crop_size * crop_size; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp crop_size = 2; + const int_tp size = channels * crop_size * crop_size; transform_param.set_crop_size(crop_size); Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); - int num_matches = this->NumSequenceMatches(transform_param, datum, TRAIN); + int_tp num_matches = this->NumSequenceMatches(transform_param, datum, TRAIN); EXPECT_LT(num_matches, size * this->num_iter_); } TYPED_TEST(DataTransformTest, TestCropTest) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int crop_size = 2; - const int size = channels * crop_size * crop_size; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp crop_size = 2; + const int_tp size = channels * crop_size * crop_size; transform_param.set_crop_size(crop_size); Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); - int num_matches = this->NumSequenceMatches(transform_param, datum, TEST); + int_tp num_matches = this->NumSequenceMatches(transform_param, datum, TEST); EXPECT_EQ(num_matches, size * this->num_iter_); } TYPED_TEST(DataTransformTest, TestMirrorTrain) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int size = channels * height * width; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp size = channels * height * width; transform_param.set_mirror(true); Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); - int num_matches = this->NumSequenceMatches(transform_param, datum, TRAIN); + int_tp num_matches = this->NumSequenceMatches(transform_param, datum, TRAIN); EXPECT_LT(num_matches, size * this->num_iter_); } TYPED_TEST(DataTransformTest, TestMirrorTest) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int size = channels * height * width; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp size = channels * height * width; transform_param.set_mirror(true); Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); - int num_matches = this->NumSequenceMatches(transform_param, datum, TEST); + int_tp num_matches = this->NumSequenceMatches(transform_param, datum, TEST); EXPECT_LT(num_matches, size * this->num_iter_); } TYPED_TEST(DataTransformTest, TestCropMirrorTrain) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int crop_size = 2; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp crop_size = 2; Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); transform_param.set_crop_size(crop_size); - int num_matches_crop = this->NumSequenceMatches( + int_tp num_matches_crop = this->NumSequenceMatches( transform_param, datum, TRAIN); transform_param.set_mirror(true); - int num_matches_crop_mirror = + int_tp num_matches_crop_mirror = this->NumSequenceMatches(transform_param, datum, TRAIN); // When doing crop and mirror we expect less num_matches than just crop EXPECT_LE(num_matches_crop_mirror, num_matches_crop); @@ -240,19 +244,20 @@ TYPED_TEST(DataTransformTest, TestCropMirrorTrain) { TYPED_TEST(DataTransformTest, TestCropMirrorTest) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int crop_size = 2; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp crop_size = 2; Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); transform_param.set_crop_size(crop_size); - int num_matches_crop = this->NumSequenceMatches(transform_param, datum, TEST); + int_tp num_matches_crop = this->NumSequenceMatches(transform_param, + datum, TEST); transform_param.set_mirror(true); - int num_matches_crop_mirror = + int_tp num_matches_crop_mirror = this->NumSequenceMatches(transform_param, datum, TEST); // When doing crop and mirror we expect less num_matches than just crop EXPECT_LT(num_matches_crop_mirror, num_matches_crop); @@ -262,20 +267,21 @@ TYPED_TEST(DataTransformTest, TestCropMirrorTest) { TYPED_TEST(DataTransformTest, TestMeanValue) { TransformationParameter transform_param; const bool unique_pixels = false; // pixels are equal to label - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int mean_value = 2; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp mean_value = 2; transform_param.add_mean_value(mean_value); Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); Blob blob(1, channels, height, width); - DataTransformer transformer(transform_param, TEST); + DataTransformer transformer(transform_param, TEST, + Caffe::GetDefaultDevice()); transformer.InitRand(); transformer.Transform(datum, &blob); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { EXPECT_EQ(blob.cpu_data()[j], label - mean_value); } } @@ -283,10 +289,10 @@ TYPED_TEST(DataTransformTest, TestMeanValue) { TYPED_TEST(DataTransformTest, TestMeanValues) { TransformationParameter transform_param; const bool unique_pixels = false; // pixels are equal to label - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; transform_param.add_mean_value(0); transform_param.add_mean_value(1); @@ -294,11 +300,12 @@ TYPED_TEST(DataTransformTest, TestMeanValues) { Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); Blob blob(1, channels, height, width); - DataTransformer transformer(transform_param, TEST); + DataTransformer transformer(transform_param, TEST, + Caffe::GetDefaultDevice()); transformer.InitRand(); transformer.Transform(datum, &blob); - for (int c = 0; c < channels; ++c) { - for (int j = 0; j < height * width; ++j) { + for (int_tp c = 0; c < channels; ++c) { + for (int_tp j = 0; j < height * width; ++j) { EXPECT_EQ(blob.cpu_data()[blob.offset(0, c) + j], label - c); } } @@ -307,11 +314,11 @@ TYPED_TEST(DataTransformTest, TestMeanValues) { TYPED_TEST(DataTransformTest, TestMeanFile) { TransformationParameter transform_param; const bool unique_pixels = true; // pixels are consecutive ints [0,size] - const int label = 0; - const int channels = 3; - const int height = 4; - const int width = 5; - const int size = channels * height * width; + const int_tp label = 0; + const int_tp channels = 3; + const int_tp height = 4; + const int_tp width = 5; + const int_tp size = channels * height * width; // Create a mean file string mean_file; @@ -322,7 +329,7 @@ TYPED_TEST(DataTransformTest, TestMeanFile) { blob_mean.set_height(height); blob_mean.set_width(width); - for (int j = 0; j < size; ++j) { + for (int_tp j = 0; j < size; ++j) { blob_mean.add_data(j); } @@ -333,10 +340,11 @@ TYPED_TEST(DataTransformTest, TestMeanFile) { Datum datum; FillDatum(label, channels, height, width, unique_pixels, &datum); Blob blob(1, channels, height, width); - DataTransformer transformer(transform_param, TEST); + DataTransformer transformer(transform_param, TEST, + Caffe::GetDefaultDevice()); transformer.InitRand(); transformer.Transform(datum, &blob); - for (int j = 0; j < blob.count(); ++j) { + for (int_tp j = 0; j < blob.count(); ++j) { EXPECT_EQ(blob.cpu_data()[j], 0); } } diff --git a/src/caffe/test/test_db.cpp b/src/caffe/test/test_db.cpp index 1b487b14c58..a578cdbd711 100644 --- a/src/caffe/test/test_db.cpp +++ b/src/caffe/test/test_db.cpp @@ -30,7 +30,7 @@ class DBTest : public ::testing::Test { scoped_ptr db(db::GetDB(TypeParam::backend)); db->Open(this->source_, db::NEW); scoped_ptr txn(db->NewTransaction()); - for (int i = 0; i < 2; ++i) { + for (int_tp i = 0; i < 2; ++i) { Datum datum; ReadImageToDatum(root_images_ + keys[i], i, &datum); string out; diff --git a/src/caffe/test/test_deconvolution_layer.cpp b/src/caffe/test/test_deconvolution_layer.cpp index c4b09ad555a..dd61dc0b90f 100644 --- a/src/caffe/test/test_deconvolution_layer.cpp +++ b/src/caffe/test/test_deconvolution_layer.cpp @@ -114,10 +114,10 @@ TYPED_TEST(DeconvolutionLayerTest, TestSimpleDeconvolution) { layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); // simply check that accumulation works with overlapping filters const Dtype* top_data = this->blob_top_->cpu_data(); - for (int n = 0; n < this->blob_top_->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { + for (int_tp n = 0; n < this->blob_top_->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { Dtype expected = 3.1; bool h_overlap = h % 2 == 0 && h > 0 && h < this->blob_top_->height() - 1; @@ -156,16 +156,16 @@ TYPED_TEST(DeconvolutionLayerTest, TestGradient) { TYPED_TEST(DeconvolutionLayerTest, TestNDAgainst2D) { typedef typename TypeParam::Dtype Dtype; - const int kernel_h = 11; - const int kernel_w = 13; - vector bottom_shape(4); + const int_tp kernel_h = 11; + const int_tp kernel_w = 13; + vector bottom_shape(4); bottom_shape[0] = 15; bottom_shape[1] = 12; bottom_shape[2] = kernel_h * 2; bottom_shape[3] = kernel_w * 2; FillerParameter filler_param; GaussianFiller filler(filler_param); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); filler.Fill(this->blob_bottom_vec_[i]); } @@ -216,7 +216,7 @@ TYPED_TEST(DeconvolutionLayerTest, TestNDAgainst2D) { // Copy pre-generated top diff into actual top diff; // do Backward and save result in backward_result_2d. ASSERT_EQ(this->blob_top_->shape(), top_diff.shape()); - caffe_copy(top_diff.count(), top_diff.cpu_data(), + caffe_cpu_copy(top_diff.count(), top_diff.cpu_data(), this->blob_top_->mutable_cpu_diff()); layer_2d.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); @@ -247,7 +247,7 @@ TYPED_TEST(DeconvolutionLayerTest, TestNDAgainst2D) { // Copy pre-generated top diff into actual top diff; // do Backward and save result in backward_result_nd. ASSERT_EQ(this->blob_top_->shape(), top_diff.shape()); - caffe_copy(top_diff.count(), top_diff.cpu_data(), + caffe_cpu_copy(top_diff.count(), top_diff.cpu_data(), this->blob_top_->mutable_cpu_diff()); layer_nd.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); @@ -256,17 +256,17 @@ TYPED_TEST(DeconvolutionLayerTest, TestNDAgainst2D) { backward_weight_result_nd.CopyFrom(weights, copy_diff, reshape); } ASSERT_EQ(result_nd.count(), result_2d.count()); - for (int i = 0; i < result_2d.count(); ++i) { + for (int_tp i = 0; i < result_2d.count(); ++i) { EXPECT_EQ(result_2d.cpu_data()[i], result_nd.cpu_data()[i]); } ASSERT_EQ(backward_result_nd.count(), backward_result_2d.count()); - for (int i = 0; i < backward_result_2d.count(); ++i) { + for (int_tp i = 0; i < backward_result_2d.count(); ++i) { EXPECT_EQ(backward_result_2d.cpu_diff()[i], backward_result_nd.cpu_diff()[i]); } ASSERT_EQ(backward_weight_result_nd.count(), backward_weight_result_2d.count()); - for (int i = 0; i < backward_weight_result_2d.count(); ++i) { + for (int_tp i = 0; i < backward_weight_result_2d.count(); ++i) { EXPECT_EQ(backward_weight_result_2d.cpu_diff()[i], backward_weight_result_nd.cpu_diff()[i]); } @@ -274,7 +274,7 @@ TYPED_TEST(DeconvolutionLayerTest, TestNDAgainst2D) { TYPED_TEST(DeconvolutionLayerTest, TestGradient3D) { typedef typename TypeParam::Dtype Dtype; - vector bottom_shape(5); + vector bottom_shape(5); bottom_shape[0] = this->blob_bottom_vec_[0]->shape(0); bottom_shape[1] = this->blob_bottom_vec_[0]->shape(1); bottom_shape[2] = 2; @@ -282,7 +282,7 @@ TYPED_TEST(DeconvolutionLayerTest, TestGradient3D) { bottom_shape[4] = 2; FillerParameter filler_param; GaussianFiller filler(filler_param); - for (int i = 0; i < this->blob_bottom_vec_.size(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_vec_.size(); ++i) { this->blob_bottom_vec_[i]->Reshape(bottom_shape); filler.Fill(this->blob_bottom_vec_[i]); } diff --git a/src/caffe/test/test_dummy_data_layer.cpp b/src/caffe/test/test_dummy_data_layer.cpp index 1a01ca85f89..53151e6b843 100644 --- a/src/caffe/test/test_dummy_data_layer.cpp +++ b/src/caffe/test/test_dummy_data_layer.cpp @@ -59,14 +59,14 @@ TYPED_TEST(DummyDataLayerTest, TestOneTopConstant) { EXPECT_EQ(this->blob_top_a_->width(), 4); EXPECT_EQ(this->blob_top_b_->count(), 0); EXPECT_EQ(this->blob_top_c_->count(), 0); - for (int i = 0; i < this->blob_top_vec_.size(); ++i) { - for (int j = 0; j < this->blob_top_vec_[i]->count(); ++j) { + for (int_tp i = 0; i < this->blob_top_vec_.size(); ++i) { + for (int_tp j = 0; j < this->blob_top_vec_[i]->count(); ++j) { EXPECT_EQ(0, this->blob_top_vec_[i]->cpu_data()[j]); } } layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_vec_.size(); ++i) { - for (int j = 0; j < this->blob_top_vec_[i]->count(); ++j) { + for (int_tp i = 0; i < this->blob_top_vec_.size(); ++i) { + for (int_tp j = 0; j < this->blob_top_vec_[i]->count(); ++j) { EXPECT_EQ(0, this->blob_top_vec_[i]->cpu_data()[j]); } } @@ -97,14 +97,14 @@ TYPED_TEST(DummyDataLayerTest, TestTwoTopConstant) { EXPECT_EQ(this->blob_top_b_->height(), 1); EXPECT_EQ(this->blob_top_b_->width(), 4); EXPECT_EQ(this->blob_top_c_->count(), 0); - for (int i = 0; i < this->blob_top_vec_.size(); ++i) { - for (int j = 0; j < this->blob_top_vec_[i]->count(); ++j) { + for (int_tp i = 0; i < this->blob_top_vec_.size(); ++i) { + for (int_tp j = 0; j < this->blob_top_vec_[i]->count(); ++j) { EXPECT_EQ(7, this->blob_top_vec_[i]->cpu_data()[j]); } } layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_vec_.size(); ++i) { - for (int j = 0; j < this->blob_top_vec_[i]->count(); ++j) { + for (int_tp i = 0; i < this->blob_top_vec_.size(); ++i) { + for (int_tp j = 0; j < this->blob_top_vec_[i]->count(); ++j) { EXPECT_EQ(7, this->blob_top_vec_[i]->cpu_data()[j]); } } @@ -141,51 +141,51 @@ TYPED_TEST(DummyDataLayerTest, TestThreeTopConstantGaussianConstant) { EXPECT_EQ(this->blob_top_c_->channels(), 3); EXPECT_EQ(this->blob_top_c_->height(), 2); EXPECT_EQ(this->blob_top_c_->width(), 4); - for (int i = 0; i < this->blob_top_a_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_a_->count(); ++i) { EXPECT_EQ(7, this->blob_top_a_->cpu_data()[i]); } // Blob b uses a Gaussian filler, so SetUp should not have initialized it. // Blob b's data should therefore be the default Blob data value: 0. - for (int i = 0; i < this->blob_top_b_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_b_->count(); ++i) { EXPECT_EQ(0, this->blob_top_b_->cpu_data()[i]); } - for (int i = 0; i < this->blob_top_c_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_c_->count(); ++i) { EXPECT_EQ(9, this->blob_top_c_->cpu_data()[i]); } // Do a Forward pass to fill in Blob b with Gaussian data. layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_a_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_a_->count(); ++i) { EXPECT_EQ(7, this->blob_top_a_->cpu_data()[i]); } // Check that the Gaussian's data has been filled in with values within // 10 standard deviations of the mean. Record the first and last sample. // to check that they're different after the next Forward pass. - for (int i = 0; i < this->blob_top_b_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_b_->count(); ++i) { EXPECT_NEAR(gaussian_mean, this->blob_top_b_->cpu_data()[i], gaussian_std * 10); } const TypeParam first_gaussian_sample = this->blob_top_b_->cpu_data()[0]; const TypeParam last_gaussian_sample = this->blob_top_b_->cpu_data()[this->blob_top_b_->count() - 1]; - for (int i = 0; i < this->blob_top_c_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_c_->count(); ++i) { EXPECT_EQ(9, this->blob_top_c_->cpu_data()[i]); } // Do another Forward pass to fill in Blob b with Gaussian data again, // checking that we get different values. layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_a_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_a_->count(); ++i) { EXPECT_EQ(7, this->blob_top_a_->cpu_data()[i]); } - for (int i = 0; i < this->blob_top_b_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_b_->count(); ++i) { EXPECT_NEAR(gaussian_mean, this->blob_top_b_->cpu_data()[i], gaussian_std * 10); } EXPECT_NE(first_gaussian_sample, this->blob_top_b_->cpu_data()[0]); EXPECT_NE(last_gaussian_sample, this->blob_top_b_->cpu_data()[this->blob_top_b_->count() - 1]); - for (int i = 0; i < this->blob_top_c_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_c_->count(); ++i) { EXPECT_EQ(9, this->blob_top_c_->cpu_data()[i]); } } diff --git a/src/caffe/test/test_eltwise_layer.cpp b/src/caffe/test/test_eltwise_layer.cpp index c06e3baab15..f59523ce9ab 100644 --- a/src/caffe/test/test_eltwise_layer.cpp +++ b/src/caffe/test/test_eltwise_layer.cpp @@ -24,7 +24,7 @@ class EltwiseLayerTest : public MultiDeviceTest { blob_bottom_c_(new Blob(2, 3, 4, 5)), blob_top_(new Blob()) { // fill the values - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); FillerParameter filler_param; UniformFiller filler(filler_param); filler.Fill(this->blob_bottom_a_); @@ -75,11 +75,11 @@ TYPED_TEST(EltwiseLayerTest, TestProd) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_a_->cpu_data(); const Dtype* in_data_b = this->blob_bottom_b_->cpu_data(); const Dtype* in_data_c = this->blob_bottom_c_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] * in_data_b[i] * in_data_c[i], 1e-4); } } @@ -94,11 +94,11 @@ TYPED_TEST(EltwiseLayerTest, TestSum) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_a_->cpu_data(); const Dtype* in_data_b = this->blob_bottom_b_->cpu_data(); const Dtype* in_data_c = this->blob_bottom_c_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] + in_data_b[i] + in_data_c[i], 1e-4); } } @@ -116,11 +116,11 @@ TYPED_TEST(EltwiseLayerTest, TestSumCoeff) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_a_->cpu_data(); const Dtype* in_data_b = this->blob_bottom_b_->cpu_data(); const Dtype* in_data_c = this->blob_bottom_c_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] - 0.5*in_data_b[i] + 2*in_data_c[i], 1e-4); } @@ -185,11 +185,11 @@ TYPED_TEST(EltwiseLayerTest, TestMax) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_a_->cpu_data(); const Dtype* in_data_b = this->blob_bottom_b_->cpu_data(); const Dtype* in_data_c = this->blob_bottom_c_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_EQ(data[i], std::max(in_data_a[i], std::max(in_data_b[i], in_data_c[i]))); } diff --git a/src/caffe/test/test_embed_layer.cpp b/src/caffe/test/test_embed_layer.cpp index dc7f5c4aa47..2423a6aa928 100644 --- a/src/caffe/test/test_embed_layer.cpp +++ b/src/caffe/test/test_embed_layer.cpp @@ -55,8 +55,8 @@ TYPED_TEST(EmbedLayerTest, TestForward) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; EmbedParameter* embed_param = layer_param.mutable_embed_param(); - const int kNumOutput = 10; - const int kInputDim = 5; + const int_tp kNumOutput = 10; + const int_tp kInputDim = 5; embed_param->set_num_output(kNumOutput); embed_param->set_input_dim(kInputDim); embed_param->mutable_weight_filler()->set_type("uniform"); @@ -66,22 +66,22 @@ TYPED_TEST(EmbedLayerTest, TestForward) { shared_ptr > layer(new EmbedLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(1, layer->blobs().size()); - vector weight_shape(2); + vector weight_shape(2); weight_shape[0] = kInputDim; weight_shape[1] = kNumOutput; ASSERT_TRUE(weight_shape == layer->blobs()[0]->shape()); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { this->blob_bottom_->mutable_cpu_data()[i] = caffe_rng_rand() % kInputDim; } layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - vector weight_offset(2, 0); - vector top_offset(5, 0); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - weight_offset[0] = static_cast(this->blob_bottom_->cpu_data()[i]); + vector weight_offset(2, 0); + vector top_offset(5, 0); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + weight_offset[0] = static_cast(this->blob_bottom_->cpu_data()[i]); weight_offset[1] = 0; top_offset[0] = i; top_offset[4] = 0; - for (int j = 0; j < kNumOutput; ++j) { + for (int_tp j = 0; j < kNumOutput; ++j) { EXPECT_EQ(layer->blobs()[0]->data_at(weight_offset), this->blob_top_->data_at(top_offset)); ++top_offset[4]; @@ -94,8 +94,8 @@ TYPED_TEST(EmbedLayerTest, TestForwardWithBias) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; EmbedParameter* embed_param = layer_param.mutable_embed_param(); - const int kNumOutput = 10; - const int kInputDim = 5; + const int_tp kNumOutput = 10; + const int_tp kInputDim = 5; embed_param->set_num_output(kNumOutput); embed_param->set_input_dim(kInputDim); embed_param->mutable_weight_filler()->set_type("uniform"); @@ -106,24 +106,24 @@ TYPED_TEST(EmbedLayerTest, TestForwardWithBias) { shared_ptr > layer(new EmbedLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(2, layer->blobs().size()); - vector weight_shape(2); + vector weight_shape(2); weight_shape[0] = kInputDim; weight_shape[1] = kNumOutput; ASSERT_TRUE(weight_shape == layer->blobs()[0]->shape()); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { this->blob_bottom_->mutable_cpu_data()[i] = caffe_rng_rand() % kInputDim; } layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - vector bias_offset(1, 0); - vector weight_offset(2, 0); - vector top_offset(5, 0); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - weight_offset[0] = static_cast(this->blob_bottom_->cpu_data()[i]); + vector bias_offset(1, 0); + vector weight_offset(2, 0); + vector top_offset(5, 0); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + weight_offset[0] = static_cast(this->blob_bottom_->cpu_data()[i]); weight_offset[1] = 0; top_offset[0] = i; top_offset[4] = 0; bias_offset[0] = 0; - for (int j = 0; j < kNumOutput; ++j) { + for (int_tp j = 0; j < kNumOutput; ++j) { EXPECT_EQ(layer->blobs()[0]->data_at(weight_offset) + layer->blobs()[1]->data_at(bias_offset), this->blob_top_->data_at(top_offset)); @@ -136,6 +136,12 @@ TYPED_TEST(EmbedLayerTest, TestForwardWithBias) { TYPED_TEST(EmbedLayerTest, TestGradient) { typedef typename TypeParam::Dtype Dtype; + // Skip the test on unsupported OpenCL devices with double + if (!Caffe::GetDefaultDevice()-> + CheckCapability("cl_khr_int64_base_atomics") + && is_same::value) { + return; + } LayerParameter layer_param; EmbedParameter* embed_param = layer_param.mutable_embed_param(); embed_param->set_num_output(10); @@ -156,6 +162,12 @@ TYPED_TEST(EmbedLayerTest, TestGradient) { TYPED_TEST(EmbedLayerTest, TestGradientWithBias) { typedef typename TypeParam::Dtype Dtype; + // Skip the test on unsupported OpenCL devices with double + if (!Caffe::GetDefaultDevice()-> + CheckCapability("cl_khr_int64_base_atomics") + && is_same::value) { + return; + } LayerParameter layer_param; EmbedParameter* embed_param = layer_param.mutable_embed_param(); embed_param->set_num_output(10); diff --git a/src/caffe/test/test_filler.cpp b/src/caffe/test/test_filler.cpp index 26e9b217e35..ab88b02dfab 100644 --- a/src/caffe/test/test_filler.cpp +++ b/src/caffe/test/test_filler.cpp @@ -26,9 +26,9 @@ TYPED_TEST_CASE(ConstantFillerTest, TestDtypes); TYPED_TEST(ConstantFillerTest, TestFill) { EXPECT_TRUE(this->blob_); - const int count = this->blob_->count(); + const int_tp count = this->blob_->count(); const TypeParam* data = this->blob_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_GE(data[i], this->filler_param_.value()); } } @@ -55,9 +55,9 @@ TYPED_TEST_CASE(UniformFillerTest, TestDtypes); TYPED_TEST(UniformFillerTest, TestFill) { EXPECT_TRUE(this->blob_); - const int count = this->blob_->count(); + const int_tp count = this->blob_->count(); const TypeParam* data = this->blob_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_GE(data[i], this->filler_param_.min()); EXPECT_LE(data[i], this->filler_param_.max()); } @@ -82,17 +82,17 @@ TYPED_TEST_CASE(PositiveUnitballFillerTest, TestDtypes); TYPED_TEST(PositiveUnitballFillerTest, TestFill) { EXPECT_TRUE(this->blob_); - const int num = this->blob_->num(); - const int count = this->blob_->count(); - const int dim = count / num; + const int_tp num = this->blob_->num(); + const int_tp count = this->blob_->count(); + const int_tp dim = count / num; const TypeParam* data = this->blob_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_GE(data[i], 0); EXPECT_LE(data[i], 1); } - for (int i = 0; i < num; ++i) { + for (int_tp i = 0; i < num; ++i) { TypeParam sum = 0; - for (int j = 0; j < dim; ++j) { + for (int_tp j = 0; j < dim; ++j) { sum += data[i * dim + j]; } EXPECT_GE(sum, 0.999); @@ -121,11 +121,11 @@ TYPED_TEST_CASE(GaussianFillerTest, TestDtypes); TYPED_TEST(GaussianFillerTest, TestFill) { EXPECT_TRUE(this->blob_); - const int count = this->blob_->count(); + const int_tp count = this->blob_->count(); const TypeParam* data = this->blob_->cpu_data(); TypeParam mean = 0.; TypeParam var = 0.; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { mean += data[i]; var += (data[i] - this->filler_param_.mean()) * (data[i] - this->filler_param_.mean()); @@ -153,11 +153,11 @@ class XavierFillerTest : public ::testing::Test { this->filler_.reset(new XavierFiller(this->filler_param_)); this->filler_->Fill(blob_); EXPECT_TRUE(this->blob_); - const int count = this->blob_->count(); + const int_tp count = this->blob_->count(); const Dtype* data = this->blob_->cpu_data(); Dtype mean = 0.; Dtype ex2 = 0.; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { mean += data[i]; ex2 += data[i] * data[i]; } @@ -202,11 +202,11 @@ class MSRAFillerTest : public ::testing::Test { this->filler_.reset(new MSRAFiller(this->filler_param_)); this->filler_->Fill(blob_); EXPECT_TRUE(this->blob_); - const int count = this->blob_->count(); + const int_tp count = this->blob_->count(); const Dtype* data = this->blob_->cpu_data(); Dtype mean = 0.; Dtype ex2 = 0.; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { mean += data[i]; ex2 += data[i] * data[i]; } diff --git a/src/caffe/test/test_filter_layer.cpp b/src/caffe/test/test_filter_layer.cpp index 9ea2b8b2168..4eb9a396701 100644 --- a/src/caffe/test/test_filter_layer.cpp +++ b/src/caffe/test/test_filter_layer.cpp @@ -25,7 +25,7 @@ class FilterLayerTest : public MultiDeviceTest { blob_top_labels_(new Blob()) {} virtual void SetUp() { // fill the values - Caffe::set_random_seed(1890); + Caffe::set_random_seed(1890, Caffe::GetDefaultDevice()); FillerParameter filler_param; GaussianFiller filler(filler_param); // fill the selector blob @@ -36,7 +36,7 @@ class FilterLayerTest : public MultiDeviceTest { bottom_data_selector_[3] = 0; // fill the other bottom blobs filler.Fill(blob_bottom_data_); - for (int i = 0; i < blob_bottom_labels_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_labels_->count(); ++i) { blob_bottom_labels_->mutable_cpu_data()[i] = caffe_rng_rand() % 5; } blob_bottom_vec_.push_back(blob_bottom_data_); @@ -78,7 +78,7 @@ TYPED_TEST(FilterLayerTest, TestReshape) { this->blob_top_data_->shape(0)); EXPECT_GT(this->blob_bottom_labels_->shape(0), this->blob_top_labels_->shape(0)); - for (int i = 1; i < this->blob_bottom_labels_->num_axes(); i++) { + for (int_tp i = 1; i < this->blob_bottom_labels_->num_axes(); i++) { EXPECT_EQ(this->blob_bottom_labels_->shape(i), this->blob_top_labels_->shape(i)); } @@ -96,19 +96,19 @@ TYPED_TEST(FilterLayerTest, TestForward) { EXPECT_EQ(this->blob_top_labels_->data_at(1, 0, 0, 0), this->blob_bottom_labels_->data_at(2, 0, 0, 0)); - int dim = this->blob_top_data_->count() / + int_tp dim = this->blob_top_data_->count() / this->blob_top_data_->shape(0); const Dtype* top_data = this->blob_top_data_->cpu_data(); const Dtype* bottom_data = this->blob_bottom_data_->cpu_data(); // selector is 0 1 1 0, so we need to compare bottom(1,c,h,w) // with top(0,c,h,w) and bottom(2,c,h,w) with top(1,c,h,w) bottom_data += dim; // bottom(1,c,h,w) - for (size_t n = 0; n < dim; n++) + for (uint_tp n = 0; n < dim; n++) EXPECT_EQ(top_data[n], bottom_data[n]); bottom_data += dim; // bottom(2,c,h,w) top_data += dim; // top(1,c,h,w) - for (size_t n = 0; n < dim; n++) + for (uint_tp n = 0; n < dim; n++) EXPECT_EQ(top_data[n], bottom_data[n]); } diff --git a/src/caffe/test/test_flatten_layer.cpp b/src/caffe/test/test_flatten_layer.cpp index d929ac7a720..c3a2bfe137a 100644 --- a/src/caffe/test/test_flatten_layer.cpp +++ b/src/caffe/test/test_flatten_layer.cpp @@ -19,7 +19,7 @@ class FlattenLayerTest : public MultiDeviceTest { FlattenLayerTest() : blob_bottom_(new Blob(2, 3, 6, 5)), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -88,7 +88,7 @@ TYPED_TEST(FlattenLayerTest, TestForward) { FlattenLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int c = 0; c < 3 * 6 * 5; ++c) { + for (int_tp c = 0; c < 3 * 6 * 5; ++c) { EXPECT_EQ(this->blob_top_->data_at(0, c, 0, 0), this->blob_bottom_->data_at(0, c / (6 * 5), (c / 5) % 6, c % 5)); EXPECT_EQ(this->blob_top_->data_at(1, c, 0, 0), diff --git a/src/caffe/test/test_gradient_based_solver.cpp b/src/caffe/test/test_gradient_based_solver.cpp index 84c6747f61a..b8002806a53 100644 --- a/src/caffe/test/test_gradient_based_solver.cpp +++ b/src/caffe/test/test_gradient_based_solver.cpp @@ -19,17 +19,17 @@ using std::ostringstream; namespace caffe { -template +template class GradientBasedSolverTest : public MultiDeviceTest { typedef typename TypeParam::Dtype Dtype; protected: - GradientBasedSolverTest() : - seed_(1701), num_(4), channels_(3), height_(10), width_(10), - share_(false) { - input_file_ = new string( - CMAKE_SOURCE_DIR "caffe/test/test_data/solver_data_list.txt" CMAKE_EXT); - } + GradientBasedSolverTest() + : seed_(1701), num_(4), channels_(3), height_(10), width_(10), + share_(false) { + input_file_ = new string( + CMAKE_SOURCE_DIR "caffe/test/test_data/solver_data_list.txt" CMAKE_EXT); + } ~GradientBasedSolverTest() { delete input_file_; } @@ -61,115 +61,117 @@ class GradientBasedSolverTest : public MultiDeviceTest { param.set_solver_mode(SolverParameter_SolverMode_GPU); break; default: - LOG(FATAL) << "Unknown Caffe mode: " << Caffe::mode(); - } + LOG(FATAL)<< "Unknown Caffe mode: " << Caffe::mode(); + } InitSolver(param); delta_ = param.delta(); } string RunLeastSquaresSolver(const Dtype learning_rate, - const Dtype weight_decay, const Dtype momentum, const int num_iters, - const int iter_size = 1, const int devices = 1, - const bool snapshot = false, const char* from_snapshot = NULL) { + const Dtype weight_decay, const Dtype momentum, + const int num_iters, const int iter_size = 1, + const int devices = 1, const bool snapshot = + false, + const char* from_snapshot = NULL) { ostringstream proto; int device_id = 0; #ifndef CPU_ONLY - if (Caffe::mode() == Caffe::GPU) { +#ifdef USE_CUDA + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { CUDA_CHECK(cudaGetDevice(&device_id)); } -#endif - proto << - "snapshot_after_train: " << snapshot << " " - "max_iter: " << num_iters << " " - "base_lr: " << learning_rate << " " - "lr_policy: 'fixed' " - "iter_size: " << iter_size << " " - "device_id: " << device_id << " " - "net_param { " - " name: 'TestNetwork' " - " layer { " - " name: 'data' " - " type: 'HDF5Data' " - " hdf5_data_param { " - " source: '" << *(this->input_file_) << "' " - " batch_size: " << num_ / iter_size << " " - " } " - " top: 'data' " - " top: 'targets' " - " } "; +#endif // USE_CUDA +#endif // !CPU_ONLY + proto << "snapshot_after_train: " << snapshot << " " + "max_iter: " << num_iters << " " + "base_lr: " << learning_rate << " " + "lr_policy: 'fixed' " + "iter_size: " << iter_size << " " + "device_id: " << device_id << " " + "net_param { " + " name: 'TestNetwork' " + " layer { " + " name: 'data' " + " type: 'HDF5Data' " + " hdf5_data_param { " + " source: '" << *(this->input_file_) << "' " + " batch_size: " << num_ / iter_size << " " + " } " + " top: 'data' " + " top: 'targets' " + " } "; if (share_) { - proto << - " layer { " - " name: 'slice' " - " type: 'Slice' " - " bottom: 'data' " - " top: 'data1' " - " top: 'data2' " - " slice_param { " - " axis: 0 " - " } " - " } "; + proto << " layer { " + " name: 'slice' " + " type: 'Slice' " + " bottom: 'data' " + " top: 'data1' " + " top: 'data2' " + " slice_param { " + " axis: 0 " + " } " + " } "; } - proto << - " layer { " - " name: 'innerprod' " - " type: 'InnerProduct' " - " param { name: 'weights' } " - " param { name: 'bias' } " - " inner_product_param { " - " num_output: 1 " - " weight_filler { " - " type: 'gaussian' " - " std: 1.0 " - " } " - " bias_filler { " - " type: 'gaussian' " - " std: 1.0 " - " } " - " } " - " bottom: '" << string(share_ ? "data1": "data") << "' " - " top: '" << string(share_ ? "innerprod1": "innerprod") << "' " - " } "; + proto << " layer { " + " name: 'innerprod' " + " type: 'InnerProduct' " + " param { name: 'weights' } " + " param { name: 'bias' } " + " inner_product_param { " + " num_output: 1 " + " weight_filler { " + " type: 'gaussian' " + " std: 1.0 " + " } " + " bias_filler { " + " type: 'gaussian' " + " std: 1.0 " + " } " + " } " + " bottom: '" + << string(share_ ? "data1" : "data") << "' " + " top: '" + << string(share_ ? "innerprod1" : "innerprod") << "' " + " } "; if (share_) { - proto << - " layer { " - " name: 'innerprod2' " - " type: 'InnerProduct' " - " param { name: 'weights' } " - " param { name: 'bias' } " - " inner_product_param { " - " num_output: 1 " - " weight_filler { " - " type: 'gaussian' " - " std: 1.0 " - " } " - " bias_filler { " - " type: 'gaussian' " - " std: 1.0 " - " } " - " } " - " bottom: 'data2' " - " top: 'innerprod2' " - " } " - " layer { " - " name: 'concat' " - " type: 'Concat' " - " bottom: 'innerprod1' " - " bottom: 'innerprod2' " - " top: 'innerprod' " - " concat_param { " - " axis: 0 " - " } " - " } "; + proto << " layer { " + " name: 'innerprod2' " + " type: 'InnerProduct' " + " param { name: 'weights' } " + " param { name: 'bias' } " + " inner_product_param { " + " num_output: 1 " + " weight_filler { " + " type: 'gaussian' " + " std: 1.0 " + " } " + " bias_filler { " + " type: 'gaussian' " + " std: 1.0 " + " } " + " } " + " bottom: 'data2' " + " top: 'innerprod2' " + " } " + " layer { " + " name: 'concat' " + " type: 'Concat' " + " bottom: 'innerprod1' " + " bottom: 'innerprod2' " + " top: 'innerprod' " + " concat_param { " + " axis: 0 " + " } " + " } "; } - proto << - " layer { " - " name: 'loss' " - " type: 'EuclideanLoss' " - " bottom: 'innerprod' " - " bottom: 'targets' " - " } " - "} "; + proto << " layer { " + " name: 'loss' " + " type: 'EuclideanLoss' " + " bottom: 'innerprod' " + " bottom: 'targets' " + " } " + "} "; if (weight_decay != 0) { proto << "weight_decay: " << weight_decay << " "; } @@ -181,7 +183,7 @@ class GradientBasedSolverTest : public MultiDeviceTest { if (snapshot) { proto << "snapshot: " << num_iters << " "; } - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitSolverFromProtoString(proto.str()); if (from_snapshot != NULL) { this->solver_->Restore(from_snapshot); @@ -193,18 +195,18 @@ class GradientBasedSolverTest : public MultiDeviceTest { if (devices == 1) { this->solver_->Solve(); } else { - LOG(INFO) << "Multi-GPU test on " << devices << " devices"; - vector gpus; + LOG(INFO)<< "Multi-GPU test on " << devices << " devices"; + vector gpus; // put current device at the beginning - int device_id = solver_->param().device_id(); - gpus.push_back(device_id); + device* dc = Caffe::GetDevice(solver_->param().device_id(), true); + gpus.push_back(dc); for (int i = 0; gpus.size() < devices; ++i) { if (i != device_id) - gpus.push_back(i); + gpus.push_back(Caffe::GetDevice(i, true)); } Caffe::set_solver_count(gpus.size()); this->sync_.reset(new P2PSync( - this->solver_, NULL, this->solver_->param())); + this->solver_, NULL, this->solver_->param())); this->sync_->run(gpus); Caffe::set_solver_count(1); } @@ -222,9 +224,9 @@ class GradientBasedSolverTest : public MultiDeviceTest { // using the analytical formula for the least squares gradient. // updated_params will store the updated weight and bias results, // using the blobs' diffs to hold the update values themselves. - void ComputeLeastSquaresUpdate(const Dtype learning_rate, - const Dtype weight_decay, const Dtype momentum, const int num_iters, - vector > >* updated_params) { + void ComputeLeastSquaresUpdate( + const Dtype learning_rate, const Dtype weight_decay, const Dtype momentum, + const int num_iters, vector > >* updated_params) { const int N = num_; const int D = channels_ * height_ * width_; @@ -238,8 +240,8 @@ class GradientBasedSolverTest : public MultiDeviceTest { ASSERT_TRUE(net.has_blob("targets")); const Blob& targets = *net.blob_by_name("targets"); ASSERT_TRUE(net.has_layer("innerprod")); - const vector > >& param_blobs = - net.layer_by_name("innerprod")->blobs(); + const vector > >& param_blobs = net.layer_by_name( + "innerprod")->blobs(); const int num_param_blobs = 2; ASSERT_EQ(num_param_blobs, param_blobs.size()); const Blob& weights = *param_blobs[0]; @@ -285,8 +287,8 @@ class GradientBasedSolverTest : public MultiDeviceTest { // Scale the gradient over the N samples. grad /= N; // Add the weight decay to the gradient. - grad += weight_decay * - ((i == D) ? bias.cpu_data()[0] : weights.cpu_data()[i]); + grad += weight_decay + * ((i == D) ? bias.cpu_data()[0] : weights.cpu_data()[i]); // Finally, compute update. const vector > >& history = solver_->history(); if (solver_->type() != string("AdaDelta") @@ -296,8 +298,8 @@ class GradientBasedSolverTest : public MultiDeviceTest { ASSERT_EQ(4, history.size()); // additional blobs for update history } Dtype update_value = learning_rate * grad; - const Dtype history_value = (i == D) ? - history[1]->cpu_data()[0] : history[0]->cpu_data()[i]; + const Dtype history_value = + (i == D) ? history[1]->cpu_data()[0] : history[0]->cpu_data()[i]; const Dtype temp = momentum * history_value; if (solver_->type() == string("SGD")) { update_value += temp; @@ -309,41 +311,45 @@ class GradientBasedSolverTest : public MultiDeviceTest { update_value /= std::sqrt(history_value + grad * grad) + delta_; } else if (solver_->type() == string("RMSProp")) { const Dtype rms_decay = 0.95; - update_value /= std::sqrt(rms_decay*history_value - + grad * grad * (1 - rms_decay)) + delta_; + update_value /= std::sqrt( + rms_decay * history_value + grad * grad * (1 - rms_decay)) + delta_; } else if (solver_->type() == string("AdaDelta")) { - const Dtype update_history_value = (i == D) ? - history[1 + num_param_blobs]->cpu_data()[0] : - history[0 + num_param_blobs]->cpu_data()[i]; - const Dtype weighted_gradient_average = - momentum * history_value + (1 - momentum) * (grad * grad); - update_value = grad * std::sqrt((update_history_value + delta_) / - (weighted_gradient_average + delta_)) * learning_rate; + const Dtype update_history_value = + (i == D) ? + history[1 + num_param_blobs]->cpu_data()[0] : + history[0 + num_param_blobs]->cpu_data()[i]; + const Dtype weighted_gradient_average = momentum * history_value + + (1 - momentum) * (grad * grad); + update_value = grad + * std::sqrt( + (update_history_value + delta_) + / (weighted_gradient_average + delta_)) * learning_rate; // not actually needed, just here for illustrative purposes // const Dtype weighted_update_average = // momentum * update_history_value + (1 - momentum) * (update_value); } else if (solver_->type() == string("Adam")) { const Dtype momentum2 = 0.999; const Dtype m = history_value; - const Dtype v = (i == D) ? - history[1 + num_param_blobs]->cpu_data()[0] : - history[0 + num_param_blobs]->cpu_data()[i]; + const Dtype v = + (i == D) ? + history[1 + num_param_blobs]->cpu_data()[0] : + history[0 + num_param_blobs]->cpu_data()[i]; const Dtype val_m = (1 - momentum) * grad + momentum * m; const Dtype val_v = (1 - momentum2) * grad * grad + momentum2 * v; - Dtype alpha_t = learning_rate * - std::sqrt(Dtype(1) - pow(momentum2, num_iters)) / - (Dtype(1.) - pow(momentum, num_iters)); + Dtype alpha_t = learning_rate + * std::sqrt(Dtype(1) - pow(momentum2, num_iters)) + / (Dtype(1.) - pow(momentum, num_iters)); update_value = alpha_t * val_m / (std::sqrt(val_v) + delta_); } else { - LOG(FATAL) << "Unknown solver type: " << solver_->type(); + LOG(FATAL)<< "Unknown solver type: " << solver_->type(); } if (i == D) { updated_bias.mutable_cpu_diff()[0] = update_value; updated_bias.mutable_cpu_data()[0] = bias.cpu_data()[0] - update_value; } else { updated_weights.mutable_cpu_diff()[i] = update_value; - updated_weights.mutable_cpu_data()[i] = - weights.cpu_data()[i] - update_value; + updated_weights.mutable_cpu_data()[i] = weights.cpu_data()[i] + - update_value; } } } @@ -357,8 +363,8 @@ class GradientBasedSolverTest : public MultiDeviceTest { Net& net = *this->solver_->net(); ASSERT_TRUE(net.has_layer("innerprod")); - const vector > >& param_blobs = - net.layer_by_name("innerprod")->blobs(); + const vector > >& param_blobs = net.layer_by_name( + "innerprod")->blobs(); ASSERT_EQ(2, param_blobs.size()); const Blob& solver_updated_weights = *param_blobs[0]; ASSERT_EQ(D, solver_updated_weights.count()); @@ -367,16 +373,21 @@ class GradientBasedSolverTest : public MultiDeviceTest { for (int i = 0; i < D; ++i) { const Dtype expected_updated_weight = updated_weights.cpu_data()[i]; const Dtype solver_updated_weight = solver_updated_weights.cpu_data()[i]; - const Dtype error_margin = std::max(kMinPrecision, kPrecision * - std::min(fabs(expected_updated_weight), fabs(solver_updated_weight))); + const Dtype error_margin = std::max( + kMinPrecision, + kPrecision + * std::min(fabs(expected_updated_weight), + fabs(solver_updated_weight))); EXPECT_NEAR(expected_updated_weight, solver_updated_weight, error_margin); } const Blob& solver_updated_bias_blob = *param_blobs[1]; ASSERT_EQ(1, solver_updated_bias_blob.count()); const Dtype expected_updated_bias = updated_bias.cpu_data()[0]; const Dtype solver_updated_bias = solver_updated_bias_blob.cpu_data()[0]; - const Dtype error_margin = std::max(kMinPrecision, kPrecision * - std::min(fabs(expected_updated_bias), fabs(solver_updated_bias))); + const Dtype error_margin = std::max( + kMinPrecision, + kPrecision + * std::min(fabs(expected_updated_bias), fabs(solver_updated_bias))); EXPECT_NEAR(expected_updated_bias, solver_updated_bias, error_margin); // Check the solver's history -- should contain the previous update value. @@ -386,29 +397,33 @@ class GradientBasedSolverTest : public MultiDeviceTest { for (int i = 0; i < D; ++i) { const Dtype expected_history = updated_weights.cpu_diff()[i]; const Dtype solver_history = history[0]->cpu_data()[i]; - const Dtype error_margin_hist = std::max(kMinPrecision, kPrecision * - std::min(fabs(expected_history), fabs(solver_history))); + const Dtype error_margin_hist = std::max( + kMinPrecision, + kPrecision + * std::min(fabs(expected_history), fabs(solver_history))); EXPECT_NEAR(expected_history, solver_history, error_margin_hist); } const Dtype expected_history = updated_bias.cpu_diff()[0]; const Dtype solver_history = history[1]->cpu_data()[0]; - const Dtype error_margin_hist = std::max(kMinPrecision, kPrecision * - std::min(fabs(expected_history), fabs(solver_history))); + const Dtype error_margin_hist = std::max( + kMinPrecision, + kPrecision * std::min(fabs(expected_history), fabs(solver_history))); EXPECT_NEAR(expected_history, solver_history, error_margin_hist); } } void CheckAccumulation(const Dtype kLearningRate, const Dtype kWeightDecay, - const Dtype kMomentum, const int kNumIters, const int kIterSize) { + const Dtype kMomentum, const int kNumIters, + const int kIterSize) { const double kPrecision = 1e-2; const double kMinPrecision = 1e-7; // Solve without accumulation and save parameters. this->RunLeastSquaresSolver(kLearningRate, kWeightDecay, kMomentum, - kNumIters); + kNumIters); // Save parameters for comparison. Net& net = *this->solver_->net(); - const vector > >& param_blobs = - net.layer_by_name("innerprod")->blobs(); + const vector > >& param_blobs = net.layer_by_name( + "innerprod")->blobs(); vector > > noaccum_params(param_blobs.size()); for (int i = 0; i < param_blobs.size(); ++i) { noaccum_params[i].reset(new Blob()); @@ -416,24 +431,26 @@ class GradientBasedSolverTest : public MultiDeviceTest { } // Solve by equivalent accumulation of gradients over divided batches. this->RunLeastSquaresSolver(kLearningRate, kWeightDecay, kMomentum, - kNumIters, kIterSize); + kNumIters, kIterSize); Net& net_accum = *this->solver_->net(); - const vector > >& accum_params = - net_accum.layer_by_name("innerprod")->blobs(); + const vector > >& accum_params = net_accum + .layer_by_name("innerprod")->blobs(); // Compare accumulated parameters against no accumulation standard. const int D = this->channels_ * this->height_ * this->width_; for (int i = 0; i < D; ++i) { const Dtype expected_param = noaccum_params[0]->cpu_data()[i]; const Dtype accum_param = accum_params[0]->cpu_data()[i]; - const Dtype error_margin = std::max(kMinPrecision, kPrecision * - std::min(fabs(expected_param), fabs(accum_param))); + const Dtype error_margin = std::max( + kMinPrecision, + kPrecision * std::min(fabs(expected_param), fabs(accum_param))); EXPECT_NEAR(expected_param, accum_param, error_margin); } ASSERT_EQ(1, accum_params[1]->count()); const Dtype expected_bias = noaccum_params[1]->cpu_data()[0]; const Dtype accum_bias = accum_params[1]->cpu_data()[0]; - const Dtype error_margin = std::max(kMinPrecision, kPrecision * - std::min(fabs(expected_bias), fabs(accum_bias))); + const Dtype error_margin = std::max( + kMinPrecision, + kPrecision * std::min(fabs(expected_bias), fabs(accum_bias))); EXPECT_NEAR(expected_bias, accum_bias, error_margin); } @@ -453,17 +470,21 @@ class GradientBasedSolverTest : public MultiDeviceTest { // from the Kth update, we compute the (K+1)th update and check that it // matches the solver's (K+1)th update. void TestLeastSquaresUpdate(const Dtype learning_rate = 1.0, - const Dtype weight_decay = 0.0, const Dtype momentum = 0.0, - const int iter_to_check = 0) { + const Dtype weight_decay = 0.0, + const Dtype momentum = 0.0, + const int iter_to_check = 0) { const int kNum = num_; const int kIterSize = 1; // Test over all numbers of devices. int available_devices = 1; #ifndef CPU_ONLY - if (Caffe::mode() == Caffe::GPU) { +#ifdef USE_CUDA + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { CUDA_CHECK(cudaGetDeviceCount(&available_devices)); } -#endif +#endif // USE_CUDA +#endif // !CPU_ONLY for (int devices = 1; devices <= available_devices; ++devices) { // Configure batch size for single / multi device equivalence. // Constant data is needed for multi device as for accumulation. @@ -477,28 +498,28 @@ class GradientBasedSolverTest : public MultiDeviceTest { // Compute the (K+1)th update using the analytic least squares gradient. vector > > updated_params; ComputeLeastSquaresUpdate(learning_rate, weight_decay, momentum, - iter_to_check + 1, &updated_params); + iter_to_check + 1, &updated_params); // Reinitialize the solver and run K+1 solver iterations. num_ = kNum; RunLeastSquaresSolver(learning_rate, weight_decay, momentum, - iter_to_check + 1, kIterSize, devices); + iter_to_check + 1, kIterSize, devices); // Check that the solver's solution matches ours. CheckLeastSquaresUpdate(updated_params); } } - void TestSnapshot(const Dtype learning_rate = 1.0, - const Dtype weight_decay = 0.0, const Dtype momentum = 0.0, - const int num_iters = 1) { + void TestSnapshot(const Dtype learning_rate = 1.0, const Dtype weight_decay = + 0.0, + const Dtype momentum = 0.0, const int num_iters = 1) { // Run the solver for num_iters * 2 iterations. const int total_num_iters = num_iters * 2; bool snapshot = false; const int kIterSize = 1; const int kDevices = 1; RunLeastSquaresSolver(learning_rate, weight_decay, momentum, - total_num_iters, kIterSize, kDevices, snapshot); + total_num_iters, kIterSize, kDevices, snapshot); // Save the resulting param values. vector > > param_copies; @@ -528,13 +549,14 @@ class GradientBasedSolverTest : public MultiDeviceTest { // Run the solver for num_iters iterations and snapshot. snapshot = true; string snapshot_name = RunLeastSquaresSolver(learning_rate, weight_decay, - momentum, num_iters, kIterSize, kDevices, snapshot); + momentum, num_iters, kIterSize, + kDevices, snapshot); // Reinitialize the solver and run for num_iters more iterations. snapshot = false; RunLeastSquaresSolver(learning_rate, weight_decay, momentum, - total_num_iters, kIterSize, kDevices, - snapshot, snapshot_name.c_str()); + total_num_iters, kIterSize, kDevices, snapshot, + snapshot_name.c_str()); // Check that params now match. const vector*>& params = solver_->net()->learnable_params(); @@ -560,8 +582,7 @@ class GradientBasedSolverTest : public MultiDeviceTest { } }; - -template +template class SGDSolverTest : public GradientBasedSolverTest { typedef typename TypeParam::Dtype Dtype; @@ -696,8 +717,7 @@ TYPED_TEST(SGDSolverTest, TestSnapshotShare) { } } - -template +template class AdaGradSolverTest : public GradientBasedSolverTest { typedef typename TypeParam::Dtype Dtype; @@ -738,7 +758,7 @@ TYPED_TEST(AdaGradSolverTest, TestAdaGradLeastSquaresUpdateWithEverything) { } TYPED_TEST(AdaGradSolverTest, - TestAdaGradLeastSquaresUpdateWithEverythingShare) { + TestAdaGradLeastSquaresUpdateWithEverythingShare) { typedef typename TypeParam::Dtype Dtype; const Dtype kLearningRate = 0.01; const Dtype kWeightDecay = 0.5; @@ -796,8 +816,7 @@ TYPED_TEST(AdaGradSolverTest, TestSnapshotShare) { } } - -template +template class NesterovSolverTest : public GradientBasedSolverTest { typedef typename TypeParam::Dtype Dtype; @@ -827,7 +846,7 @@ TYPED_TEST(NesterovSolverTest, TestNesterovLeastSquaresUpdateWithWeightDecay) { } TYPED_TEST(NesterovSolverTest, - TestNesterovLeastSquaresUpdateWithWeightDecayMultiIter) { + TestNesterovLeastSquaresUpdateWithWeightDecayMultiIter) { typedef typename TypeParam::Dtype Dtype; const Dtype kLearningRate = 0.01; const Dtype kWeightDecay = 0.5; @@ -872,7 +891,7 @@ TYPED_TEST(NesterovSolverTest, TestNesterovLeastSquaresUpdateWithEverything) { } TYPED_TEST(NesterovSolverTest, - TestNesterovLeastSquaresUpdateWithEverythingShare) { + TestNesterovLeastSquaresUpdateWithEverythingShare) { typedef typename TypeParam::Dtype Dtype; const Dtype kLearningRate = 0.01; const Dtype kWeightDecay = 0.5; @@ -930,7 +949,7 @@ TYPED_TEST(NesterovSolverTest, TestSnapshotShare) { } } -template +template class AdaDeltaSolverTest : public GradientBasedSolverTest { typedef typename TypeParam::Dtype Dtype; @@ -1001,7 +1020,7 @@ TYPED_TEST(AdaDeltaSolverTest, TestAdaDeltaLeastSquaresUpdateWithEverything) { } TYPED_TEST(AdaDeltaSolverTest, - TestAdaDeltaLeastSquaresUpdateWithEverythingShare) { + TestAdaDeltaLeastSquaresUpdateWithEverythingShare) { typedef typename TypeParam::Dtype Dtype; const Dtype kLearningRate = 0.1; const Dtype kWeightDecay = 0.1; @@ -1059,7 +1078,7 @@ TYPED_TEST(AdaDeltaSolverTest, TestSnapshotShare) { } } -template +template class AdamSolverTest : public GradientBasedSolverTest { typedef typename TypeParam::Dtype Dtype; @@ -1161,7 +1180,7 @@ TYPED_TEST(AdamSolverTest, TestSnapshotShare) { } } -template +template class RMSPropSolverTest : public GradientBasedSolverTest { typedef typename TypeParam::Dtype Dtype; @@ -1206,7 +1225,7 @@ TYPED_TEST(RMSPropSolverTest, TestRMSPropLeastSquaresUpdateWithEverything) { } TYPED_TEST(RMSPropSolverTest, - TestRMSPropLeastSquaresUpdateWithEverythingShare) { + TestRMSPropLeastSquaresUpdateWithEverythingShare) { typedef typename TypeParam::Dtype Dtype; const Dtype kLearningRate = 0.01; const Dtype kWeightDecay = 0.5; diff --git a/src/caffe/test/test_hdf5_output_layer.cpp b/src/caffe/test/test_hdf5_output_layer.cpp index 3833ebff78e..1a509d36fb7 100644 --- a/src/caffe/test/test_hdf5_output_layer.cpp +++ b/src/caffe/test/test_hdf5_output_layer.cpp @@ -44,10 +44,10 @@ class HDF5OutputLayerTest : public MultiDeviceTest { Blob* const blob_label_; vector*> blob_bottom_vec_; vector*> blob_top_vec_; - int num_; - int channels_; - int height_; - int width_; + int_tp num_; + int_tp channels_; + int_tp height_; + int_tp width_; }; template @@ -57,10 +57,10 @@ void HDF5OutputLayerTest::CheckBlobEqual(const Blob& b1, EXPECT_EQ(b1.channels(), b2.channels()); EXPECT_EQ(b1.height(), b2.height()); EXPECT_EQ(b1.width(), b2.width()); - for (int n = 0; n < b1.num(); ++n) { - for (int c = 0; c < b1.channels(); ++c) { - for (int h = 0; h < b1.height(); ++h) { - for (int w = 0; w < b1.width(); ++w) { + for (int_tp n = 0; n < b1.num(); ++n) { + for (int_tp c = 0; c < b1.channels(); ++c) { + for (int_tp h = 0; h < b1.height(); ++h) { + for (int_tp w = 0; w < b1.width(); ++w) { EXPECT_EQ(b1.data_at(n, c, h, w), b2.data_at(n, c, h, w)); } } diff --git a/src/caffe/test/test_hdf5data_layer.cpp b/src/caffe/test/test_hdf5data_layer.cpp index 8884ce95a23..ff867b9b06b 100644 --- a/src/caffe/test/test_hdf5data_layer.cpp +++ b/src/caffe/test/test_hdf5data_layer.cpp @@ -63,12 +63,12 @@ TYPED_TEST(HDF5DataLayerTest, TestRead) { param.add_top("label2"); HDF5DataParameter* hdf5_data_param = param.mutable_hdf5_data_param(); - int batch_size = 5; + int_tp batch_size = 5; hdf5_data_param->set_batch_size(batch_size); hdf5_data_param->set_source(*(this->filename)); - int num_cols = 8; - int height = 6; - int width = 5; + int_tp num_cols = 8; + int_tp height = 6; + int_tp width = 5; // Test that the layer setup got the correct parameters. HDF5DataLayer layer(param); @@ -89,23 +89,23 @@ TYPED_TEST(HDF5DataLayerTest, TestRead) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); // Go through the data 10 times (5 batches). - const int data_size = num_cols * height * width; - for (int iter = 0; iter < 10; ++iter) { + const int_tp data_size = num_cols * height * width; + for (int_tp iter = 0; iter < 10; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // On even iterations, we're reading the first half of the data. // On odd iterations, we're reading the second half of the data. // NB: label is 1-indexed - int label_offset = 1 + ((iter % 2 == 0) ? 0 : batch_size); - int label2_offset = 1 + label_offset; - int data_offset = (iter % 2 == 0) ? 0 : batch_size * data_size; + int_tp label_offset = 1 + ((iter % 2 == 0) ? 0 : batch_size); + int_tp label2_offset = 1 + label_offset; + int_tp data_offset = (iter % 2 == 0) ? 0 : batch_size * data_size; // Every two iterations we are reading the second file, // which has the same labels, but data is offset by total data size, // which is 2400 (see generate_sample_data). - int file_offset = (iter % 4 < 2) ? 0 : 2400; + int_tp file_offset = (iter % 4 < 2) ? 0 : 2400; - for (int i = 0; i < batch_size; ++i) { + for (int_tp i = 0; i < batch_size; ++i) { EXPECT_EQ( label_offset + i, this->blob_top_label_->cpu_data()[i]); @@ -113,11 +113,11 @@ TYPED_TEST(HDF5DataLayerTest, TestRead) { label2_offset + i, this->blob_top_label2_->cpu_data()[i]); } - for (int i = 0; i < batch_size; ++i) { - for (int j = 0; j < num_cols; ++j) { - for (int h = 0; h < height; ++h) { - for (int w = 0; w < width; ++w) { - int idx = ( + for (int_tp i = 0; i < batch_size; ++i) { + for (int_tp j = 0; j < num_cols; ++j) { + for (int_tp h = 0; h < height; ++h) { + for (int_tp w = 0; w < width; ++w) { + int_tp idx = ( i * num_cols * height * width + j * height * width + h * width + w); diff --git a/src/caffe/test/test_hinge_loss_layer.cpp b/src/caffe/test/test_hinge_loss_layer.cpp index 8bf89fa6387..ffe46ae9a65 100644 --- a/src/caffe/test/test_hinge_loss_layer.cpp +++ b/src/caffe/test/test_hinge_loss_layer.cpp @@ -23,13 +23,13 @@ class HingeLossLayerTest : public MultiDeviceTest { blob_bottom_label_(new Blob(10, 1, 1, 1)), blob_top_loss_(new Blob()) { // fill the values - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); FillerParameter filler_param; filler_param.set_std(10); GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_data_); blob_bottom_vec_.push_back(blob_bottom_data_); - for (int i = 0; i < blob_bottom_label_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_label_->count(); ++i) { blob_bottom_label_->mutable_cpu_data()[i] = caffe_rng_rand() % 5; } blob_bottom_vec_.push_back(blob_bottom_label_); diff --git a/src/caffe/test/test_im2col_kernel.cu b/src/caffe/test/test_im2col_kernel.cu index e3a9791bcca..b17ead1a9ac 100644 --- a/src/caffe/test/test_im2col_kernel.cu +++ b/src/caffe/test/test_im2col_kernel.cu @@ -1,3 +1,5 @@ +#ifdef USE_CUDA +#include #include #include "gtest/gtest.h" @@ -13,37 +15,39 @@ namespace caffe { // Forward declare kernel functions -template -__global__ void im2col_gpu_kernel(const int n, const Dtype* data_im, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, - const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, - const int height_col, const int width_col, - Dtype* data_col); - -template -__global__ void im2col_nd_gpu_kernel(const int n, const Dtype* data_im, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_col); +template +__global__ void im2col_gpu_kernel(const int_tp n, const Dtype* data_im, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + const int_tp height_col, + const int_tp width_col, Dtype* data_col); + +template +__global__ void im2col_nd_gpu_kernel(const int_tp n, const Dtype* data_im, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_col); template class Im2colKernelTest : public GPUDeviceTest { protected: Im2colKernelTest() - // big so launches > 1024 threads + // big so launches > 1024 threads : blob_bottom_(new Blob(5, 500, 15, 15)), - blob_kernel_shape_(new Blob()), - blob_stride_(new Blob()), - blob_pad_(new Blob()), - blob_dilation_(new Blob()), - blob_top_(new Blob()), + blob_kernel_shape_(new Blob()), + blob_stride_(new Blob()), blob_pad_(new Blob()), + blob_dilation_(new Blob()), blob_top_(new Blob()), blob_top_cpu_(new Blob()) { FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_); - vector dim_blob_shape(1, 2); + vector dim_blob_shape(1, 2); blob_kernel_shape_->Reshape(dim_blob_shape); blob_stride_->Reshape(dim_blob_shape); blob_pad_->Reshape(dim_blob_shape); @@ -56,12 +60,12 @@ class Im2colKernelTest : public GPUDeviceTest { stride_ = 2; dilation_ = 3; kernel_size_ = 3; - height_col_ = (height_ + 2 * pad_ - - (dilation_ * (kernel_size_ - 1) + 1)) / stride_ + 1; - width_col_ = (width_ + 2 * pad_ - - (dilation_ * (kernel_size_ - 1) + 1)) / stride_ + 1; + height_col_ = (height_ + 2 * pad_ - (dilation_ * (kernel_size_ - 1) + 1)) + / stride_ + 1; + width_col_ = (width_ + 2 * pad_ - (dilation_ * (kernel_size_ - 1) + 1)) + / stride_ + 1; - for (int i = 0; i < 2; ++i) { + for (int_tp i = 0; i < 2; ++i) { blob_kernel_shape_->mutable_cpu_data()[i] = kernel_size_; blob_stride_->mutable_cpu_data()[i] = stride_; blob_pad_->mutable_cpu_data()[i] = pad_; @@ -79,135 +83,143 @@ class Im2colKernelTest : public GPUDeviceTest { delete blob_dilation_; } - Blob* const blob_kernel_shape_; - Blob* const blob_stride_; - Blob* const blob_pad_; - Blob* const blob_dilation_; + Blob* const blob_kernel_shape_; + Blob* const blob_stride_; + Blob* const blob_pad_; + Blob* const blob_dilation_; Blob* const blob_bottom_; Blob* const blob_top_; Blob* const blob_top_cpu_; - int height_; - int width_; - int channels_; - int pad_; - int stride_; - int dilation_; - int kernel_size_; - int height_col_; - int width_col_; + int_tp height_; + int_tp width_; + int_tp channels_; + int_tp pad_; + int_tp stride_; + int_tp dilation_; + int_tp kernel_size_; + int_tp height_col_; + int_tp width_col_; }; TYPED_TEST_CASE(Im2colKernelTest, TestDtypes); TYPED_TEST(Im2colKernelTest, Test2D) { - // Reshape the blobs to correct size for im2col output - this->blob_top_->Reshape(this->blob_bottom_->num(), - this->channels_ * this->kernel_size_ * this->kernel_size_, - this->height_col_, - this->width_col_); - - this->blob_top_cpu_->Reshape(this->blob_bottom_->num(), - this->channels_ * this->kernel_size_ * this->kernel_size_, - this->height_col_, - this->width_col_); - - const TypeParam* bottom_data = this->blob_bottom_->gpu_data(); - TypeParam* top_data = this->blob_top_->mutable_gpu_data(); - TypeParam* cpu_data = this->blob_top_cpu_->mutable_cpu_data(); - - // CPU Version - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - im2col_cpu(this->blob_bottom_->cpu_data() + this->blob_bottom_->offset(n), - this->channels_, this->height_, this->width_, - this->kernel_size_, this->kernel_size_, this->pad_, this->pad_, - this->stride_, this->stride_, this->dilation_, this->dilation_, - cpu_data + this->blob_top_cpu_->offset(n)); - } - - // GPU version - int num_kernels = this->channels_ * this->height_col_ * this->width_col_; - int default_grid_dim = CAFFE_GET_BLOCKS(num_kernels); - - // Launch with different grid sizes - for (int grid_div = 2; grid_div <= 8; grid_div++) { - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - int grid_dim = default_grid_dim/grid_div; - // NOLINT_NEXT_LINE(whitespace/operators) - im2col_gpu_kernel<<>>( - num_kernels, bottom_data + this->blob_bottom_->offset(n), - this->height_, this->width_, this->kernel_size_, this->kernel_size_, - this->pad_, this->pad_, this->stride_, this->stride_, - this->dilation_, this->dilation_, - this->height_col_, this->width_col_, - top_data + this->blob_top_->offset(n)); - CUDA_POST_KERNEL_CHECK; + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + // Reshape the blobs to correct size for im2col output + this->blob_top_->Reshape(this->blob_bottom_->num(), + this->channels_ * this->kernel_size_ * this->kernel_size_, + this->height_col_, + this->width_col_); + + this->blob_top_cpu_->Reshape(this->blob_bottom_->num(), + this->channels_ * this->kernel_size_ * this->kernel_size_, + this->height_col_, + this->width_col_); + + const TypeParam* bottom_data = this->blob_bottom_->gpu_data(); + TypeParam* top_data = this->blob_top_->mutable_gpu_data(); + TypeParam* cpu_data = this->blob_top_cpu_->mutable_cpu_data(); + + // CPU Version + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + im2col_cpu(this->blob_bottom_->cpu_data() + this->blob_bottom_->offset(n), + this->channels_, this->height_, this->width_, + this->kernel_size_, this->kernel_size_, this->pad_, this->pad_, + this->stride_, this->stride_, this->dilation_, this->dilation_, + cpu_data + this->blob_top_cpu_->offset(n)); } - // Compare results against CPU version - for (int i = 0; i < this->blob_top_->count(); ++i) { - TypeParam cpuval = cpu_data[i]; - TypeParam gpuval = this->blob_top_->cpu_data()[i]; - EXPECT_EQ(cpuval, gpuval); - if (cpuval != gpuval) { - break; + // GPU version + int_tp num_kernels = this->channels_ * this->height_col_ * this->width_col_; + int_tp default_grid_dim = CAFFE_GET_BLOCKS(num_kernels); + + // Launch with different grid sizes + for (int_tp grid_div = 2; grid_div <= 8; grid_div++) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + int_tp grid_dim = default_grid_dim/grid_div; + // NOLINT_NEXT_LINE(whitespace/operators) + im2col_gpu_kernel + CUDA_KERNEL(grid_dim, CAFFE_CUDA_NUM_THREADS)( + num_kernels, bottom_data + this->blob_bottom_->offset(n), + this->height_, this->width_, this->kernel_size_, this->kernel_size_, + this->pad_, this->pad_, this->stride_, this->stride_, + this->dilation_, this->dilation_, + this->height_col_, this->width_col_, + top_data + this->blob_top_->offset(n)); + CUDA_POST_KERNEL_CHECK; + } + + // Compare results against CPU version + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + TypeParam cpuval = cpu_data[i]; + TypeParam gpuval = this->blob_top_->cpu_data()[i]; + EXPECT_EQ(cpuval, gpuval); + if (cpuval != gpuval) { + break; + } } } } } TYPED_TEST(Im2colKernelTest, TestND) { - // Reshape the blobs to correct size for im2col output - this->blob_top_->Reshape(this->blob_bottom_->num(), - this->channels_ * this->kernel_size_ * this->kernel_size_, - this->height_col_, - this->width_col_); - - this->blob_top_cpu_->ReshapeLike(*this->blob_top_); - - const TypeParam* bottom_data_cpu = this->blob_bottom_->cpu_data(); - TypeParam* top_data_cpu = this->blob_top_cpu_->mutable_cpu_data(); - - // CPU Version - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - im2col_nd_cpu(bottom_data_cpu + this->blob_bottom_->offset(n), 2, - this->blob_bottom_->shape().data() + 1, - this->blob_top_cpu_->shape().data() + 1, - this->blob_kernel_shape_->cpu_data(), - this->blob_pad_->cpu_data(), this->blob_stride_->cpu_data(), - this->blob_dilation_->cpu_data(), - top_data_cpu + this->blob_top_cpu_->offset(n)); - } - - // GPU version - int num_kernels = this->channels_ * this->height_col_ * this->width_col_; - int default_grid_dim = CAFFE_GET_BLOCKS(num_kernels); - const TypeParam* bottom_data_gpu = this->blob_bottom_->gpu_data(); - - // Launch with different grid sizes - for (int grid_div = 2; grid_div <= 8; grid_div++) { - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - const int grid_dim = default_grid_dim / grid_div; - TypeParam* top_data_gpu = this->blob_top_->mutable_gpu_data(); - // NOLINT_NEXT_LINE(whitespace/operators) - im2col_nd_gpu_kernel<<>>( - num_kernels, bottom_data_gpu + this->blob_bottom_->offset(n), - this->blob_bottom_->gpu_shape() + 1, this->blob_top_->gpu_shape() + 1, - this->blob_kernel_shape_->gpu_data(), this->blob_pad_->gpu_data(), - this->blob_stride_->gpu_data(), this->blob_dilation_->gpu_data(), - top_data_gpu + this->blob_top_->offset(n)); - CUDA_POST_KERNEL_CHECK; + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + // Reshape the blobs to correct size for im2col output + this->blob_top_->Reshape(this->blob_bottom_->num(), + this->channels_ * this->kernel_size_ * this->kernel_size_, + this->height_col_, + this->width_col_); + + this->blob_top_cpu_->ReshapeLike(*this->blob_top_); + + const TypeParam* bottom_data_cpu = this->blob_bottom_->cpu_data(); + TypeParam* top_data_cpu = this->blob_top_cpu_->mutable_cpu_data(); + + // CPU Version + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + im2col_nd_cpu(bottom_data_cpu + this->blob_bottom_->offset(n), 2, + this->blob_bottom_->shape().data() + 1, + this->blob_top_cpu_->shape().data() + 1, + this->blob_kernel_shape_->cpu_data(), + this->blob_pad_->cpu_data(), this->blob_stride_->cpu_data(), + this->blob_dilation_->cpu_data(), + top_data_cpu + this->blob_top_cpu_->offset(n)); } - // Compare results against CPU version - for (int i = 0; i < this->blob_top_->count(); ++i) { - TypeParam cpuval = top_data_cpu[i]; - TypeParam gpuval = this->blob_top_->cpu_data()[i]; - EXPECT_EQ(cpuval, gpuval); - if (cpuval != gpuval) { - break; + // GPU version + int_tp num_kernels = this->channels_ * this->height_col_ * this->width_col_; + int_tp default_grid_dim = CAFFE_GET_BLOCKS(num_kernels); + const TypeParam* bottom_data_gpu = this->blob_bottom_->gpu_data(); + + // Launch with different grid sizes + for (int_tp grid_div = 2; grid_div <= 8; grid_div++) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + const int_tp grid_dim = default_grid_dim / grid_div; + TypeParam* top_data_gpu = this->blob_top_->mutable_gpu_data(); + // NOLINT_NEXT_LINE(whitespace/operators) + im2col_nd_gpu_kernel + CUDA_KERNEL(grid_dim, CAFFE_CUDA_NUM_THREADS)( + num_kernels, bottom_data_gpu + this->blob_bottom_->offset(n), + this->blob_bottom_->gpu_shape() + 1, + this->blob_top_->gpu_shape() + 1, + this->blob_kernel_shape_->gpu_data(), this->blob_pad_->gpu_data(), + this->blob_stride_->gpu_data(), this->blob_dilation_->gpu_data(), + top_data_gpu + this->blob_top_->offset(n)); + CUDA_POST_KERNEL_CHECK; + } + + // Compare results against CPU version + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + TypeParam cpuval = top_data_cpu[i]; + TypeParam gpuval = this->blob_top_->cpu_data()[i]; + EXPECT_EQ(cpuval, gpuval); + if (cpuval != gpuval) { + break; + } } } } } } // namespace caffe +#endif // USE_CUDA diff --git a/src/caffe/test/test_im2col_layer.cpp b/src/caffe/test/test_im2col_layer.cpp index a7faf18f972..0606dfd5540 100644 --- a/src/caffe/test/test_im2col_layer.cpp +++ b/src/caffe/test/test_im2col_layer.cpp @@ -20,7 +20,7 @@ class Im2colLayerTest : public MultiDeviceTest { : blob_bottom_(new Blob(2, 3, 6, 5)), blob_top_(new Blob()) { // fill the values - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_); @@ -41,7 +41,7 @@ TYPED_TEST(Im2colLayerTest, TestSetup) { LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); - vector bottom_shape; + vector bottom_shape; bottom_shape.push_back(2); bottom_shape.push_back(3); bottom_shape.push_back(10); @@ -69,7 +69,7 @@ TYPED_TEST(Im2colLayerTest, TestForward) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // We are lazy and will only check the top left block - for (int c = 0; c < 27; ++c) { + for (int_tp c = 0; c < 27; ++c) { EXPECT_EQ(this->blob_bottom_->data_at(0, (c / 9), (c / 3) % 3, c % 3), this->blob_top_->data_at(0, c, 0, 0)); } @@ -93,7 +93,7 @@ TYPED_TEST(Im2colLayerTest, TestDilatedGradient) { LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); - vector bottom_shape; + vector bottom_shape; bottom_shape.push_back(2); bottom_shape.push_back(3); bottom_shape.push_back(10); @@ -127,7 +127,7 @@ TYPED_TEST(Im2colLayerTest, TestDilatedGradientForceND) { LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); - vector bottom_shape; + vector bottom_shape; bottom_shape.push_back(2); bottom_shape.push_back(3); bottom_shape.push_back(10); @@ -155,7 +155,7 @@ TYPED_TEST(Im2colLayerTest, TestRect) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // We are lazy and will only check the top left block - for (int c = 0; c < 45; ++c) { + for (int_tp c = 0; c < 45; ++c) { EXPECT_EQ(this->blob_top_->data_at(0, c, 0, 0), this->blob_bottom_->data_at(0, (c / 15), (c / 3) % 5, c % 3)); } diff --git a/src/caffe/test/test_image_data_layer.cpp b/src/caffe/test/test_image_data_layer.cpp index a4080ccd145..6f8cbd7d14a 100644 --- a/src/caffe/test/test_image_data_layer.cpp +++ b/src/caffe/test/test_image_data_layer.cpp @@ -28,12 +28,12 @@ class ImageDataLayerTest : public MultiDeviceTest { virtual void SetUp() { blob_top_vec_.push_back(blob_top_data_); blob_top_vec_.push_back(blob_top_label_); - Caffe::set_random_seed(seed_); + Caffe::set_random_seed(seed_, Caffe::GetDefaultDevice()); // Create test input file. MakeTempFilename(&filename_); std::ofstream outfile(filename_.c_str(), std::ofstream::out); LOG(INFO) << "Using temporary file " << filename_; - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { outfile << EXAMPLES_SOURCE_DIR "images/cat.jpg " << i; } outfile.close(); @@ -51,7 +51,7 @@ class ImageDataLayerTest : public MultiDeviceTest { delete blob_top_label_; } - int seed_; + int_tp seed_; string filename_; string filename_reshape_; Blob* const blob_top_data_; @@ -80,9 +80,9 @@ TYPED_TEST(ImageDataLayerTest, TestRead) { EXPECT_EQ(this->blob_top_label_->height(), 1); EXPECT_EQ(this->blob_top_label_->width(), 1); // Go through the data twice - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]); } } @@ -108,9 +108,9 @@ TYPED_TEST(ImageDataLayerTest, TestResize) { EXPECT_EQ(this->blob_top_label_->height(), 1); EXPECT_EQ(this->blob_top_label_->width(), 1); // Go through the data twice - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < 5; ++i) { + for (int_tp i = 0; i < 5; ++i) { EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]); } } @@ -161,11 +161,11 @@ TYPED_TEST(ImageDataLayerTest, TestShuffle) { EXPECT_EQ(this->blob_top_label_->height(), 1); EXPECT_EQ(this->blob_top_label_->width(), 1); // Go through the data twice - for (int iter = 0; iter < 2; ++iter) { + for (int_tp iter = 0; iter < 2; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - map values_to_indices; - int num_in_order = 0; - for (int i = 0; i < 5; ++i) { + map values_to_indices; + int_tp num_in_order = 0; + for (int_tp i = 0; i < 5; ++i) { Dtype value = this->blob_top_label_->cpu_data()[i]; // Check that the value has not been seen already (no duplicates). EXPECT_EQ(values_to_indices.find(value), values_to_indices.end()); diff --git a/src/caffe/test/test_infogain_loss_layer.cpp b/src/caffe/test/test_infogain_loss_layer.cpp index a24ac683dc5..eb8a39aaf78 100644 --- a/src/caffe/test/test_infogain_loss_layer.cpp +++ b/src/caffe/test/test_infogain_loss_layer.cpp @@ -22,12 +22,12 @@ class InfogainLossLayerTest : public MultiDeviceTest { blob_bottom_label_(new Blob(10, 1, 1, 1)), blob_bottom_infogain_(new Blob(1, 1, 5, 5)), blob_top_loss_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); FillerParameter filler_param; PositiveUnitballFiller filler(filler_param); filler.Fill(this->blob_bottom_data_); blob_bottom_vec_.push_back(blob_bottom_data_); - for (int i = 0; i < blob_bottom_label_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_label_->count(); ++i) { blob_bottom_label_->mutable_cpu_data()[i] = caffe_rng_rand() % 5; } blob_bottom_vec_.push_back(blob_bottom_label_); diff --git a/src/caffe/test/test_inner_product_layer.cpp b/src/caffe/test/test_inner_product_layer.cpp index b888b510318..ae55b7b94c2 100644 --- a/src/caffe/test/test_inner_product_layer.cpp +++ b/src/caffe/test/test_inner_product_layer.cpp @@ -12,10 +12,6 @@ namespace caffe { -#ifndef CPU_ONLY -extern cudaDeviceProp CAFFE_TEST_CUDA_PROP; -#endif - template class InnerProductLayerTest : public MultiDeviceTest { typedef typename TypeParam::Dtype Dtype; @@ -63,89 +59,62 @@ TYPED_TEST(InnerProductLayerTest, TestSetUp) { TYPED_TEST(InnerProductLayerTest, TestForward) { typedef typename TypeParam::Dtype Dtype; this->blob_bottom_vec_.push_back(this->blob_bottom_); - bool IS_VALID_CUDA = false; -#ifndef CPU_ONLY - IS_VALID_CUDA = CAFFE_TEST_CUDA_PROP.major >= 2; -#endif - if (Caffe::mode() == Caffe::CPU || - sizeof(Dtype) == 4 || IS_VALID_CUDA) { - LayerParameter layer_param; - InnerProductParameter* inner_product_param = - layer_param.mutable_inner_product_param(); - inner_product_param->set_num_output(10); - inner_product_param->mutable_weight_filler()->set_type("uniform"); - inner_product_param->mutable_bias_filler()->set_type("uniform"); - inner_product_param->mutable_bias_filler()->set_min(1); - inner_product_param->mutable_bias_filler()->set_max(2); - shared_ptr > layer( - new InnerProductLayer(layer_param)); - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); - for (int i = 0; i < count; ++i) { - EXPECT_GE(data[i], 1.); - } - } else { - LOG(ERROR) << "Skipping test due to old architecture."; + LayerParameter layer_param; + InnerProductParameter* inner_product_param = + layer_param.mutable_inner_product_param(); + inner_product_param->set_num_output(10); + inner_product_param->mutable_weight_filler()->set_type("uniform"); + inner_product_param->mutable_bias_filler()->set_type("uniform"); + inner_product_param->mutable_bias_filler()->set_min(1); + inner_product_param->mutable_bias_filler()->set_max(2); + shared_ptr > layer( + new InnerProductLayer(layer_param)); + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); + const Dtype* data = this->blob_top_->cpu_data(); + const int_tp count = this->blob_top_->count(); + for (int_tp i = 0; i < count; ++i) { + EXPECT_GE(data[i], 1.); } } TYPED_TEST(InnerProductLayerTest, TestForwardNoBatch) { typedef typename TypeParam::Dtype Dtype; this->blob_bottom_vec_.push_back(this->blob_bottom_nobatch_); - bool IS_VALID_CUDA = false; -#ifndef CPU_ONLY - IS_VALID_CUDA = CAFFE_TEST_CUDA_PROP.major >= 2; -#endif - if (Caffe::mode() == Caffe::CPU || - sizeof(Dtype) == 4 || IS_VALID_CUDA) { - LayerParameter layer_param; - InnerProductParameter* inner_product_param = - layer_param.mutable_inner_product_param(); - inner_product_param->set_num_output(10); - inner_product_param->mutable_weight_filler()->set_type("uniform"); - inner_product_param->mutable_bias_filler()->set_type("uniform"); - inner_product_param->mutable_bias_filler()->set_min(1); - inner_product_param->mutable_bias_filler()->set_max(2); - shared_ptr > layer( - new InnerProductLayer(layer_param)); - layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); - for (int i = 0; i < count; ++i) { - EXPECT_GE(data[i], 1.); - } - } else { - LOG(ERROR) << "Skipping test due to old architecture."; + LayerParameter layer_param; + InnerProductParameter* inner_product_param = + layer_param.mutable_inner_product_param(); + inner_product_param->set_num_output(10); + inner_product_param->mutable_weight_filler()->set_type("uniform"); + inner_product_param->mutable_bias_filler()->set_type("uniform"); + inner_product_param->mutable_bias_filler()->set_min(1); + inner_product_param->mutable_bias_filler()->set_max(2); + shared_ptr > layer( + new InnerProductLayer(layer_param)); + layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); + const Dtype* data = this->blob_top_->cpu_data(); + const int_tp count = this->blob_top_->count(); + for (int_tp i = 0; i < count; ++i) { + EXPECT_GE(data[i], 1.); } } TYPED_TEST(InnerProductLayerTest, TestGradient) { typedef typename TypeParam::Dtype Dtype; this->blob_bottom_vec_.push_back(this->blob_bottom_); - bool IS_VALID_CUDA = false; -#ifndef CPU_ONLY - IS_VALID_CUDA = CAFFE_TEST_CUDA_PROP.major >= 2; -#endif - if (Caffe::mode() == Caffe::CPU || - sizeof(Dtype) == 4 || IS_VALID_CUDA) { - LayerParameter layer_param; - InnerProductParameter* inner_product_param = - layer_param.mutable_inner_product_param(); - inner_product_param->set_num_output(10); - inner_product_param->mutable_weight_filler()->set_type("gaussian"); - inner_product_param->mutable_bias_filler()->set_type("gaussian"); - inner_product_param->mutable_bias_filler()->set_min(1); - inner_product_param->mutable_bias_filler()->set_max(2); - InnerProductLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); - } else { - LOG(ERROR) << "Skipping test due to old architecture."; - } + LayerParameter layer_param; + InnerProductParameter* inner_product_param = + layer_param.mutable_inner_product_param(); + inner_product_param->set_num_output(10); + inner_product_param->mutable_weight_filler()->set_type("gaussian"); + inner_product_param->mutable_bias_filler()->set_type("gaussian"); + inner_product_param->mutable_bias_filler()->set_min(1); + inner_product_param->mutable_bias_filler()->set_max(2); + InnerProductLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); } } // namespace caffe diff --git a/src/caffe/test/test_internal_thread.cpp b/src/caffe/test/test_internal_thread.cpp index 93f1cc541cd..99aa461fea2 100644 --- a/src/caffe/test/test_internal_thread.cpp +++ b/src/caffe/test/test_internal_thread.cpp @@ -14,7 +14,7 @@ class InternalThreadTest : public ::testing::Test {}; TEST_F(InternalThreadTest, TestStartAndExit) { InternalThread thread; EXPECT_FALSE(thread.is_started()); - thread.StartInternalThread(); + thread.StartInternalThread(Caffe::Get().GetDefaultDevice()); EXPECT_TRUE(thread.is_started()); thread.StopInternalThread(); EXPECT_FALSE(thread.is_started()); @@ -22,30 +22,38 @@ TEST_F(InternalThreadTest, TestStartAndExit) { class TestThreadA : public InternalThread { void InternalThreadEntry() { - EXPECT_EQ(4244559767, caffe_rng_rand()); + if (sizeof(uint_tp) == 4) { + EXPECT_EQ(2682223724U, caffe_rng_rand()); + } else { + EXPECT_EQ(10282592414170385089UL, caffe_rng_rand()); + } } }; class TestThreadB : public InternalThread { void InternalThreadEntry() { - EXPECT_EQ(1726478280, caffe_rng_rand()); + if (sizeof(uint_tp) == 4) { + EXPECT_EQ(887095485U, caffe_rng_rand()); + } else { + EXPECT_EQ(10310463406559028313UL, caffe_rng_rand()); + } } }; TEST_F(InternalThreadTest, TestRandomSeed) { TestThreadA t1; - Caffe::set_random_seed(9658361); - t1.StartInternalThread(); + Caffe::set_random_seed(9658361, Caffe::GetDefaultDevice()); + t1.StartInternalThread(Caffe::Get().GetDefaultDevice()); t1.StopInternalThread(); TestThreadA t2; - Caffe::set_random_seed(9658361); - t2.StartInternalThread(); + Caffe::set_random_seed(9658361, Caffe::GetDefaultDevice()); + t2.StartInternalThread(Caffe::Get().GetDefaultDevice()); t2.StopInternalThread(); TestThreadB t3; - Caffe::set_random_seed(3435563); - t3.StartInternalThread(); + Caffe::set_random_seed(3435563, Caffe::GetDefaultDevice()); + t3.StartInternalThread(Caffe::Get().GetDefaultDevice()); t3.StopInternalThread(); } diff --git a/src/caffe/test/test_io.cpp b/src/caffe/test/test_io.cpp index c2c919e90dc..4f2eeefcd84 100644 --- a/src/caffe/test/test_io.cpp +++ b/src/caffe/test/test_io.cpp @@ -17,10 +17,11 @@ namespace caffe { class IOTest : public ::testing::Test {}; -bool ReadImageToDatumReference(const string& filename, const int label, - const int height, const int width, const bool is_color, Datum* datum) { +bool ReadImageToDatumReference(const string& filename, const int_tp label, + const int_tp height, const int_tp width, + const bool is_color, Datum* datum) { cv::Mat cv_img; - int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : + int_tp cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : CV_LOAD_IMAGE_GRAYSCALE); cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag); @@ -34,7 +35,7 @@ bool ReadImageToDatumReference(const string& filename, const int label, cv_img = cv_img_origin; } - int num_channels = (is_color ? 3 : 1); + int_tp num_channels = (is_color ? 3 : 1); datum->set_channels(num_channels); datum->set_height(cv_img.rows); datum->set_width(cv_img.cols); @@ -43,17 +44,17 @@ bool ReadImageToDatumReference(const string& filename, const int label, datum->clear_float_data(); string* datum_string = datum->mutable_data(); if (is_color) { - for (int c = 0; c < num_channels; ++c) { - for (int h = 0; h < cv_img.rows; ++h) { - for (int w = 0; w < cv_img.cols; ++w) { + for (int_tp c = 0; c < num_channels; ++c) { + for (int_tp h = 0; h < cv_img.rows; ++h) { + for (int_tp w = 0; w < cv_img.cols; ++w) { datum_string->push_back( static_cast(cv_img.at(h, w)[c])); } } } } else { // Faster than repeatedly testing is_color for each pixel w/i loop - for (int h = 0; h < cv_img.rows; ++h) { - for (int w = 0; w < cv_img.cols; ++w) { + for (int_tp h = 0; h < cv_img.rows; ++h) { + for (int_tp w = 0; w < cv_img.cols; ++w) { datum_string->push_back( static_cast(cv_img.at(h, w))); } @@ -84,7 +85,7 @@ TEST_F(IOTest, TestReadImageToDatumReference) { const string& data = datum.data(); const string& data_ref = datum.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -103,7 +104,7 @@ TEST_F(IOTest, TestReadImageToDatumReferenceResized) { const string& data = datum.data(); const string& data_ref = datum.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -118,10 +119,10 @@ TEST_F(IOTest, TestReadImageToDatumContent) { EXPECT_EQ(datum.width(), cv_img.cols); const string& data = datum.data(); - int index = 0; - for (int c = 0; c < datum.channels(); ++c) { - for (int h = 0; h < datum.height(); ++h) { - for (int w = 0; w < datum.width(); ++w) { + int_tp index = 0; + for (int_tp c = 0; c < datum.channels(); ++c) { + for (int_tp h = 0; h < datum.height(); ++h) { + for (int_tp w = 0; w < datum.width(); ++w) { EXPECT_TRUE(data[index++] == static_cast(cv_img.at(h, w)[c])); } @@ -140,9 +141,9 @@ TEST_F(IOTest, TestReadImageToDatumContentGray) { EXPECT_EQ(datum.width(), cv_img.cols); const string& data = datum.data(); - int index = 0; - for (int h = 0; h < datum.height(); ++h) { - for (int w = 0; w < datum.width(); ++w) { + int_tp index = 0; + for (int_tp h = 0; h < datum.height(); ++h) { + for (int_tp w = 0; w < datum.width(); ++w) { EXPECT_TRUE(data[index++] == static_cast(cv_img.at(h, w))); } } @@ -253,7 +254,7 @@ TEST_F(IOTest, TestCVMatToDatumContent) { const string& data = datum.data(); const string& data_ref = datum_ref.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -272,7 +273,7 @@ TEST_F(IOTest, TestCVMatToDatumReference) { const string& data = datum.data(); const string& data_ref = datum_ref.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -301,7 +302,7 @@ TEST_F(IOTest, TestDecodeDatum) { const string& data = datum.data(); const string& data_ref = datum_ref.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -330,9 +331,9 @@ TEST_F(IOTest, TestDecodeDatumToCVMatContent) { EXPECT_EQ(cv_img_ref.rows, cv_img.rows); EXPECT_EQ(cv_img_ref.cols, cv_img.cols); - for (int c = 0; c < datum.channels(); ++c) { - for (int h = 0; h < datum.height(); ++h) { - for (int w = 0; w < datum.width(); ++w) { + for (int_tp c = 0; c < datum.channels(); ++c) { + for (int_tp h = 0; h < datum.height(); ++h) { + for (int_tp w = 0; w < datum.width(); ++w) { EXPECT_TRUE(cv_img.at(h, w)[c]== cv_img_ref.at(h, w)[c]); } @@ -355,7 +356,7 @@ TEST_F(IOTest, TestDecodeDatumNative) { const string& data = datum.data(); const string& data_ref = datum_ref.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -385,7 +386,7 @@ TEST_F(IOTest, TestDecodeDatumNativeGray) { const string& data = datum.data(); const string& data_ref = datum_ref.data(); - for (int i = 0; i < datum.data().size(); ++i) { + for (int_tp i = 0; i < datum.data().size(); ++i) { EXPECT_TRUE(data[i] == data_ref[i]); } } @@ -410,9 +411,9 @@ TEST_F(IOTest, TestDecodeDatumToCVMatContentNative) { EXPECT_EQ(cv_img_ref.rows, cv_img.rows); EXPECT_EQ(cv_img_ref.cols, cv_img.cols); - for (int c = 0; c < datum.channels(); ++c) { - for (int h = 0; h < datum.height(); ++h) { - for (int w = 0; w < datum.width(); ++w) { + for (int_tp c = 0; c < datum.channels(); ++c) { + for (int_tp h = 0; h < datum.height(); ++h) { + for (int_tp w = 0; w < datum.width(); ++w) { EXPECT_TRUE(cv_img.at(h, w)[c]== cv_img_ref.at(h, w)[c]); } diff --git a/src/caffe/test/test_lrn_layer.cpp b/src/caffe/test/test_lrn_layer.cpp index 4c97b1ae07b..8808fc32982 100644 --- a/src/caffe/test/test_lrn_layer.cpp +++ b/src/caffe/test/test_lrn_layer.cpp @@ -27,11 +27,11 @@ class LRNLayerTest : public MultiDeviceTest { protected: LRNLayerTest() - : epsilon_(Dtype(1e-5)), + : epsilon_(Dtype(1e-3)), blob_bottom_(new Blob()), blob_top_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 7, 3, 3); // fill the values FillerParameter filler_param; @@ -62,18 +62,18 @@ void LRNLayerTest::ReferenceLRNForward( LRNParameter lrn_param = layer_param.lrn_param(); Dtype alpha = lrn_param.alpha(); Dtype beta = lrn_param.beta(); - int size = lrn_param.local_size(); + int_tp size = lrn_param.local_size(); switch (lrn_param.norm_region()) { case LRNParameter_NormRegion_ACROSS_CHANNELS: - for (int n = 0; n < blob_bottom.num(); ++n) { - for (int c = 0; c < blob_bottom.channels(); ++c) { - for (int h = 0; h < blob_bottom.height(); ++h) { - for (int w = 0; w < blob_bottom.width(); ++w) { - int c_start = c - (size - 1) / 2; - int c_end = min(c_start + size, blob_bottom.channels()); - c_start = max(c_start, 0); + for (int_tp n = 0; n < blob_bottom.num(); ++n) { + for (int_tp c = 0; c < blob_bottom.channels(); ++c) { + for (int_tp h = 0; h < blob_bottom.height(); ++h) { + for (int_tp w = 0; w < blob_bottom.width(); ++w) { + int_tp c_start = c - (size - 1) / 2; + int_tp c_end = min(c_start + size, blob_bottom.channels()); + c_start = max(c_start, (int_tp)0); Dtype scale = 1.; - for (int i = c_start; i < c_end; ++i) { + for (int_tp i = c_start; i < c_end; ++i) { Dtype value = blob_bottom.data_at(n, i, h, w); scale += value * value * alpha / size; } @@ -85,19 +85,19 @@ void LRNLayerTest::ReferenceLRNForward( } break; case LRNParameter_NormRegion_WITHIN_CHANNEL: - for (int n = 0; n < blob_bottom.num(); ++n) { - for (int c = 0; c < blob_bottom.channels(); ++c) { - for (int h = 0; h < blob_bottom.height(); ++h) { - int h_start = h - (size - 1) / 2; - int h_end = min(h_start + size, blob_bottom.height()); - h_start = max(h_start, 0); - for (int w = 0; w < blob_bottom.width(); ++w) { + for (int_tp n = 0; n < blob_bottom.num(); ++n) { + for (int_tp c = 0; c < blob_bottom.channels(); ++c) { + for (int_tp h = 0; h < blob_bottom.height(); ++h) { + int_tp h_start = h - (size - 1) / 2; + int_tp h_end = min(h_start + size, blob_bottom.height()); + h_start = max(h_start, (int_tp)0); + for (int_tp w = 0; w < blob_bottom.width(); ++w) { Dtype scale = 1.; - int w_start = w - (size - 1) / 2; - int w_end = min(w_start + size, blob_bottom.width()); - w_start = max(w_start, 0); - for (int nh = h_start; nh < h_end; ++nh) { - for (int nw = w_start; nw < w_end; ++nw) { + int_tp w_start = w - (size - 1) / 2; + int_tp w_end = min(w_start + size, blob_bottom.width()); + w_start = max(w_start, (int_tp)0); + for (int_tp nh = h_start; nh < h_end; ++nh) { + for (int_tp nw = w_start; nw < w_end; ++nw) { Dtype value = blob_bottom.data_at(n, c, nh, nw); scale += value * value * alpha / (size * size); } @@ -136,7 +136,7 @@ TYPED_TEST(LRNLayerTest, TestForwardAcrossChannels) { Blob top_reference; this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, &top_reference); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], this->epsilon_); } @@ -152,7 +152,7 @@ TYPED_TEST(LRNLayerTest, TestForwardAcrossChannelsLargeRegion) { Blob top_reference; this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, &top_reference); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], this->epsilon_); } @@ -165,13 +165,13 @@ TYPED_TEST(LRNLayerTest, TestGradientAcrossChannels) { GradientChecker checker(1e-2, 1e-2); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { this->blob_top_->mutable_cpu_diff()[i] = 1.; } vector propagate_down(this->blob_bottom_vec_.size(), true); layer.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); - // for (int i = 0; i < this->blob_bottom_->count(); ++i) { + // for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { // std::cout << "CPU diff " << this->blob_bottom_->cpu_diff()[i] // << std::endl; // } @@ -187,13 +187,13 @@ TYPED_TEST(LRNLayerTest, TestGradientAcrossChannelsLargeRegion) { GradientChecker checker(1e-2, 1e-2); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { this->blob_top_->mutable_cpu_diff()[i] = 1.; } vector propagate_down(this->blob_bottom_vec_.size(), true); layer.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); - // for (int i = 0; i < this->blob_bottom_->count(); ++i) { + // for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { // std::cout << "CPU diff " << this->blob_bottom_->cpu_diff()[i] // << std::endl; // } @@ -227,7 +227,7 @@ TYPED_TEST(LRNLayerTest, TestForwardWithinChannel) { Blob top_reference; this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, &top_reference); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], this->epsilon_); } @@ -243,7 +243,7 @@ TYPED_TEST(LRNLayerTest, TestGradientWithinChannel) { GradientChecker checker(1e-2, 1e-2); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { this->blob_top_->mutable_cpu_diff()[i] = 1.; } checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, @@ -259,7 +259,7 @@ class CuDNNLRNLayerTest : public GPUDeviceTest { blob_bottom_(new Blob()), blob_top_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 7, 3, 3); // fill the values FillerParameter filler_param; @@ -290,18 +290,18 @@ void CuDNNLRNLayerTest::ReferenceLRNForward( LRNParameter lrn_param = layer_param.lrn_param(); Dtype alpha = lrn_param.alpha(); Dtype beta = lrn_param.beta(); - int size = lrn_param.local_size(); + int_tp size = lrn_param.local_size(); switch (lrn_param.norm_region()) { case LRNParameter_NormRegion_ACROSS_CHANNELS: - for (int n = 0; n < blob_bottom.num(); ++n) { - for (int c = 0; c < blob_bottom.channels(); ++c) { - for (int h = 0; h < blob_bottom.height(); ++h) { - for (int w = 0; w < blob_bottom.width(); ++w) { - int c_start = c - (size - 1) / 2; - int c_end = min(c_start + size, blob_bottom.channels()); - c_start = max(c_start, 0); + for (int_tp n = 0; n < blob_bottom.num(); ++n) { + for (int_tp c = 0; c < blob_bottom.channels(); ++c) { + for (int_tp h = 0; h < blob_bottom.height(); ++h) { + for (int_tp w = 0; w < blob_bottom.width(); ++w) { + int_tp c_start = c - (size - 1) / 2; + int_tp c_end = min(c_start + size, blob_bottom.channels()); + c_start = max(c_start, (int_tp)0); Dtype scale = 1.; - for (int i = c_start; i < c_end; ++i) { + for (int_tp i = c_start; i < c_end; ++i) { Dtype value = blob_bottom.data_at(n, i, h, w); scale += value * value * alpha / size; } @@ -313,19 +313,19 @@ void CuDNNLRNLayerTest::ReferenceLRNForward( } break; case LRNParameter_NormRegion_WITHIN_CHANNEL: - for (int n = 0; n < blob_bottom.num(); ++n) { - for (int c = 0; c < blob_bottom.channels(); ++c) { - for (int h = 0; h < blob_bottom.height(); ++h) { - int h_start = h - (size - 1) / 2; - int h_end = min(h_start + size, blob_bottom.height()); - h_start = max(h_start, 0); - for (int w = 0; w < blob_bottom.width(); ++w) { + for (int_tp n = 0; n < blob_bottom.num(); ++n) { + for (int_tp c = 0; c < blob_bottom.channels(); ++c) { + for (int_tp h = 0; h < blob_bottom.height(); ++h) { + int_tp h_start = h - (size - 1) / 2; + int_tp h_end = min(h_start + size, blob_bottom.height()); + h_start = max(h_start, (int_tp)0); + for (int_tp w = 0; w < blob_bottom.width(); ++w) { Dtype scale = 1.; - int w_start = w - (size - 1) / 2; - int w_end = min(w_start + size, blob_bottom.width()); - w_start = max(w_start, 0); - for (int nh = h_start; nh < h_end; ++nh) { - for (int nw = w_start; nw < w_end; ++nw) { + int_tp w_start = w - (size - 1) / 2; + int_tp w_end = min(w_start + size, blob_bottom.width()); + w_start = max(w_start, (int_tp)0); + for (int_tp nh = h_start; nh < h_end; ++nh) { + for (int_tp nw = w_start; nw < w_end; ++nw) { Dtype value = blob_bottom.data_at(n, c, nh, nw); scale += value * value * alpha / (size * size); } @@ -345,104 +345,116 @@ void CuDNNLRNLayerTest::ReferenceLRNForward( TYPED_TEST_CASE(CuDNNLRNLayerTest, TestDtypes); TYPED_TEST(CuDNNLRNLayerTest, TestForwardAcrossChannelsCuDNN) { - // typedef typename TypeParam::Dtype Dtype; - LayerParameter layer_param; - CuDNNLRNLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - Blob top_reference; - this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, - &top_reference); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], - this->epsilon_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + // typedef typename TypeParam::Dtype Dtype; + LayerParameter layer_param; + CuDNNLRNLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + Blob top_reference; + this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, + &top_reference); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], + this->epsilon_); + } } } TYPED_TEST(CuDNNLRNLayerTest, TestForwardAcrossChannelsLargeRegionCuDNN) { - typedef TypeParam Dtype; - LayerParameter layer_param; - layer_param.mutable_lrn_param()->set_local_size(15); - CuDNNLRNLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - Blob top_reference; - this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, - &top_reference); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], - this->epsilon_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + typedef TypeParam Dtype; + LayerParameter layer_param; + layer_param.mutable_lrn_param()->set_local_size(15); + CuDNNLRNLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + Blob top_reference; + this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, + &top_reference); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], + this->epsilon_); + } } } TYPED_TEST(CuDNNLRNLayerTest, TestGradientAcrossChannelsCuDNN) { - typedef TypeParam Dtype; - LayerParameter layer_param; - CuDNNLRNLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-2); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { - this->blob_top_->mutable_cpu_diff()[i] = 1.; + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + typedef TypeParam Dtype; + LayerParameter layer_param; + CuDNNLRNLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-2); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + this->blob_top_->mutable_cpu_diff()[i] = 1.; + } + vector propagate_down(this->blob_bottom_vec_.size(), true); + layer.Backward(this->blob_top_vec_, propagate_down, + this->blob_bottom_vec_); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); } - vector propagate_down(this->blob_bottom_vec_.size(), true); - layer.Backward(this->blob_top_vec_, propagate_down, - this->blob_bottom_vec_); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); } TYPED_TEST(CuDNNLRNLayerTest, TestForwardWithinChannel) { - typedef TypeParam Dtype; - LayerParameter layer_param; - layer_param.mutable_lrn_param()->set_norm_region( - LRNParameter_NormRegion_WITHIN_CHANNEL); - layer_param.mutable_lrn_param()->set_local_size(3); - CuDNNLCNLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - Blob top_reference; - this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, - &top_reference); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], - this->epsilon_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + typedef TypeParam Dtype; + LayerParameter layer_param; + layer_param.mutable_lrn_param()->set_norm_region( + LRNParameter_NormRegion_WITHIN_CHANNEL); + layer_param.mutable_lrn_param()->set_local_size(3); + CuDNNLCNLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + Blob top_reference; + this->ReferenceLRNForward(*(this->blob_bottom_), layer_param, + &top_reference); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + EXPECT_NEAR(this->blob_top_->cpu_data()[i], top_reference.cpu_data()[i], + this->epsilon_); + } } } TYPED_TEST(CuDNNLRNLayerTest, TestGradientWithinChannel) { - typedef TypeParam Dtype; - LayerParameter layer_param; - layer_param.mutable_lrn_param()->set_norm_region( - LRNParameter_NormRegion_WITHIN_CHANNEL); - layer_param.mutable_lrn_param()->set_local_size(3); - CuDNNLCNLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-2); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { - this->blob_top_->mutable_cpu_diff()[i] = 1.; + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + typedef TypeParam Dtype; + LayerParameter layer_param; + layer_param.mutable_lrn_param()->set_norm_region( + LRNParameter_NormRegion_WITHIN_CHANNEL); + layer_param.mutable_lrn_param()->set_local_size(3); + CuDNNLCNLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-2); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + this->blob_top_->mutable_cpu_diff()[i] = 1.; + } + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); } - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); } TYPED_TEST(CuDNNLRNLayerTest, TestGradientAcrossChannelsLargeRegionCuDNN) { - typedef TypeParam Dtype; - LayerParameter layer_param; - layer_param.mutable_lrn_param()->set_local_size(15); - CuDNNLRNLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-2); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { - this->blob_top_->mutable_cpu_diff()[i] = 1.; + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + typedef TypeParam Dtype; + LayerParameter layer_param; + layer_param.mutable_lrn_param()->set_local_size(15); + CuDNNLRNLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-2); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { + this->blob_top_->mutable_cpu_diff()[i] = 1.; + } + vector propagate_down(this->blob_bottom_vec_.size(), true); + layer.Backward(this->blob_top_vec_, propagate_down, + this->blob_bottom_vec_); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); } - vector propagate_down(this->blob_bottom_vec_.size(), true); - layer.Backward(this->blob_top_vec_, propagate_down, - this->blob_bottom_vec_); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); } #endif diff --git a/src/caffe/test/test_math_functions.cpp b/src/caffe/test/test_math_functions.cpp index efc5a2784eb..384e3ea8e56 100644 --- a/src/caffe/test/test_math_functions.cpp +++ b/src/caffe/test/test_math_functions.cpp @@ -11,6 +11,11 @@ #include "caffe/test/test_caffe_main.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { template @@ -24,7 +29,7 @@ class MathFunctionsTest : public MultiDeviceTest { } virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); this->blob_bottom_->Reshape(11, 17, 19, 23); this->blob_top_->Reshape(11, 17, 19, 23); // fill the values @@ -56,10 +61,10 @@ TYPED_TEST(CPUMathFunctionsTest, TestNothing) { } TYPED_TEST(CPUMathFunctionsTest, TestAsum) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); const TypeParam* x = this->blob_bottom_->cpu_data(); TypeParam std_asum = 0; - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { std_asum += std::fabs(x[i]); } TypeParam cpu_asum = caffe_cpu_asum(n, x); @@ -67,54 +72,54 @@ TYPED_TEST(CPUMathFunctionsTest, TestAsum) { } TYPED_TEST(CPUMathFunctionsTest, TestSign) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); const TypeParam* x = this->blob_bottom_->cpu_data(); caffe_cpu_sign(n, x, this->blob_bottom_->mutable_cpu_diff()); const TypeParam* signs = this->blob_bottom_->cpu_diff(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(signs[i], x[i] > 0 ? 1 : (x[i] < 0 ? -1 : 0)); } } TYPED_TEST(CPUMathFunctionsTest, TestSgnbit) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); const TypeParam* x = this->blob_bottom_->cpu_data(); caffe_cpu_sgnbit(n, x, this->blob_bottom_->mutable_cpu_diff()); const TypeParam* signbits = this->blob_bottom_->cpu_diff(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(signbits[i], x[i] < 0 ? 1 : 0); } } TYPED_TEST(CPUMathFunctionsTest, TestFabs) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); const TypeParam* x = this->blob_bottom_->cpu_data(); caffe_abs(n, x, this->blob_bottom_->mutable_cpu_diff()); const TypeParam* abs_val = this->blob_bottom_->cpu_diff(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(abs_val[i], x[i] > 0 ? x[i] : -x[i]); } } TYPED_TEST(CPUMathFunctionsTest, TestScale) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); TypeParam alpha = this->blob_bottom_->cpu_diff()[caffe_rng_rand() % this->blob_bottom_->count()]; caffe_cpu_scale(n, alpha, this->blob_bottom_->cpu_data(), this->blob_bottom_->mutable_cpu_diff()); const TypeParam* scaled = this->blob_bottom_->cpu_diff(); const TypeParam* x = this->blob_bottom_->cpu_data(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(scaled[i], x[i] * alpha); } } TYPED_TEST(CPUMathFunctionsTest, TestCopy) { - const int n = this->blob_bottom_->count(); + const int_tp n = this->blob_bottom_->count(); const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); TypeParam* top_data = this->blob_top_->mutable_cpu_data(); - caffe_copy(n, bottom_data, top_data); - for (int i = 0; i < n; ++i) { + caffe_cpu_copy(n, bottom_data, top_data); + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(bottom_data[i], top_data[i]); } } @@ -128,71 +133,153 @@ class GPUMathFunctionsTest : public MathFunctionsTest > { TYPED_TEST_CASE(GPUMathFunctionsTest, TestDtypes); TYPED_TEST(GPUMathFunctionsTest, TestAsum) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); const TypeParam* x = this->blob_bottom_->cpu_data(); TypeParam std_asum = 0; - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { std_asum += std::fabs(x[i]); } TypeParam gpu_asum; - caffe_gpu_asum(n, this->blob_bottom_->gpu_data(), &gpu_asum); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_asum(n, this->blob_bottom_->gpu_data(), &gpu_asum); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_asum(dc->id(), n, + (cl_mem)(this->blob_bottom_->gpu_data()), 0, &gpu_asum); +#endif // USE_GREENTEA + } EXPECT_LT((gpu_asum - std_asum) / std_asum, 1e-2); } TYPED_TEST(GPUMathFunctionsTest, TestSign) { - int n = this->blob_bottom_->count(); - caffe_gpu_sign(n, this->blob_bottom_->gpu_data(), + int_tp n = this->blob_bottom_->count(); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_sign(n, this->blob_bottom_->gpu_data(), this->blob_bottom_->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_sign(dc->id(), n, + (cl_mem)(this->blob_bottom_->gpu_data()), 0, + (cl_mem)(this->blob_bottom_->mutable_gpu_diff()), 0); +#endif // USE_GREENTEA + } + const TypeParam* signs = this->blob_bottom_->cpu_diff(); const TypeParam* x = this->blob_bottom_->cpu_data(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(signs[i], x[i] > 0 ? 1 : (x[i] < 0 ? -1 : 0)); } } TYPED_TEST(GPUMathFunctionsTest, TestSgnbit) { - int n = this->blob_bottom_->count(); - caffe_gpu_sgnbit(n, this->blob_bottom_->gpu_data(), + int_tp n = this->blob_bottom_->count(); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_sgnbit(n, this->blob_bottom_->gpu_data(), this->blob_bottom_->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_sgnbit(dc->id(), n, + (cl_mem)(this->blob_bottom_->gpu_data()), 0, + (cl_mem)(this->blob_bottom_->mutable_gpu_diff()), 0); +#endif // USE_GREENTEA + } + const TypeParam* signbits = this->blob_bottom_->cpu_diff(); const TypeParam* x = this->blob_bottom_->cpu_data(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(signbits[i], x[i] < 0 ? 1 : 0); } } TYPED_TEST(GPUMathFunctionsTest, TestFabs) { - int n = this->blob_bottom_->count(); - caffe_gpu_abs(n, this->blob_bottom_->gpu_data(), + int_tp n = this->blob_bottom_->count(); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_abs(n, this->blob_bottom_->gpu_data(), this->blob_bottom_->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_abs(dc->id(), n, + (cl_mem)(this->blob_bottom_->gpu_data()), 0, + (cl_mem)(this->blob_bottom_->mutable_gpu_diff()), 0); +#endif // USE_GREENTEA + } + const TypeParam* abs_val = this->blob_bottom_->cpu_diff(); const TypeParam* x = this->blob_bottom_->cpu_data(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(abs_val[i], x[i] > 0 ? x[i] : -x[i]); } } TYPED_TEST(GPUMathFunctionsTest, TestScale) { - int n = this->blob_bottom_->count(); + int_tp n = this->blob_bottom_->count(); TypeParam alpha = this->blob_bottom_->cpu_diff()[caffe_rng_rand() % this->blob_bottom_->count()]; - caffe_gpu_scale(n, alpha, this->blob_bottom_->gpu_data(), + + device *dc = Caffe::GetDefaultDevice(); + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_scale(n, alpha, this->blob_bottom_->gpu_data(), this->blob_bottom_->mutable_gpu_diff()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_scale(dc->id(), n, alpha, + (cl_mem)(this->blob_bottom_->gpu_data()), 0, + (cl_mem)(this->blob_bottom_->mutable_gpu_diff()), 0); +#endif // USE_GREENTEA + } + const TypeParam* scaled = this->blob_bottom_->cpu_diff(); const TypeParam* x = this->blob_bottom_->cpu_data(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(scaled[i], x[i] * alpha); } } TYPED_TEST(GPUMathFunctionsTest, TestCopy) { - const int n = this->blob_bottom_->count(); + const int_tp n = this->blob_bottom_->count(); const TypeParam* bottom_data = this->blob_bottom_->gpu_data(); TypeParam* top_data = this->blob_top_->mutable_gpu_data(); - caffe_copy(n, bottom_data, top_data); + + device *dc = Caffe::GetDefaultDevice(); + if (dc->backend() == BACKEND_CUDA) { + #ifdef USE_CUDA + caffe_copy(n, bottom_data, top_data); + #endif // USE_CUDA + } else { + #ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context( + dc->id()); + + greentea_copy(n, (cl_mem)bottom_data, 0, + (cl_mem)top_data, 0, &ctx); + #endif // USE_GREENTEA + } + bottom_data = this->blob_bottom_->cpu_data(); top_data = this->blob_top_->mutable_cpu_data(); - for (int i = 0; i < n; ++i) { + for (int_tp i = 0; i < n; ++i) { EXPECT_EQ(bottom_data[i], top_data[i]); } } diff --git a/src/caffe/test/test_maxpool_dropout_layers.cpp b/src/caffe/test/test_maxpool_dropout_layers.cpp index 4f0e20ac3a7..f662201307d 100644 --- a/src/caffe/test/test_maxpool_dropout_layers.cpp +++ b/src/caffe/test/test_maxpool_dropout_layers.cpp @@ -21,7 +21,7 @@ class MaxPoolingDropoutTest : public MultiDeviceTest { : blob_bottom_(new Blob()), blob_top_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1703); + Caffe::set_random_seed(1703, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 3, 6, 5); // fill the values FillerParameter filler_param; @@ -44,8 +44,8 @@ TYPED_TEST(MaxPoolingDropoutTest, TestSetup) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); PoolingLayer max_layer(layer_param); max_layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); DropoutLayer dropout_layer(layer_param); @@ -61,14 +61,14 @@ TYPED_TEST(MaxPoolingDropoutTest, TestForward) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* top_data = this->blob_top_->cpu_data(); Dtype sum = 0.; - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { sum += top_data[i]; } EXPECT_EQ(sum, this->blob_top_->count()); @@ -79,7 +79,7 @@ TYPED_TEST(MaxPoolingDropoutTest, TestForward) { sum = 0.; Dtype scale = 1. / (1. - layer_param.dropout_param().dropout_ratio()); top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { sum += top_data[i]; } EXPECT_GE(sum, 0); @@ -91,12 +91,12 @@ TYPED_TEST(MaxPoolingDropoutTest, TestBackward) { LayerParameter layer_param; layer_param.set_phase(TRAIN); PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { this->blob_top_->mutable_cpu_diff()[i] = 1.; } vector propagate_down(this->blob_bottom_vec_.size(), true); @@ -104,7 +104,7 @@ TYPED_TEST(MaxPoolingDropoutTest, TestBackward) { this->blob_bottom_vec_); const Dtype* bottom_diff = this->blob_bottom_->cpu_diff(); Dtype sum = 0.; - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { sum += bottom_diff[i]; } EXPECT_EQ(sum, this->blob_top_->count()); @@ -118,7 +118,7 @@ TYPED_TEST(MaxPoolingDropoutTest, TestBackward) { this->blob_bottom_vec_); Dtype sum_with_dropout = 0.; bottom_diff = this->blob_bottom_->cpu_diff(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { sum_with_dropout += bottom_diff[i]; } EXPECT_GE(sum_with_dropout, sum); diff --git a/src/caffe/test/test_memory_data_layer.cpp b/src/caffe/test/test_memory_data_layer.cpp index 7998bc18262..70a72a4fbd0 100644 --- a/src/caffe/test/test_memory_data_layer.cpp +++ b/src/caffe/test/test_memory_data_layer.cpp @@ -45,11 +45,11 @@ class MemoryDataLayerTest : public MultiDeviceTest { delete data_; delete labels_; } - int batch_size_; - int batches_; - int channels_; - int height_; - int width_; + int_tp batch_size_; + int_tp batches_; + int_tp channels_; + int_tp height_; + int_tp width_; // we don't really need blobs for the input data, but it makes it // easier to call Filler Blob* const data_; @@ -100,15 +100,15 @@ TYPED_TEST(MemoryDataLayerTest, TestForward) { layer->DataLayerSetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Reset(this->data_->mutable_cpu_data(), this->labels_->mutable_cpu_data(), this->data_->num()); - for (int i = 0; i < this->batches_ * 6; ++i) { - int batch_num = i % this->batches_; + for (int_tp i = 0; i < this->batches_ * 6; ++i) { + int_tp batch_num = i % this->batches_; layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int j = 0; j < this->data_blob_->count(); ++j) { + for (int_tp j = 0; j < this->data_blob_->count(); ++j) { EXPECT_EQ(this->data_blob_->cpu_data()[j], this->data_->cpu_data()[ this->data_->offset(1) * this->batch_size_ * batch_num + j]); } - for (int j = 0; j < this->label_blob_->count(); ++j) { + for (int_tp j = 0; j < this->label_blob_->count(); ++j) { EXPECT_EQ(this->label_blob_->cpu_data()[j], this->labels_->cpu_data()[this->batch_size_ * batch_num + j]); } @@ -129,36 +129,36 @@ TYPED_TEST(MemoryDataLayerTest, AddDatumVectorDefaultTransform) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); // We add batch_size*num_iter items, then for each iteration // we forward batch_size elements - int num_iter = 5; + int_tp num_iter = 5; vector datum_vector(this->batch_size_ * num_iter); - const size_t count = this->channels_ * this->height_ * this->width_; - size_t pixel_index = 0; - for (int i = 0; i < this->batch_size_ * num_iter; ++i) { + const uint_tp count = this->channels_ * this->height_ * this->width_; + uint_tp pixel_index = 0; + for (int_tp i = 0; i < this->batch_size_ * num_iter; ++i) { datum_vector[i].set_channels(this->channels_); datum_vector[i].set_height(this->height_); datum_vector[i].set_width(this->width_); datum_vector[i].set_label(i); vector pixels(count); - for (int j = 0; j < count; ++j) { + for (int_tp j = 0; j < count; ++j) { pixels[j] = pixel_index++ % 256; } datum_vector[i].set_data(&(pixels[0]), count); } layer.AddDatumVector(datum_vector); - int data_index; + int_tp data_index; // Go through the data 5 times - for (int iter = 0; iter < num_iter; ++iter) { - int offset = this->batch_size_ * iter; + for (int_tp iter = 0; iter < num_iter; ++iter) { + int_tp offset = this->batch_size_ * iter; layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->data_blob_->cpu_data(); - size_t index = 0; - for (int i = 0; i < this->batch_size_; ++i) { + uint_tp index = 0; + for (int_tp i = 0; i < this->batch_size_; ++i) { const string& data_string = datum_vector[offset + i].data(); EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); - for (int c = 0; c < this->channels_; ++c) { - for (int h = 0; h < this->height_; ++h) { - for (int w = 0; w < this->width_; ++w) { + for (int_tp c = 0; c < this->channels_; ++c) { + for (int_tp h = 0; h < this->height_; ++h) { + for (int_tp w = 0; w < this->width_; ++w) { data_index = (c * this->height_ + h) * this->width_ + w; EXPECT_EQ(static_cast( static_cast(data_string[data_index])), @@ -182,32 +182,32 @@ TYPED_TEST(MemoryDataLayerTest, AddMatVectorDefaultTransform) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); // We add batch_size*num_iter items, then for each iteration // we forward batch_size elements - int num_iter = 5; + int_tp num_iter = 5; vector mat_vector(this->batch_size_ * num_iter); - vector label_vector(this->batch_size_ * num_iter); - for (int i = 0; i < this->batch_size_*num_iter; ++i) { + vector label_vector(this->batch_size_ * num_iter); + for (int_tp i = 0; i < this->batch_size_*num_iter; ++i) { mat_vector[i] = cv::Mat(this->height_, this->width_, CV_8UC4); label_vector[i] = i; cv::randu(mat_vector[i], cv::Scalar::all(0), cv::Scalar::all(255)); } layer.AddMatVector(mat_vector, label_vector); - int data_index; - const size_t count = this->channels_ * this->height_ * this->width_; - for (int iter = 0; iter < num_iter; ++iter) { - int offset = this->batch_size_ * iter; + int_tp data_index; + const uint_tp count = this->channels_ * this->height_ * this->width_; + for (int_tp iter = 0; iter < num_iter; ++iter) { + int_tp offset = this->batch_size_ * iter; layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->data_blob_->cpu_data(); - for (int i = 0; i < this->batch_size_; ++i) { + for (int_tp i = 0; i < this->batch_size_; ++i) { EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); - for (int h = 0; h < this->height_; ++h) { + for (int_tp h = 0; h < this->height_; ++h) { const unsigned char* ptr_mat = mat_vector[offset + i].ptr(h); - int index = 0; - for (int w = 0; w < this->width_; ++w) { - for (int c = 0; c < this->channels_; ++c) { + int_tp index = 0; + for (int_tp w = 0; w < this->width_; ++w) { + for (int_tp c = 0; c < this->channels_; ++c) { data_index = (i*count) + (c * this->height_ + h) * this->width_ + w; Dtype pixel = static_cast(ptr_mat[index++]); - EXPECT_EQ(static_cast(pixel), + EXPECT_EQ(static_cast(pixel), data[data_index]); } } @@ -227,45 +227,45 @@ TYPED_TEST(MemoryDataLayerTest, TestSetBatchSize) { MemoryDataLayer layer(param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); // first add data as usual - int num_iter = 5; + int_tp num_iter = 5; vector mat_vector(this->batch_size_ * num_iter); - vector label_vector(this->batch_size_ * num_iter); - for (int i = 0; i < this->batch_size_*num_iter; ++i) { + vector label_vector(this->batch_size_ * num_iter); + for (int_tp i = 0; i < this->batch_size_*num_iter; ++i) { mat_vector[i] = cv::Mat(this->height_, this->width_, CV_8UC4); label_vector[i] = i; cv::randu(mat_vector[i], cv::Scalar::all(0), cv::Scalar::all(255)); } layer.AddMatVector(mat_vector, label_vector); // then consume the data - int data_index; - const size_t count = this->channels_ * this->height_ * this->width_; - for (int iter = 0; iter < num_iter; ++iter) { - int offset = this->batch_size_ * iter; + int_tp data_index; + const uint_tp count = this->channels_ * this->height_ * this->width_; + for (int_tp iter = 0; iter < num_iter; ++iter) { + int_tp offset = this->batch_size_ * iter; layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->data_blob_->cpu_data(); - for (int i = 0; i < this->batch_size_; ++i) { + for (int_tp i = 0; i < this->batch_size_; ++i) { EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); - for (int h = 0; h < this->height_; ++h) { + for (int_tp h = 0; h < this->height_; ++h) { const unsigned char* ptr_mat = mat_vector[offset + i].ptr(h); - int index = 0; - for (int w = 0; w < this->width_; ++w) { - for (int c = 0; c < this->channels_; ++c) { + int_tp index = 0; + for (int_tp w = 0; w < this->width_; ++w) { + for (int_tp c = 0; c < this->channels_; ++c) { data_index = (i*count) + (c * this->height_ + h) * this->width_ + w; Dtype pixel = static_cast(ptr_mat[index++]); - EXPECT_EQ(static_cast(pixel), data[data_index]); + EXPECT_EQ(static_cast(pixel), data[data_index]); } } } } } // and then add new data with different batch_size - int new_batch_size = 16; + int_tp new_batch_size = 16; layer.set_batch_size(new_batch_size); mat_vector.clear(); mat_vector.resize(new_batch_size * num_iter); label_vector.clear(); label_vector.resize(new_batch_size * num_iter); - for (int i = 0; i < new_batch_size*num_iter; ++i) { + for (int_tp i = 0; i < new_batch_size*num_iter; ++i) { mat_vector[i] = cv::Mat(this->height_, this->width_, CV_8UC4); label_vector[i] = i; cv::randu(mat_vector[i], cv::Scalar::all(0), cv::Scalar::all(255)); @@ -273,22 +273,22 @@ TYPED_TEST(MemoryDataLayerTest, TestSetBatchSize) { layer.AddMatVector(mat_vector, label_vector); // finally consume new data and check if everything is fine - for (int iter = 0; iter < num_iter; ++iter) { - int offset = new_batch_size * iter; + for (int_tp iter = 0; iter < num_iter; ++iter) { + int_tp offset = new_batch_size * iter; layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(new_batch_size, this->blob_top_vec_[0]->num()); EXPECT_EQ(new_batch_size, this->blob_top_vec_[1]->num()); const Dtype* data = this->data_blob_->cpu_data(); - for (int i = 0; i < new_batch_size; ++i) { + for (int_tp i = 0; i < new_batch_size; ++i) { EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); - for (int h = 0; h < this->height_; ++h) { + for (int_tp h = 0; h < this->height_; ++h) { const unsigned char* ptr_mat = mat_vector[offset + i].ptr(h); - int index = 0; - for (int w = 0; w < this->width_; ++w) { - for (int c = 0; c < this->channels_; ++c) { + int_tp index = 0; + for (int_tp w = 0; w < this->width_; ++w) { + for (int_tp c = 0; c < this->channels_; ++c) { data_index = (i*count) + (c * this->height_ + h) * this->width_ + w; Dtype pixel = static_cast(ptr_mat[index++]); - EXPECT_EQ(static_cast(pixel), data[data_index]); + EXPECT_EQ(static_cast(pixel), data[data_index]); } } } diff --git a/src/caffe/test/test_mergecrop_layer.cpp b/src/caffe/test/test_mergecrop_layer.cpp new file mode 100644 index 00000000000..1c4fb42243e --- /dev/null +++ b/src/caffe/test/test_mergecrop_layer.cpp @@ -0,0 +1,212 @@ +#include +#include + +#include "gtest/gtest.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/layers/mergecrop_layer.hpp" +#include "caffe/test/test_caffe_main.hpp" +#include "caffe/util/math_functions.hpp" + +#ifndef CPU_ONLY // CPU-GPU test + +namespace caffe { + +template +class MergeCropLayerTest : public GPUDeviceTest { + protected: + MergeCropLayerTest() + : blob_bottom_a_(new Blob()), + blob_bottom_b_(new Blob()), + blob_top_(new Blob()) { + } + + virtual void SetUp() { + vector shape_a; + shape_a.push_back(1); + shape_a.push_back(3); + shape_a.push_back(3); + shape_a.push_back(2); + shape_a.push_back(6); + + vector shape_b; + shape_b.push_back(1); + shape_b.push_back(3); + shape_b.push_back(5); + shape_b.push_back(4); + shape_b.push_back(8); + + blob_bottom_a_->Reshape(shape_a); + blob_bottom_b_->Reshape(shape_b); + // fill the values + blob_bottom_vec_.push_back(blob_bottom_a_); + blob_bottom_vec_.push_back(blob_bottom_b_); + blob_top_vec_.push_back(blob_top_); + } + + virtual ~MergeCropLayerTest() { + delete blob_bottom_a_; + delete blob_bottom_b_; + delete blob_top_; + } + + void TestForward() { + vector shape_a = blob_bottom_a_->shape(); + vector shape_b = blob_bottom_b_->shape(); + + for (int_tp i = 0; i < blob_bottom_a_->count(); ++i) { + int val = i; + int out = 0; + int dec = 1; + for (int_tp d = shape_a.size() - 1; d >= 0; --d) { + out += (val % shape_a[d]) * dec; + val /= shape_a[d]; + dec *= 10; + } + blob_bottom_a_->mutable_cpu_data()[i] = out; + // std::cout << i << " - " << out << std::endl; + } + + for (int_tp i = 0; i < blob_bottom_b_->count(); ++i) { + int val = i; + int out = 0; + int dec = 1; + for (int_tp d = shape_b.size() - 1; d >= 0; --d) { + out += (val % shape_b[d]) * dec; + val /= shape_b[d]; + dec *= 10; + } + blob_bottom_b_->mutable_cpu_data()[i] = out; + // std::cout << i << " - " << out << std::endl; + } + + + LayerParameter layer_param; + MergeCropLayer layer(layer_param); + layer.SetUp(blob_bottom_vec_, blob_top_vec_); + + EXPECT_EQ(this->blob_top_->shape(0), this->blob_bottom_a_->shape(0)); + EXPECT_EQ(this->blob_top_->shape(1), this->blob_bottom_a_->shape(1) + + this->blob_bottom_b_->shape(1)); + + for (int i = 2; i < this->blob_top_->shape().size(); ++i) { + EXPECT_EQ(this->blob_top_->shape(i), this->blob_bottom_a_->shape(i)); + } + vector shape_top = blob_top_->shape(); + + layer.Forward(blob_bottom_vec_, blob_top_vec_); + + // Test copy from A & B + for (int_tp i = 0; i < blob_top_->count(); ++i) { + int val = i < blob_bottom_a_->count() ? i : i - blob_bottom_a_->count(); + int out = 0; + int dec = 1; + for (int_tp d = shape_top.size() - 1; d >= 0; --d) { + if (i < blob_bottom_a_->count()) { + out += (val % shape_a[d]) * dec; + val /= shape_a[d]; + dec *= 10; + } else { + out += ((val % shape_a[d]) + (shape_b[d] - shape_a[d]) / 2) * dec; + val /= shape_a[d]; + dec *= 10; + } + } + EXPECT_EQ(out, blob_top_->mutable_cpu_data()[i]); + // std::cout << i << " - " << out << std::endl; + } + } + + void TestBackward() { + vector shape_a = blob_bottom_a_->shape(); + vector shape_b = blob_bottom_b_->shape(); + vector shape_top = blob_top_->shape(); + + for (int_tp i = 0; i < blob_bottom_a_->count(); ++i) { + int val = i; + int out = 0; + int dec = 1; + for (int_tp d = shape_a.size() - 1; d >= 0; --d) { + out += (val % shape_a[d]) * dec; + val /= shape_a[d]; + dec *= 10; + } + blob_bottom_a_->mutable_cpu_data()[i] = out; + // std::cout << i << " - " << out << std::endl; + } + + for (int_tp i = 0; i < blob_bottom_b_->count(); ++i) { + int val = i; + int out = 0; + int dec = 1; + for (int_tp d = shape_b.size() - 1; d >= 0; --d) { + out += (val % shape_b[d]) * dec; + val /= shape_b[d]; + dec *= 10; + } + blob_bottom_b_->mutable_cpu_data()[i] = out; + // std::cout << i << " - " << out << std::endl; + } + + LayerParameter layer_param; + MergeCropLayer layer(layer_param); + layer.SetUp(blob_bottom_vec_, blob_top_vec_); + + layer.Forward(blob_bottom_vec_, blob_top_vec_); + caffe_cpu_copy(blob_top_->count(), blob_top_->cpu_data(), + blob_top_->mutable_cpu_diff()); + + vector propagate_down(blob_bottom_vec_.size(), true); + layer.Backward(blob_top_vec_, propagate_down, blob_bottom_vec_); + + // Test copy to A + for (int_tp i = 0; i < blob_bottom_a_->count(); ++i) { + int val = i; + int out = 0; + int dec = 1; + for (int_tp d = shape_a.size() - 1; d >= 0; --d) { + out += (val % shape_a[d]) * dec; + val /= shape_a[d]; + dec *= 10; + } + EXPECT_EQ(out, blob_bottom_a_->mutable_cpu_data()[i]); + // std::cout << i << " - " << out << std::endl; + } + } + + Blob* const blob_bottom_a_; + Blob* const blob_bottom_b_; + Blob* const blob_top_; + + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +TYPED_TEST_CASE(MergeCropLayerTest, TestDtypes); + +TYPED_TEST(MergeCropLayerTest, TestSetup) { + LayerParameter layer_param; + MergeCropLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + EXPECT_EQ(this->blob_top_->shape(0), this->blob_bottom_a_->shape(0)); + EXPECT_EQ(this->blob_top_->shape(1), this->blob_bottom_a_->shape(1) + + this->blob_bottom_b_->shape(1)); + + for (int i = 2; i < this->blob_top_->shape().size(); ++i) { + EXPECT_EQ(this->blob_top_->shape(i), this->blob_bottom_a_->shape(i)); + } +} + +TYPED_TEST(MergeCropLayerTest, TestForward) { + this->TestForward(); +} + +TYPED_TEST(MergeCropLayerTest, TestBackward) { + this->TestBackward(); +} + +} // namespace caffe +#endif // !CPU_ONLY diff --git a/src/caffe/test/test_multinomial_logistic_loss_layer.cpp b/src/caffe/test/test_multinomial_logistic_loss_layer.cpp index 8cc21022305..7b1725c2205 100644 --- a/src/caffe/test/test_multinomial_logistic_loss_layer.cpp +++ b/src/caffe/test/test_multinomial_logistic_loss_layer.cpp @@ -19,13 +19,13 @@ class MultinomialLogisticLossLayerTest : public CPUDeviceTest { : blob_bottom_data_(new Blob(10, 5, 1, 1)), blob_bottom_label_(new Blob(10, 1, 1, 1)), blob_top_loss_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; PositiveUnitballFiller filler(filler_param); filler.Fill(this->blob_bottom_data_); blob_bottom_vec_.push_back(blob_bottom_data_); - for (int i = 0; i < blob_bottom_label_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_label_->count(); ++i) { blob_bottom_label_->mutable_cpu_data()[i] = caffe_rng_rand() % 5; } blob_bottom_vec_.push_back(blob_bottom_label_); diff --git a/src/caffe/test/test_mvn_layer.cpp b/src/caffe/test/test_mvn_layer.cpp index 28a762d2741..377b2b85357 100644 --- a/src/caffe/test/test_mvn_layer.cpp +++ b/src/caffe/test/test_mvn_layer.cpp @@ -42,16 +42,16 @@ TYPED_TEST(MVNLayerTest, TestForward) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Test mean - int num = this->blob_bottom_->num(); - int channels = this->blob_bottom_->channels(); - int height = this->blob_bottom_->height(); - int width = this->blob_bottom_->width(); + int_tp num = this->blob_bottom_->num(); + int_tp channels = this->blob_bottom_->channels(); + int_tp height = this->blob_bottom_->height(); + int_tp width = this->blob_bottom_->width(); - for (int i = 0; i < num; ++i) { - for (int j = 0; j < channels; ++j) { + for (int_tp i = 0; i < num; ++i) { + for (int_tp j = 0; j < channels; ++j) { Dtype sum = 0, var = 0; - for (int k = 0; k < height; ++k) { - for (int l = 0; l < width; ++l) { + for (int_tp k = 0; k < height; ++k) { + for (int_tp l = 0; l < width; ++l) { Dtype data = this->blob_top_->data_at(i, j, k, l); sum += data; var += data * data; @@ -78,16 +78,16 @@ TYPED_TEST(MVNLayerTest, TestForwardMeanOnly) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Test mean - int num = this->blob_bottom_->num(); - int channels = this->blob_bottom_->channels(); - int height = this->blob_bottom_->height(); - int width = this->blob_bottom_->width(); + int_tp num = this->blob_bottom_->num(); + int_tp channels = this->blob_bottom_->channels(); + int_tp height = this->blob_bottom_->height(); + int_tp width = this->blob_bottom_->width(); - for (int i = 0; i < num; ++i) { - for (int j = 0; j < channels; ++j) { + for (int_tp i = 0; i < num; ++i) { + for (int_tp j = 0; j < channels; ++j) { Dtype sum = 0, var = 0; - for (int k = 0; k < height; ++k) { - for (int l = 0; l < width; ++l) { + for (int_tp k = 0; k < height; ++k) { + for (int_tp l = 0; l < width; ++l) { Dtype data = this->blob_top_->data_at(i, j, k, l); sum += data; var += data * data; @@ -111,16 +111,16 @@ TYPED_TEST(MVNLayerTest, TestForwardAcrossChannels) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Test mean - int num = this->blob_bottom_->num(); - int channels = this->blob_bottom_->channels(); - int height = this->blob_bottom_->height(); - int width = this->blob_bottom_->width(); + int_tp num = this->blob_bottom_->num(); + int_tp channels = this->blob_bottom_->channels(); + int_tp height = this->blob_bottom_->height(); + int_tp width = this->blob_bottom_->width(); - for (int i = 0; i < num; ++i) { + for (int_tp i = 0; i < num; ++i) { Dtype sum = 0, var = 0; - for (int j = 0; j < channels; ++j) { - for (int k = 0; k < height; ++k) { - for (int l = 0; l < width; ++l) { + for (int_tp j = 0; j < channels; ++j) { + for (int_tp k = 0; k < height; ++k) { + for (int_tp l = 0; l < width; ++l) { Dtype data = this->blob_top_->data_at(i, j, k, l); sum += data; var += data * data; @@ -142,7 +142,7 @@ TYPED_TEST(MVNLayerTest, TestGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; MVNLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } diff --git a/src/caffe/test/test_net.cpp b/src/caffe/test/test_net.cpp index ab4afba1a93..b48f4341e16 100644 --- a/src/caffe/test/test_net.cpp +++ b/src/caffe/test/test_net.cpp @@ -21,12 +21,12 @@ class NetTest : public MultiDeviceTest { typedef typename TypeParam::Dtype Dtype; protected: - NetTest() : seed_(1701) {} + NetTest() : seed_(1702) {} virtual void InitNetFromProtoString(const string& proto) { NetParameter param; CHECK(google::protobuf::TextFormat::ParseFromString(proto, ¶m)); - net_.reset(new Net(param)); + net_.reset(new Net(param, Caffe::GetDefaultDevice())); } virtual void CopyNetBlobs(const bool copy_diff, @@ -36,7 +36,7 @@ class NetTest : public MultiDeviceTest { blobs_copy->clear(); blobs_copy->resize(net_blobs.size()); const bool kReshape = true; - for (int i = 0; i < net_blobs.size(); ++i) { + for (int_tp i = 0; i < net_blobs.size(); ++i) { (*blobs_copy)[i].reset(new Blob()); (*blobs_copy)[i]->CopyFrom(*net_blobs[i], copy_diff, kReshape); } @@ -49,7 +49,7 @@ class NetTest : public MultiDeviceTest { params_copy->clear(); params_copy->resize(net_params.size()); const bool kReshape = true; - for (int i = 0; i < net_params.size(); ++i) { + for (int_tp i = 0; i < net_params.size(); ++i) { (*params_copy)[i].reset(new Blob()); (*params_copy)[i]->CopyFrom(*net_params[i], copy_diff, kReshape); } @@ -713,7 +713,7 @@ class NetTest : public MultiDeviceTest { InitNetFromProtoString(proto); } - int seed_; + int_tp seed_; shared_ptr > net_; }; @@ -818,7 +818,7 @@ TYPED_TEST(NetTest, TestLossWeight) { // In this case, the loss weight for the 'EuclideanLoss' layer should default // to 1. vector*> bottom; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); const bool kForceBackward = true; this->InitUnsharedWeightsNet(NULL, NULL, kForceBackward); const Dtype loss = this->net_->ForwardBackward(bottom); @@ -831,10 +831,10 @@ TYPED_TEST(NetTest, TestLossWeight) { const Dtype kMinLossAbsValue = 1e-2; ASSERT_GE(fabs(loss), kMinLossAbsValue); const Dtype kErrorMargin = 1e-4; - const int kNumLossWeights = 6; + const int_tp kNumLossWeights = 6; Dtype kLossWeights[kNumLossWeights] = {2, 0, 1, -1, -2.5, 3.7}; - for (int i = 0; i < kNumLossWeights; ++i) { - Caffe::set_random_seed(this->seed_); + for (int_tp i = 0; i < kNumLossWeights; ++i) { + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&kLossWeights[i], NULL, kForceBackward); const Dtype weighted_loss = this->net_->ForwardBackward(bottom); const Dtype error_margin = kErrorMargin * fabs(kLossWeights[i]); @@ -843,9 +843,9 @@ TYPED_TEST(NetTest, TestLossWeight) { const vector > >& weighted_blobs = this->net_->blobs(); ASSERT_EQ(blob_grads.size(), weighted_blobs.size()); - for (int j = 0; j < blob_grads.size(); ++j) { + for (int_tp j = 0; j < blob_grads.size(); ++j) { ASSERT_EQ(blob_grads[j]->count(), weighted_blobs[j]->count()); - for (int k = 0; k < blob_grads[j]->count(); ++k) { + for (int_tp k = 0; k < blob_grads[j]->count(); ++k) { EXPECT_NEAR(blob_grads[j]->cpu_diff()[k] * kLossWeights[i], weighted_blobs[j]->cpu_diff()[k], error_margin); } @@ -853,9 +853,9 @@ TYPED_TEST(NetTest, TestLossWeight) { const vector > >& weighted_params = this->net_->params(); ASSERT_EQ(param_grads.size(), weighted_params.size()); - for (int j = 0; j < param_grads.size(); ++j) { + for (int_tp j = 0; j < param_grads.size(); ++j) { ASSERT_EQ(param_grads[j]->count(), weighted_params[j]->count()); - for (int k = 0; k < param_grads[j]->count(); ++k) { + for (int_tp k = 0; k < param_grads[j]->count(); ++k) { EXPECT_NEAR(param_grads[j]->cpu_diff()[k] * kLossWeights[i], weighted_params[j]->cpu_diff()[k], error_margin); } @@ -866,7 +866,7 @@ TYPED_TEST(NetTest, TestLossWeight) { TYPED_TEST(NetTest, TestLossWeightMidNet) { typedef typename TypeParam::Dtype Dtype; vector*> bottom; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); const bool kForceBackward = true; Dtype loss_weight = 0; Dtype midnet_loss_weight = 1; @@ -881,10 +881,10 @@ TYPED_TEST(NetTest, TestLossWeightMidNet) { const Dtype kMinLossAbsValue = 1e-2; ASSERT_GE(fabs(loss), kMinLossAbsValue); const Dtype kErrorMargin = 1e-4; - const int kNumLossWeights = 6; + const int_tp kNumLossWeights = 6; Dtype kLossWeights[kNumLossWeights] = {2, 0, 1, -1, -2.5, 3.7}; - for (int i = 0; i < kNumLossWeights; ++i) { - Caffe::set_random_seed(this->seed_); + for (int_tp i = 0; i < kNumLossWeights; ++i) { + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&loss_weight, &kLossWeights[i], kForceBackward); const Dtype weighted_loss = this->net_->ForwardBackward(bottom); @@ -894,7 +894,7 @@ TYPED_TEST(NetTest, TestLossWeightMidNet) { const shared_ptr >& weighted_blob = this->net_->blob_by_name("data"); ASSERT_EQ(data_grad.count(), weighted_blob->count()); - for (int j = 0; j < data_grad.count(); ++j) { + for (int_tp j = 0; j < data_grad.count(); ++j) { EXPECT_NEAR(data_grad.cpu_diff()[j] * kLossWeights[i], weighted_blob->cpu_diff()[j], error_margin); } @@ -913,7 +913,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { // 'InnerProduct' weight 1. loss_weight = 1; midnet_loss_weight = 1; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&loss_weight, &midnet_loss_weight, kForceBackward); const Dtype loss = this->net_->ForwardBackward(bottom); @@ -925,7 +925,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { loss_weight = 2; midnet_loss_weight = 1; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&loss_weight, &midnet_loss_weight, kForceBackward); const Dtype loss_main_2 = this->net_->ForwardBackward(bottom); @@ -936,7 +936,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { loss_weight = 3; midnet_loss_weight = 1; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&loss_weight, &midnet_loss_weight, kForceBackward); const Dtype loss_main_3 = this->net_->ForwardBackward(bottom); @@ -944,7 +944,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { this->net_->blobs(); ASSERT_EQ(blob_grads.size(), blob_grads_loss_3.size()); ASSERT_EQ(blob_grads_loss_2.size(), blob_grads_loss_3.size()); - for (int j = 0; j < blob_grads.size(); ++j) { + for (int_tp j = 0; j < blob_grads.size(); ++j) { const string& blob_name = this->net_->blob_names()[j]; bool grad_should_change = true; if (blob_name == "innerproduct1_innerproduct1_0_split_0") { @@ -952,7 +952,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { } ASSERT_EQ(blob_grads[j]->count(), blob_grads_loss_3[j]->count()); ASSERT_EQ(blob_grads_loss_2[j]->count(), blob_grads_loss_3[j]->count()); - for (int k = 0; k < blob_grads[j]->count(); ++k) { + for (int_tp k = 0; k < blob_grads[j]->count(); ++k) { const Dtype grad_diff_2 = blob_grads_loss_2[j]->cpu_diff()[k] - blob_grads[j]->cpu_diff()[k]; const Dtype grad_diff_3 = blob_grads_loss_3[j]->cpu_diff()[k] - @@ -971,7 +971,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { loss_weight = 1; midnet_loss_weight = 2; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&loss_weight, &midnet_loss_weight, kForceBackward); const Dtype loss_midnet_2 = this->net_->ForwardBackward(bottom); @@ -980,7 +980,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { loss_weight = 1; midnet_loss_weight = 3; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitUnsharedWeightsNet(&loss_weight, &midnet_loss_weight, kForceBackward); const Dtype loss_midnet_3 = this->net_->ForwardBackward(bottom); @@ -989,7 +989,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { ASSERT_EQ(blob_grads.size(), blob_grads_midnet_loss_3.size()); ASSERT_EQ(blob_grads_loss_2.size(), blob_grads_midnet_loss_3.size()); const vector& blob_names = this->net_->blob_names(); - for (int j = 0; j < blob_grads.size(); ++j) { + for (int_tp j = 0; j < blob_grads.size(); ++j) { const string& blob_name = blob_names[j]; bool grad_should_change = false; if (blob_name == "innerproduct1" || @@ -999,7 +999,7 @@ TYPED_TEST(NetTest, TestComboLossWeight) { } ASSERT_EQ(blob_grads[j]->count(), blob_grads_midnet_loss_3[j]->count()); ASSERT_EQ(blob_grads[j]->count(), blob_grads_loss_2[j]->count()); - for (int k = 0; k < blob_grads[j]->count(); ++k) { + for (int_tp k = 0; k < blob_grads[j]->count(); ++k) { const Dtype grad_diff_2 = blob_grads_loss_2[j]->cpu_diff()[k] - blob_grads[j]->cpu_diff()[k]; const Dtype grad_diff_3 = blob_grads_midnet_loss_3[j]->cpu_diff()[k] - @@ -1069,10 +1069,10 @@ TYPED_TEST(NetTest, TestUnsharedWeightsDiffNet) { net->Backward(); Layer* ip1_layer = net->layer_by_name("innerproduct1").get(); Layer* ip2_layer = net->layer_by_name("innerproduct2").get(); - const int count = ip1_layer->blobs()[0]->count(); + const int_tp count = ip1_layer->blobs()[0]->count(); const Dtype* grad1 = ip1_layer->blobs()[0]->cpu_diff(); const Dtype* grad2 = ip2_layer->blobs()[0]->cpu_diff(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_GT(fabs(grad1[i]), 0); EXPECT_FLOAT_EQ(-1 * grad1[i], grad2[i]); } @@ -1089,10 +1089,10 @@ TYPED_TEST(NetTest, TestSharedWeightsDiffNet) { EXPECT_FLOAT_EQ(loss, 0); Layer* ip1_layer = net->layer_by_name("innerproduct1").get(); Layer* ip2_layer = net->layer_by_name("innerproduct2").get(); - const int count = ip1_layer->blobs()[0]->count(); + const int_tp count = ip1_layer->blobs()[0]->count(); const Dtype* grad1 = ip1_layer->blobs()[0]->cpu_diff(); const Dtype* grad2 = ip2_layer->blobs()[0]->cpu_diff(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_FLOAT_EQ(0, grad1[i]); EXPECT_FLOAT_EQ(0, grad2[i]); } @@ -1100,7 +1100,7 @@ TYPED_TEST(NetTest, TestSharedWeightsDiffNet) { TYPED_TEST(NetTest, TestSharedWeightsUpdate) { typedef typename TypeParam::Dtype Dtype; - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitDiffDataSharedWeightsNet(); vector*> bottom; EXPECT_EQ(this->net_->layer_names()[1], "innerproduct1"); @@ -1119,9 +1119,9 @@ TYPED_TEST(NetTest, TestSharedWeightsUpdate) { const bool copy_diff = false; shared_params.CopyFrom(*ip1_weights, copy_diff, reshape); shared_params.CopyFrom(*ip1_weights, !copy_diff, reshape); - const int count = ip1_weights->count(); + const int_tp count = ip1_weights->count(); // Make sure the diffs are non-trivial. - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NE(0, ip1_weights->cpu_diff()[i]); } caffe_axpy(count, Dtype(-1), shared_params.cpu_diff(), @@ -1129,14 +1129,14 @@ TYPED_TEST(NetTest, TestSharedWeightsUpdate) { const Dtype* expected_updated_params = shared_params.cpu_data(); this->net_->Update(); const Dtype* actual_updated_params = ip1_weights->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_EQ(expected_updated_params[i], actual_updated_params[i]); } // Check that data blobs of shared weights STILL point to the same memory // location (because ... who knows). EXPECT_EQ(ip1_weights->cpu_data(), ip2_weights->cpu_data()); - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitDiffDataUnsharedWeightsNet(); EXPECT_EQ(this->net_->layer_names()[1], "innerproduct1"); EXPECT_EQ(this->net_->layer_names()[2], "innerproduct2"); @@ -1151,12 +1151,12 @@ TYPED_TEST(NetTest, TestSharedWeightsUpdate) { // Compute the expected update. Blob unshared_params1; unshared_params1.CopyFrom(*ip1_weights, copy_diff, reshape); - unshared_params1.CopyFrom(*ip1_weights, !copy_diff, reshape); + unshared_params1.CopyFrom(*ip1_weights, !copy_diff, reshape); Blob unshared_params2; unshared_params2.CopyFrom(*ip2_weights, copy_diff, reshape); unshared_params2.CopyFrom(*ip2_weights, !copy_diff, reshape); // Make sure the diffs are non-trivial and sum to the diff in the shared net. - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NE(0, ip1_weights->cpu_diff()[i]); EXPECT_NE(0, ip2_weights->cpu_diff()[i]); EXPECT_NE(ip1_weights->cpu_diff()[i], ip2_weights->cpu_diff()[i]); @@ -1172,7 +1172,7 @@ TYPED_TEST(NetTest, TestSharedWeightsUpdate) { this->net_->Update(); const Dtype* actual_updated_params1 = ip1_weights->cpu_data(); const Dtype* actual_updated_params2 = ip2_weights->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_EQ(expected_updated_params1[i], actual_updated_params1[i]); EXPECT_EQ(expected_updated_params2[i], actual_updated_params2[i]); EXPECT_NE(actual_updated_params1[i], actual_updated_params2[i]); @@ -1184,7 +1184,7 @@ TYPED_TEST(NetTest, TestSharedWeightsResume) { typedef typename TypeParam::Dtype Dtype; // Create a net with weight sharing; Update it once. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitDiffDataSharedWeightsNet(); vector*> bottom; EXPECT_EQ(this->net_->layer_names()[1], "innerproduct1"); @@ -1201,7 +1201,7 @@ TYPED_TEST(NetTest, TestSharedWeightsResume) { const bool kReshape = true; const bool kCopyDiff = false; shared_params.CopyFrom(*ip1_weights, kCopyDiff, kReshape); - const int count = ip1_weights->count(); + const int_tp count = ip1_weights->count(); // Write the net to a NetParameter, as in Solver::Snapshot. NetParameter net_param; @@ -1209,7 +1209,7 @@ TYPED_TEST(NetTest, TestSharedWeightsResume) { // Reinitialize the net and copy parameters from net_param, as in // Solver::Restore. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); this->InitDiffDataSharedWeightsNet(); this->net_->CopyTrainedLayersFrom(net_param); ip1_weights = this->net_->layers()[1]->blobs()[0].get(); @@ -1221,7 +1221,7 @@ TYPED_TEST(NetTest, TestSharedWeightsResume) { // locations. EXPECT_EQ(ip1_weights->cpu_data(), ip2_weights->cpu_data()); EXPECT_EQ(ip1_weights->cpu_diff(), ip2_weights->cpu_diff()); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_FLOAT_EQ(shared_params.cpu_data()[i], ip1_weights->cpu_data()[i]); } } @@ -1234,18 +1234,18 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { const Dtype* kLossWeight2 = NULL; // Run the net with all params learned; check that gradients are non-zero. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); Dtype blobs_lr_w1 = 1, blobs_lr_w2 = 1, blobs_lr_b1 = 2, blobs_lr_b2 = 2; this->InitUnsharedWeightsNet(kLossWeight1, kLossWeight2, kForceBackward, kBiasTerm, blobs_lr_w1, blobs_lr_w2, blobs_lr_b1, blobs_lr_b2); this->net_->Forward(bottom); this->net_->Backward(); const vector > >& params = this->net_->params(); - const int num_params = params.size(); + const int_tp num_params = params.size(); ASSERT_EQ(4, num_params); const Dtype kNonZeroTestMin = 1e-3; vector param_asums(params.size()); - for (int i = 0; i < num_params; ++i) { + for (int_tp i = 0; i < num_params; ++i) { const Dtype param_asum = caffe_cpu_asum(params[i]->count(), params[i]->cpu_diff()); param_asums[i] = param_asum; @@ -1254,7 +1254,7 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { // Change the learning rates to different non-zero values; should see same // gradients. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); blobs_lr_w1 *= 2, blobs_lr_w2 *= 2, blobs_lr_b1 *= 2, blobs_lr_b2 *= 2; this->InitUnsharedWeightsNet(kLossWeight1, kLossWeight2, kForceBackward, kBiasTerm, blobs_lr_w1, blobs_lr_w2, blobs_lr_b1, blobs_lr_b2); @@ -1262,7 +1262,7 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { this->net_->Backward(); const vector > >& params2 = this->net_->params(); ASSERT_EQ(num_params, params2.size()); - for (int i = 0; i < num_params; ++i) { + for (int_tp i = 0; i < num_params; ++i) { const Dtype param_asum = caffe_cpu_asum(params2[i]->count(), params2[i]->cpu_diff()); EXPECT_FLOAT_EQ(param_asum, param_asums[i]); @@ -1270,7 +1270,7 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { // Change a subset of the learning rates to zero; check that we see zero // gradients for those. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); blobs_lr_w1 = 1, blobs_lr_w2 = 0, blobs_lr_b1 = 0, blobs_lr_b2 = 1; this->InitUnsharedWeightsNet(kLossWeight1, kLossWeight2, kForceBackward, kBiasTerm, blobs_lr_w1, blobs_lr_w2, blobs_lr_b1, blobs_lr_b2); @@ -1278,7 +1278,7 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { this->net_->Backward(); const vector > >& params3 = this->net_->params(); ASSERT_EQ(num_params, params3.size()); - for (int i = 0; i < num_params; ++i) { + for (int_tp i = 0; i < num_params; ++i) { const Dtype param_asum = caffe_cpu_asum(params3[i]->count(), params3[i]->cpu_diff()); if (i == 1 || i == 2) { @@ -1289,7 +1289,7 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { } // Change the opposite subset of the learning rates to zero. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); blobs_lr_w1 = 0, blobs_lr_w2 = 1, blobs_lr_b1 = 1, blobs_lr_b2 = 0; this->InitUnsharedWeightsNet(kLossWeight1, kLossWeight2, kForceBackward, kBiasTerm, blobs_lr_w1, blobs_lr_w2, blobs_lr_b1, blobs_lr_b2); @@ -1297,7 +1297,7 @@ TYPED_TEST(NetTest, TestParamPropagateDown) { this->net_->Backward(); const vector > >& params4 = this->net_->params(); ASSERT_EQ(num_params, params4.size()); - for (int i = 0; i < num_params; ++i) { + for (int_tp i = 0; i < num_params; ++i) { const Dtype param_asum = caffe_cpu_asum(params4[i]->count(), params4[i]->cpu_diff()); if (i == 0 || i == 3) { @@ -1322,7 +1322,7 @@ TYPED_TEST(NetTest, TestFromTo) { Dtype loss = *loss_ptr; // Check that combining partial Forwards gives the same loss. - for (int i = 1; i < this->net_->layers().size(); ++i) { + for (int_tp i = 1; i < this->net_->layers().size(); ++i) { // Note that we skip layer zero to keep the same data. this->net_->ForwardFromTo(1, 1); if (i < this->net_->layers().size() - 1) { @@ -1332,10 +1332,10 @@ TYPED_TEST(NetTest, TestFromTo) { } // Check that combining partial Backwards gives the same data diff. - for (int i = 1; i < this->net_->layers().size(); ++i) { + for (int_tp i = 1; i < this->net_->layers().size(); ++i) { this->net_->BackwardTo(i); this->net_->BackwardFrom(i - 1); - for (int j = 0; j < data.count(); ++j) { + for (int_tp j = 0; j < data.count(); ++j) { EXPECT_EQ(data.cpu_diff()[j], this->net_->blob_by_name("data")->cpu_diff()[j]); } @@ -2264,7 +2264,7 @@ TYPED_TEST(NetTest, TestReshape) { // We set up bottom blobs of two different sizes, switch between // them, check that forward and backward both run and the results // are the same, and check that the output shapes change. - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); Caffe::set_mode(Caffe::CPU); FillerParameter filler_param; filler_param.set_std(1); @@ -2305,7 +2305,7 @@ TYPED_TEST(NetTest, TestReshape) { caffe_copy(blob1.count(), blob1.cpu_data(), input_blob->mutable_cpu_data()); this->net_->ForwardPrefilled(); this->net_->Backward(); - for (int i = 0; i < output1.count(); ++i) { + for (int_tp i = 0; i < output1.count(); ++i) { EXPECT_FLOAT_EQ(*(output1.cpu_data() + i), *(output_blob->cpu_data() + i)); } @@ -2314,15 +2314,15 @@ TYPED_TEST(NetTest, TestReshape) { caffe_copy(blob2.count(), blob2.cpu_data(), input_blob->mutable_cpu_data()); this->net_->ForwardPrefilled(); this->net_->Backward(); - for (int i = 0; i < output2.count(); ++i) { + for (int_tp i = 0; i < output2.count(); ++i) { EXPECT_FLOAT_EQ(*(output2.cpu_data() + i), *(output_blob->cpu_data() + i)); } EXPECT_EQ(output1.num(), blob1.num()); EXPECT_EQ(output2.num(), blob2.num()); bool same_spatial_shape = true; - const int kFirstSpatialAxis = 2; - for (int i = kFirstSpatialAxis; i < output1.num_axes(); ++i) { + const int_tp kFirstSpatialAxis = 2; + for (int_tp i = kFirstSpatialAxis; i < output1.num_axes(); ++i) { if (output1.shape(i) != output2.shape(i)) { same_spatial_shape = false; break; @@ -2335,7 +2335,8 @@ TYPED_TEST(NetTest, TestSkipPropagateDown) { // check bottom_need_backward if propagate_down is true this->InitSkipPropNet(false); vector vec_layer_need_backward = this->net_->layer_need_backward(); - for (int layer_id = 0; layer_id < this->net_->layers().size(); ++layer_id) { +for (int_tp layer_id = 0; layer_id < this->net_->layers().size(); + ++layer_id) { string layer_name = this->net_->layer_names()[layer_id]; if (layer_name == "loss") { // access to bottom_need_backward coresponding to label's blob @@ -2358,7 +2359,8 @@ TYPED_TEST(NetTest, TestSkipPropagateDown) { this->InitSkipPropNet(true); vec_layer_need_backward.clear(); vec_layer_need_backward = this->net_->layer_need_backward(); - for (int layer_id = 0; layer_id < this->net_->layers().size(); ++layer_id) { + for (int_tp layer_id = 0; layer_id < this->net_->layers().size(); + ++layer_id) { string layer_name = this->net_->layer_names()[layer_id]; if (layer_name == "loss") { // access to bottom_need_backward coresponding to label's blob diff --git a/src/caffe/test/test_neuron_layer.cpp b/src/caffe/test/test_neuron_layer.cpp index dd591f7d204..fe52ec94fe3 100644 --- a/src/caffe/test/test_neuron_layer.cpp +++ b/src/caffe/test/test_neuron_layer.cpp @@ -41,7 +41,7 @@ class NeuronLayerTest : public MultiDeviceTest { NeuronLayerTest() : blob_bottom_(new Blob(2, 3, 4, 5)), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -70,10 +70,10 @@ class NeuronLayerTest : public MultiDeviceTest { const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); float scale = 1. / (1. - layer_param.dropout_param().dropout_ratio()); - const int count = this->blob_bottom_->count(); + const int_tp count = this->blob_bottom_->count(); // Initialize num_kept to count the number of inputs NOT dropped out. - int num_kept = 0; - for (int i = 0; i < count; ++i) { + int_tp num_kept = 0; + for (int_tp i = 0; i < count; ++i) { if (top_data[i] != 0) { ++num_kept; EXPECT_EQ(top_data[i], bottom_data[i] * scale); @@ -95,10 +95,10 @@ class NeuronLayerTest : public MultiDeviceTest { ExpLayer layer(layer_param); layer.SetUp(blob_bottom_vec_, blob_top_vec_); layer.Forward(blob_bottom_vec_, blob_top_vec_); - const Dtype kDelta = 2e-4; + const Dtype kDelta = 2e-2; const Dtype* bottom_data = blob_bottom_->cpu_data(); const Dtype* top_data = blob_top_->cpu_data(); - for (int i = 0; i < blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_->count(); ++i) { const Dtype bottom_val = bottom_data[i]; const Dtype top_val = top_data[i]; if (base == -1) { @@ -115,7 +115,7 @@ class NeuronLayerTest : public MultiDeviceTest { layer_param.mutable_exp_param()->set_scale(scale); layer_param.mutable_exp_param()->set_shift(shift); ExpLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientEltwise(&layer, blob_bottom_vec_, blob_top_vec_); } @@ -125,11 +125,11 @@ class NeuronLayerTest : public MultiDeviceTest { const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); const Dtype* slope_data = layer->blobs()[0]->cpu_data(); - int hw = this->blob_bottom_->height() * this->blob_bottom_->width(); - int channels = this->blob_bottom_->channels(); + int_tp hw = this->blob_bottom_->height() * this->blob_bottom_->width(); + int_tp channels = this->blob_bottom_->channels(); bool channel_shared = layer->layer_param().prelu_param().channel_shared(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - int c = channel_shared ? 0 : (i / hw) % channels; + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + int_tp c = channel_shared ? 0 : (i / hw) % channels; EXPECT_EQ(top_data[i], std::max(bottom_data[i], (Dtype)(0)) + slope_data[c] * std::min(bottom_data[i], (Dtype)(0))); @@ -153,10 +153,10 @@ class NeuronLayerTest : public MultiDeviceTest { LogLayer layer(layer_param); layer.SetUp(blob_bottom_vec_, blob_top_vec_); layer.Forward(blob_bottom_vec_, blob_top_vec_); - const Dtype kDelta = 2e-4; + const Dtype kDelta = 2e-3; const Dtype* bottom_data = blob_bottom_->cpu_data(); const Dtype* top_data = blob_top_->cpu_data(); - for (int i = 0; i < blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_->count(); ++i) { const Dtype bottom_val = bottom_data[i]; const Dtype top_val = top_data[i]; if (base == -1) { @@ -175,7 +175,7 @@ class NeuronLayerTest : public MultiDeviceTest { layer_param.mutable_log_param()->set_scale(scale); layer_param.mutable_log_param()->set_shift(shift); LogLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-2); + GradientChecker checker(1e-2, 1e-1); checker.CheckGradientEltwise(&layer, blob_bottom_vec_, blob_top_vec_); } }; @@ -190,8 +190,8 @@ TYPED_TEST(NeuronLayerTest, TestAbsVal) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); - const int count = this->blob_bottom_->count(); - for (int i = 0; i < count; ++i) { + const int_tp count = this->blob_bottom_->count(); + for (int_tp i = 0; i < count; ++i) { EXPECT_EQ(top_data[i], fabs(bottom_data[i])); } } @@ -200,7 +200,7 @@ TYPED_TEST(NeuronLayerTest, TestAbsGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; AbsValLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + GradientChecker checker(1e-2, 1e-2, 1701, 0., 0.01); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -214,7 +214,7 @@ TYPED_TEST(NeuronLayerTest, TestReLU) { // Now, check values const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_GE(top_data[i], 0.); EXPECT_TRUE(top_data[i] == 0 || top_data[i] == bottom_data[i]); } @@ -224,7 +224,7 @@ TYPED_TEST(NeuronLayerTest, TestReLUGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; ReLULayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + GradientChecker checker(1e-2, 1e-2, 1701, 0., 0.01); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -240,7 +240,7 @@ TYPED_TEST(NeuronLayerTest, TestReLUWithNegativeSlope) { // Now, check values const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { if (top_data[i] >= 0) { EXPECT_FLOAT_EQ(top_data[i], bottom_data[i]); } else { @@ -255,7 +255,7 @@ TYPED_TEST(NeuronLayerTest, TestReLUGradientWithNegativeSlope) { CHECK(google::protobuf::TextFormat::ParseFromString( "relu_param { negative_slope: 0.01 }", &layer_param)); ReLULayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + GradientChecker checker(1e-2, 1e-2, 1701, 0., 0.01); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -327,8 +327,9 @@ TYPED_TEST(NeuronLayerTest, TestSigmoid) { // Now, check values const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - EXPECT_FLOAT_EQ(top_data[i], 1. / (1 + exp(-bottom_data[i]))); + const Dtype kDelta = 2e-3; + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + EXPECT_NEAR(top_data[i], 1. / (1 + exp(-bottom_data[i])), kDelta); // check that we squashed the value between 0 and 1 EXPECT_GE(top_data[i], 0.); EXPECT_LE(top_data[i], 1.); @@ -339,7 +340,7 @@ TYPED_TEST(NeuronLayerTest, TestSigmoidGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; SigmoidLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + GradientChecker checker(1e-2, 1e-2, 1701, 0., 0.01); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -351,10 +352,10 @@ TYPED_TEST(NeuronLayerTest, TestTanH) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Test exact values - for (int i = 0; i < this->blob_bottom_->num(); ++i) { - for (int j = 0; j < this->blob_bottom_->channels(); ++j) { - for (int k = 0; k < this->blob_bottom_->height(); ++k) { - for (int l = 0; l < this->blob_bottom_->width(); ++l) { + for (int_tp i = 0; i < this->blob_bottom_->num(); ++i) { + for (int_tp j = 0; j < this->blob_bottom_->channels(); ++j) { + for (int_tp k = 0; k < this->blob_bottom_->height(); ++k) { + for (int_tp l = 0; l < this->blob_bottom_->width(); ++l) { EXPECT_GE(this->blob_top_->data_at(i, j, k, l) + 1e-4, (exp(2*this->blob_bottom_->data_at(i, j, k, l)) - 1) / (exp(2*this->blob_bottom_->data_at(i, j, k, l)) + 1)); @@ -371,7 +372,7 @@ TYPED_TEST(NeuronLayerTest, TestTanHGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; TanHLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -560,7 +561,7 @@ TYPED_TEST(NeuronLayerTest, TestDropoutTestPhase) { // Now, check values const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { if (top_data[i] != 0) { EXPECT_EQ(top_data[i], bottom_data[i]); } @@ -572,7 +573,7 @@ TYPED_TEST(NeuronLayerTest, TestDropoutGradient) { LayerParameter layer_param; layer_param.set_phase(TRAIN); DropoutLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -582,7 +583,7 @@ TYPED_TEST(NeuronLayerTest, TestDropoutGradientTest) { LayerParameter layer_param; layer_param.set_phase(TEST); DropoutLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -596,7 +597,7 @@ TYPED_TEST(NeuronLayerTest, TestBNLL) { // Now, check values const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_GE(top_data[i], 0.); EXPECT_GE(top_data[i], bottom_data[i]); } @@ -606,7 +607,7 @@ TYPED_TEST(NeuronLayerTest, TestBNLLGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; BNLLLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -617,8 +618,8 @@ TYPED_TEST(NeuronLayerTest, TestPReLUParam) { PReLULayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* slopes = layer.blobs()[0]->cpu_data(); - int count = layer.blobs()[0]->count(); - for (int i = 0; i < count; ++i, ++slopes) { + int_tp count = layer.blobs()[0]->count(); + for (int_tp i = 0; i < count; ++i, ++slopes) { EXPECT_EQ(*slopes, 0.25); } } @@ -651,7 +652,7 @@ TYPED_TEST(NeuronLayerTest, TestPReLUGradient) { FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(layer.blobs()[0].get()); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + GradientChecker checker(1e-2, 1e-2, 1701, 0., 0.01); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -662,7 +663,7 @@ TYPED_TEST(NeuronLayerTest, TestPReLUGradientChannelShared) { layer_param.mutable_prelu_param()->set_channel_shared(true); PReLULayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + GradientChecker checker(1e-2, 1e-2, 1701, 0., 0.01); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -688,7 +689,7 @@ TYPED_TEST(NeuronLayerTest, TestPReLUConsistencyReLU) { // Check forward prelu.Forward(this->blob_bottom_vec_, this->blob_top_vec_); relu.Forward(this->blob_bottom_vec_, blob_top_vec_2); - for (int s = 0; s < blob_top_2->count(); ++s) { + for (int_tp s = 0; s < blob_top_2->count(); ++s) { EXPECT_EQ(this->blob_top_->cpu_data()[s], blob_top_2->cpu_data()[s]); } // Check backward @@ -697,15 +698,15 @@ TYPED_TEST(NeuronLayerTest, TestPReLUConsistencyReLU) { FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(tmp_blob.get()); - caffe_copy(blob_top_2->count(), tmp_blob->cpu_data(), + caffe_cpu_copy(blob_top_2->count(), tmp_blob->cpu_data(), this->blob_top_->mutable_cpu_diff()); - caffe_copy(blob_top_2->count(), tmp_blob->cpu_data(), + caffe_cpu_copy(blob_top_2->count(), tmp_blob->cpu_data(), blob_top_2->mutable_cpu_diff()); vector propagate_down; propagate_down.push_back(true); prelu.Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); relu.Backward(blob_top_vec_2, propagate_down, blob_bottom_vec_2); - for (int s = 0; s < blob_bottom_2->count(); ++s) { + for (int_tp s = 0; s < blob_bottom_2->count(); ++s) { EXPECT_EQ(this->blob_bottom_->cpu_diff()[s], blob_bottom_2->cpu_diff()[s]); } } @@ -739,7 +740,7 @@ TYPED_TEST(NeuronLayerTest, TestPReLUInPlace) { prelu.SetUp(this->blob_top_vec_, this->blob_top_vec_); ip2.SetUp(blob_bottom_vec_2, blob_middle_vec_2); prelu2.SetUp(blob_middle_vec_2, blob_top_vec_2); - caffe_copy(ip2.blobs()[0]->count(), ip.blobs()[0]->cpu_data(), + caffe_cpu_copy(ip2.blobs()[0]->count(), ip.blobs()[0]->cpu_data(), ip2.blobs()[0]->mutable_cpu_data()); // Forward in-place ip.Forward(this->blob_bottom_vec_, this->blob_top_vec_); @@ -748,7 +749,7 @@ TYPED_TEST(NeuronLayerTest, TestPReLUInPlace) { ip2.Forward(blob_bottom_vec_2, blob_middle_vec_2); prelu2.Forward(blob_middle_vec_2, blob_top_vec_2); // Check numbers - for (int s = 0; s < blob_top_2->count(); ++s) { + for (int_tp s = 0; s < blob_top_2->count(); ++s) { EXPECT_EQ(this->blob_top_->cpu_data()[s], blob_top_2->cpu_data()[s]); } // Fill top diff with random numbers @@ -757,9 +758,9 @@ TYPED_TEST(NeuronLayerTest, TestPReLUInPlace) { FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(tmp_blob.get()); - caffe_copy(blob_top_2->count(), tmp_blob->cpu_data(), + caffe_cpu_copy(blob_top_2->count(), tmp_blob->cpu_data(), this->blob_top_->mutable_cpu_diff()); - caffe_copy(blob_top_2->count(), tmp_blob->cpu_data(), + caffe_cpu_copy(blob_top_2->count(), tmp_blob->cpu_data(), blob_top_2->mutable_cpu_diff()); // Backward in-place vector propagate_down; @@ -770,16 +771,16 @@ TYPED_TEST(NeuronLayerTest, TestPReLUInPlace) { prelu2.Backward(blob_top_vec_2, propagate_down, blob_middle_vec_2); ip2.Backward(blob_middle_vec_2, propagate_down, blob_bottom_vec_2); // Check numbers - for (int s = 0; s < blob_bottom_2->count(); ++s) { + for (int_tp s = 0; s < blob_bottom_2->count(); ++s) { EXPECT_EQ(this->blob_bottom_->cpu_diff()[s], blob_bottom_2->cpu_diff()[s]); } - for (int s = 0; s < ip.blobs()[0]->count(); ++s) { + for (int_tp s = 0; s < ip.blobs()[0]->count(); ++s) { EXPECT_EQ(ip.blobs()[0]->cpu_diff()[s], ip2.blobs()[0]->cpu_diff()[s]); } - for (int s = 0; s < ip.blobs()[1]->count(); ++s) { + for (int_tp s = 0; s < ip.blobs()[1]->count(); ++s) { EXPECT_EQ(ip.blobs()[1]->cpu_diff()[s], ip2.blobs()[1]->cpu_diff()[s]); } - for (int s = 0; s < prelu.blobs()[0]->count(); ++s) { + for (int_tp s = 0; s < prelu.blobs()[0]->count(); ++s) { EXPECT_EQ(prelu.blobs()[0]->cpu_diff()[s], prelu2.blobs()[0]->cpu_diff()[s]); } @@ -792,7 +793,7 @@ class CuDNNNeuronLayerTest : public GPUDeviceTest { CuDNNNeuronLayerTest() : blob_bottom_(new Blob(2, 3, 4, 5)), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -810,96 +811,110 @@ class CuDNNNeuronLayerTest : public GPUDeviceTest { TYPED_TEST_CASE(CuDNNNeuronLayerTest, TestDtypes); TYPED_TEST(CuDNNNeuronLayerTest, TestReLUCuDNN) { - LayerParameter layer_param; - CuDNNReLULayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Now, check values - const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); - const TypeParam* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - EXPECT_GE(top_data[i], 0.); - EXPECT_TRUE(top_data[i] == 0 || top_data[i] == bottom_data[i]); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNReLULayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Now, check values + const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); + const TypeParam* top_data = this->blob_top_->cpu_data(); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + EXPECT_GE(top_data[i], 0.); + EXPECT_TRUE(top_data[i] == 0 || top_data[i] == bottom_data[i]); + } } } TYPED_TEST(CuDNNNeuronLayerTest, TestReLUGradientCuDNN) { - LayerParameter layer_param; - CuDNNReLULayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); - checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNReLULayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } TYPED_TEST(CuDNNNeuronLayerTest, TestReLUWithNegativeSlopeCuDNN) { - LayerParameter layer_param; - CHECK(google::protobuf::TextFormat::ParseFromString( - "relu_param { negative_slope: 0.01 }", &layer_param)); - CuDNNReLULayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Now, check values - const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); - const TypeParam* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - if (top_data[i] >= 0) { - EXPECT_FLOAT_EQ(top_data[i], bottom_data[i]); - } else { - EXPECT_FLOAT_EQ(top_data[i], bottom_data[i] * 0.01); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CHECK(google::protobuf::TextFormat::ParseFromString( + "relu_param { negative_slope: 0.01 }", &layer_param)); + CuDNNReLULayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Now, check values + const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); + const TypeParam* top_data = this->blob_top_->cpu_data(); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + if (top_data[i] >= 0) { + EXPECT_FLOAT_EQ(top_data[i], bottom_data[i]); + } else { + EXPECT_FLOAT_EQ(top_data[i], bottom_data[i] * 0.01); + } } } } TYPED_TEST(CuDNNNeuronLayerTest, TestReLUGradientWithNegativeSlopeCuDNN) { - LayerParameter layer_param; - CHECK(google::protobuf::TextFormat::ParseFromString( - "relu_param { negative_slope: 0.01 }", &layer_param)); - CuDNNReLULayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); - checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CHECK(google::protobuf::TextFormat::ParseFromString( + "relu_param { negative_slope: 0.01 }", &layer_param)); + CuDNNReLULayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } TYPED_TEST(CuDNNNeuronLayerTest, TestSigmoidCuDNN) { - LayerParameter layer_param; - CuDNNSigmoidLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Now, check values - const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); - const TypeParam* top_data = this->blob_top_->cpu_data(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { - EXPECT_FLOAT_EQ(top_data[i], 1. / (1 + exp(-bottom_data[i]))); - // check that we squashed the value between 0 and 1 - EXPECT_GE(top_data[i], 0.); - EXPECT_LE(top_data[i], 1.); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNSigmoidLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Now, check values + const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); + const TypeParam* top_data = this->blob_top_->cpu_data(); + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { + EXPECT_FLOAT_EQ(top_data[i], 1. / (1 + exp(-bottom_data[i]))); + // check that we squashed the value between 0 and 1 + EXPECT_GE(top_data[i], 0.); + EXPECT_LE(top_data[i], 1.); + } } } TYPED_TEST(CuDNNNeuronLayerTest, TestSigmoidGradientCuDNN) { - LayerParameter layer_param; - CuDNNSigmoidLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); - checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNSigmoidLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3, 1701, 0., 0.01); + checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } TYPED_TEST(CuDNNNeuronLayerTest, TestTanHCuDNN) { - LayerParameter layer_param; - CuDNNTanHLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Test exact values - for (int i = 0; i < this->blob_bottom_->num(); ++i) { - for (int j = 0; j < this->blob_bottom_->channels(); ++j) { - for (int k = 0; k < this->blob_bottom_->height(); ++k) { - for (int l = 0; l < this->blob_bottom_->width(); ++l) { - EXPECT_GE(this->blob_top_->data_at(i, j, k, l) + 1e-4, - (exp(2*this->blob_bottom_->data_at(i, j, k, l)) - 1) / - (exp(2*this->blob_bottom_->data_at(i, j, k, l)) + 1)); - EXPECT_LE(this->blob_top_->data_at(i, j, k, l) - 1e-4, - (exp(2*this->blob_bottom_->data_at(i, j, k, l)) - 1) / - (exp(2*this->blob_bottom_->data_at(i, j, k, l)) + 1)); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNTanHLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Test exact values + for (int_tp i = 0; i < this->blob_bottom_->num(); ++i) { + for (int_tp j = 0; j < this->blob_bottom_->channels(); ++j) { + for (int_tp k = 0; k < this->blob_bottom_->height(); ++k) { + for (int_tp l = 0; l < this->blob_bottom_->width(); ++l) { + EXPECT_GE(this->blob_top_->data_at(i, j, k, l) + 1e-4, + (exp(2*this->blob_bottom_->data_at(i, j, k, l)) - 1) / + (exp(2*this->blob_bottom_->data_at(i, j, k, l)) + 1)); + EXPECT_LE(this->blob_top_->data_at(i, j, k, l) - 1e-4, + (exp(2*this->blob_bottom_->data_at(i, j, k, l)) - 1) / + (exp(2*this->blob_bottom_->data_at(i, j, k, l)) + 1)); + } } } } @@ -907,11 +922,13 @@ TYPED_TEST(CuDNNNeuronLayerTest, TestTanHCuDNN) { } TYPED_TEST(CuDNNNeuronLayerTest, TestTanHGradientCuDNN) { - LayerParameter layer_param; - CuDNNTanHLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); - checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNTanHLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3); + checker.CheckGradientEltwise(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } #endif diff --git a/src/caffe/test/test_platform.cpp b/src/caffe/test/test_platform.cpp index f3513e08814..ff9b751a4e2 100644 --- a/src/caffe/test/test_platform.cpp +++ b/src/caffe/test/test_platform.cpp @@ -1,4 +1,5 @@ #ifndef CPU_ONLY +#ifdef USE_CUDA #include #include @@ -54,4 +55,5 @@ TEST_F(PlatformTest, TestInitialization) { } // namespace caffe +#endif // USE_CUDA #endif // CPU_ONLY diff --git a/src/caffe/test/test_pooling_layer.cpp b/src/caffe/test/test_pooling_layer.cpp index bb95cae032d..102a44109c6 100644 --- a/src/caffe/test/test_pooling_layer.cpp +++ b/src/caffe/test/test_pooling_layer.cpp @@ -26,7 +26,7 @@ class PoolingLayerTest : public MultiDeviceTest { blob_top_(new Blob()), blob_top_mask_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 3, 6, 5); // fill the values FillerParameter filler_param; @@ -49,16 +49,16 @@ class PoolingLayerTest : public MultiDeviceTest { void TestForwardSquare() { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(2); + pooling_param->add_kernel_size(2); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - const int num = 2; - const int channels = 2; + const int_tp num = 2; + const int_tp channels = 2; blob_bottom_->Reshape(num, channels, 3, 5); // Input: 2x 2 channels of: // [1 2 5 2 3] // [9 4 1 4 8] // [1 2 5 2 3] - for (int i = 0; i < 15 * num * channels; i += 15) { + for (int_tp i = 0; i < 15 * num * channels; i += 15) { blob_bottom_->mutable_cpu_data()[i + 0] = 1; blob_bottom_->mutable_cpu_data()[i + 1] = 2; blob_bottom_->mutable_cpu_data()[i + 2] = 5; @@ -91,7 +91,7 @@ class PoolingLayerTest : public MultiDeviceTest { // Expected output: 2x 2 channels of: // [9 5 5 8] // [9 5 5 8] - for (int i = 0; i < 8 * num * channels; i += 8) { + for (int_tp i = 0; i < 8 * num * channels; i += 8) { EXPECT_EQ(blob_top_->cpu_data()[i + 0], 9); EXPECT_EQ(blob_top_->cpu_data()[i + 1], 5); EXPECT_EQ(blob_top_->cpu_data()[i + 2], 5); @@ -105,7 +105,7 @@ class PoolingLayerTest : public MultiDeviceTest { // Expected mask output: 2x 2 channels of: // [5 2 2 9] // [5 12 12 9] - for (int i = 0; i < 8 * num * channels; i += 8) { + for (int_tp i = 0; i < 8 * num * channels; i += 8) { EXPECT_EQ(blob_top_mask_->cpu_data()[i + 0], 5); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 1], 2); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 2], 2); @@ -124,8 +124,8 @@ class PoolingLayerTest : public MultiDeviceTest { pooling_param->set_kernel_h(3); pooling_param->set_kernel_w(2); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - const int num = 2; - const int channels = 2; + const int_tp num = 2; + const int_tp channels = 2; blob_bottom_->Reshape(num, channels, 6, 6); // Input: 2x 2 channels of: // [35 1 6 26 19 24] @@ -135,7 +135,7 @@ class PoolingLayerTest : public MultiDeviceTest { // [30 5 34 12 14 16] // [ 4 36 29 13 18 11] // (this is generated by magic(6) in MATLAB) - for (int i = 0; i < 36 * num * channels; i += 36) { + for (int_tp i = 0; i < 36 * num * channels; i += 36) { blob_bottom_->mutable_cpu_data()[i + 0] = 35; blob_bottom_->mutable_cpu_data()[i + 1] = 1; blob_bottom_->mutable_cpu_data()[i + 2] = 6; @@ -191,7 +191,7 @@ class PoolingLayerTest : public MultiDeviceTest { // [32 33 33 27 27] // [31 34 34 27 27] // [36 36 34 18 18] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_->cpu_data()[i + 0], 35); EXPECT_EQ(blob_top_->cpu_data()[i + 1], 32); EXPECT_EQ(blob_top_->cpu_data()[i + 2], 26); @@ -218,7 +218,7 @@ class PoolingLayerTest : public MultiDeviceTest { // [ 8 21 21 17 17] // [13 27 27 17 17] // [32 32 27 35 35] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_mask_->cpu_data()[i + 0], 0); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 1], 7); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 2], 3); @@ -249,8 +249,8 @@ class PoolingLayerTest : public MultiDeviceTest { pooling_param->set_kernel_h(2); pooling_param->set_kernel_w(3); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - const int num = 2; - const int channels = 2; + const int_tp num = 2; + const int_tp channels = 2; blob_bottom_->Reshape(num, channels, 6, 6); // Input: 2x 2 channels of: // [35 1 6 26 19 24] @@ -260,7 +260,7 @@ class PoolingLayerTest : public MultiDeviceTest { // [30 5 34 12 14 16] // [ 4 36 29 13 18 11] // (this is generated by magic(6) in MATLAB) - for (int i = 0; i < 36 * num * channels; i += 36) { + for (int_tp i = 0; i < 36 * num * channels; i += 36) { blob_bottom_->mutable_cpu_data()[i + 0] = 35; blob_bottom_->mutable_cpu_data()[i + 1] = 1; blob_bottom_->mutable_cpu_data()[i + 2] = 6; @@ -317,7 +317,7 @@ class PoolingLayerTest : public MultiDeviceTest { // [33 33 33 27] // [34 34 34 17] // [36 36 34 18] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_->cpu_data()[i + 0], 35); EXPECT_EQ(blob_top_->cpu_data()[i + 1], 32); EXPECT_EQ(blob_top_->cpu_data()[i + 2], 26); @@ -345,7 +345,7 @@ class PoolingLayerTest : public MultiDeviceTest { // [21 21 21 17] // [27 27 27 22] // [32 32 27 35] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_mask_->cpu_data()[i + 0], 0); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 1], 7); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 2], 3); @@ -377,8 +377,8 @@ TYPED_TEST(PoolingLayerTest, TestSetup) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); @@ -391,9 +391,9 @@ TYPED_TEST(PoolingLayerTest, TestSetupPadded) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); - pooling_param->set_pad(1); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); + pooling_param->add_pad(1); pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); @@ -420,24 +420,24 @@ TYPED_TEST(PoolingLayerTest, TestSetupGlobalPooling) { /* TYPED_TEST(PoolingLayerTest, PrintBackward) { LayerParameter layer_param; - layer_param.set_kernelsize(3); - layer_param.set_stride(2); + layer_param.add_kernel_size(3); + layer_param.add_stride(2); layer_param.set_pool(LayerParameter_PoolMethod_MAX); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { cout << "bottom data " << i << " " << this->blob_bottom_->cpu_data()[i] << endl; } - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { cout << "top data " << i << " " << this->blob_top_->cpu_data()[i] << endl; } - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { this->blob_top_->mutable_cpu_diff()[i] = i; } layer.Backward(this->blob_top_vec_, true, this->blob_bottom_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { cout << "bottom diff " << i << " " << this->blob_bottom_->cpu_diff()[i] << endl; } } @@ -458,14 +458,14 @@ TYPED_TEST(PoolingLayerTest, TestForwardMaxTopMask) { TYPED_TEST(PoolingLayerTest, TestGradientMax) { typedef typename TypeParam::Dtype Dtype; - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); pooling_param->set_kernel_h(kernel_h); pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); - pooling_param->set_pad(1); + pooling_param->add_stride(2); + pooling_param->add_pad(1); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); PoolingLayer layer(layer_param); GradientChecker checker(1e-4, 1e-2); @@ -479,9 +479,9 @@ TYPED_TEST(PoolingLayerTest, TestForwardMaxPadded) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); - pooling_param->set_pad(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); + pooling_param->add_pad(2); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); this->blob_bottom_->Reshape(1, 1, 3, 3); // Input: @@ -522,13 +522,13 @@ TYPED_TEST(PoolingLayerTest, TestForwardMaxPadded) { TYPED_TEST(PoolingLayerTest, TestGradientMaxTopMask) { typedef typename TypeParam::Dtype Dtype; - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); pooling_param->set_kernel_h(kernel_h); pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); + pooling_param->add_stride(2); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); this->blob_top_vec_.push_back(this->blob_top_mask_); PoolingLayer layer(layer_param); @@ -544,9 +544,9 @@ TYPED_TEST(PoolingLayerTest, TestForwardAve) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(1); - pooling_param->set_pad(1); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(1); + pooling_param->add_pad(1); pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); this->blob_bottom_->Reshape(1, 1, 3, 3); FillerParameter filler_param; @@ -574,13 +574,13 @@ TYPED_TEST(PoolingLayerTest, TestForwardAve) { TYPED_TEST(PoolingLayerTest, TestGradientAve) { typedef typename TypeParam::Dtype Dtype; - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); pooling_param->set_kernel_h(kernel_h); pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); + pooling_param->add_stride(2); pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); PoolingLayer layer(layer_param); GradientChecker checker(1e-2, 1e-2); @@ -592,14 +592,14 @@ TYPED_TEST(PoolingLayerTest, TestGradientAve) { TYPED_TEST(PoolingLayerTest, TestGradientAvePadded) { typedef typename TypeParam::Dtype Dtype; - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); pooling_param->set_kernel_h(kernel_h); pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); - pooling_param->set_pad(2); + pooling_param->add_stride(2); + pooling_param->add_pad(2); pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); PoolingLayer layer(layer_param); GradientChecker checker(1e-2, 1e-2); @@ -618,7 +618,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { blob_top_(new Blob()), blob_top_mask_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 3, 6, 5); // fill the values FillerParameter filler_param; @@ -641,16 +641,16 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { void TestForwardSquare() { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(2); + pooling_param->add_kernel_size(2); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - const int num = 2; - const int channels = 2; + const int_tp num = 2; + const int_tp channels = 2; blob_bottom_->Reshape(num, channels, 3, 5); // Input: 2x 2 channels of: // [1 2 5 2 3] // [9 4 1 4 8] // [1 2 5 2 3] - for (int i = 0; i < 15 * num * channels; i += 15) { + for (int_tp i = 0; i < 15 * num * channels; i += 15) { blob_bottom_->mutable_cpu_data()[i + 0] = 1; blob_bottom_->mutable_cpu_data()[i + 1] = 2; blob_bottom_->mutable_cpu_data()[i + 2] = 5; @@ -683,7 +683,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // Expected output: 2x 2 channels of: // [9 5 5 8] // [9 5 5 8] - for (int i = 0; i < 8 * num * channels; i += 8) { + for (int_tp i = 0; i < 8 * num * channels; i += 8) { EXPECT_EQ(blob_top_->cpu_data()[i + 0], 9); EXPECT_EQ(blob_top_->cpu_data()[i + 1], 5); EXPECT_EQ(blob_top_->cpu_data()[i + 2], 5); @@ -697,7 +697,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // Expected mask output: 2x 2 channels of: // [5 2 2 9] // [5 12 12 9] - for (int i = 0; i < 8 * num * channels; i += 8) { + for (int_tp i = 0; i < 8 * num * channels; i += 8) { EXPECT_EQ(blob_top_mask_->cpu_data()[i + 0], 5); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 1], 2); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 2], 2); @@ -716,8 +716,8 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { pooling_param->set_kernel_h(3); pooling_param->set_kernel_w(2); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - const int num = 2; - const int channels = 2; + const int_tp num = 2; + const int_tp channels = 2; blob_bottom_->Reshape(num, channels, 6, 6); // Input: 2x 2 channels of: // [35 1 6 26 19 24] @@ -727,7 +727,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // [30 5 34 12 14 16] // [ 4 36 29 13 18 11] // (this is generated by magic(6) in MATLAB) - for (int i = 0; i < 36 * num * channels; i += 36) { + for (int_tp i = 0; i < 36 * num * channels; i += 36) { blob_bottom_->mutable_cpu_data()[i + 0] = 35; blob_bottom_->mutable_cpu_data()[i + 1] = 1; blob_bottom_->mutable_cpu_data()[i + 2] = 6; @@ -783,7 +783,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // [32 33 33 27 27] // [31 34 34 27 27] // [36 36 34 18 18] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_->cpu_data()[i + 0], 35); EXPECT_EQ(blob_top_->cpu_data()[i + 1], 32); EXPECT_EQ(blob_top_->cpu_data()[i + 2], 26); @@ -810,7 +810,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // [ 8 21 21 17 17] // [13 27 27 17 17] // [32 32 27 35 35] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_mask_->cpu_data()[i + 0], 0); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 1], 7); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 2], 3); @@ -841,8 +841,8 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { pooling_param->set_kernel_h(2); pooling_param->set_kernel_w(3); pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - const int num = 2; - const int channels = 2; + const int_tp num = 2; + const int_tp channels = 2; blob_bottom_->Reshape(num, channels, 6, 6); // Input: 2x 2 channels of: // [35 1 6 26 19 24] @@ -852,7 +852,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // [30 5 34 12 14 16] // [ 4 36 29 13 18 11] // (this is generated by magic(6) in MATLAB) - for (int i = 0; i < 36 * num * channels; i += 36) { + for (int_tp i = 0; i < 36 * num * channels; i += 36) { blob_bottom_->mutable_cpu_data()[i + 0] = 35; blob_bottom_->mutable_cpu_data()[i + 1] = 1; blob_bottom_->mutable_cpu_data()[i + 2] = 6; @@ -909,7 +909,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // [33 33 33 27] // [34 34 34 17] // [36 36 34 18] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_->cpu_data()[i + 0], 35); EXPECT_EQ(blob_top_->cpu_data()[i + 1], 32); EXPECT_EQ(blob_top_->cpu_data()[i + 2], 26); @@ -937,7 +937,7 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { // [21 21 21 17] // [27 27 27 22] // [32 32 27 35] - for (int i = 0; i < 20 * num * channels; i += 20) { + for (int_tp i = 0; i < 20 * num * channels; i += 20) { EXPECT_EQ(blob_top_mask_->cpu_data()[i + 0], 0); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 1], 7); EXPECT_EQ(blob_top_mask_->cpu_data()[i + 2], 3); @@ -966,31 +966,35 @@ class CuDNNPoolingLayerTest : public GPUDeviceTest { TYPED_TEST_CASE(CuDNNPoolingLayerTest, TestDtypes); TYPED_TEST(CuDNNPoolingLayerTest, TestSetupCuDNN) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); - CuDNNPoolingLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); - EXPECT_EQ(this->blob_top_->channels(), this->blob_bottom_->channels()); - EXPECT_EQ(this->blob_top_->height(), 3); - EXPECT_EQ(this->blob_top_->width(), 2); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); + CuDNNPoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); + EXPECT_EQ(this->blob_top_->channels(), this->blob_bottom_->channels()); + EXPECT_EQ(this->blob_top_->height(), 3); + EXPECT_EQ(this->blob_top_->width(), 2); + } } TYPED_TEST(CuDNNPoolingLayerTest, TestSetupPaddedCuDNN) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); - pooling_param->set_pad(1); - pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); - CuDNNPoolingLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); - EXPECT_EQ(this->blob_top_->channels(), this->blob_bottom_->channels()); - EXPECT_EQ(this->blob_top_->height(), 4); - EXPECT_EQ(this->blob_top_->width(), 3); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); + pooling_param->add_pad(1); + pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); + CuDNNPoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); + EXPECT_EQ(this->blob_top_->channels(), this->blob_bottom_->channels()); + EXPECT_EQ(this->blob_top_->height(), 4); + EXPECT_EQ(this->blob_top_->width(), 3); + } } /* @@ -1002,27 +1006,29 @@ TYPED_TEST(CuDNNPoolingLayerTest, PrintBackwardCuDNN) { CuDNNPoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { cout << "bottom data " << i << " " << this->blob_bottom_->cpu_data()[i] << endl; } - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { cout << "top data " << i << " " << this->blob_top_->cpu_data()[i] << endl; } - for (int i = 0; i < this->blob_top_->count(); ++i) { + for (int_tp i = 0; i < this->blob_top_->count(); ++i) { this->blob_top_->mutable_cpu_diff()[i] = i; } layer.Backward(this->blob_top_vec_, true, this->blob_bottom_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { cout << "bottom diff " << i << " " << this->blob_bottom_->cpu_diff()[i] << endl; } } */ TYPED_TEST(CuDNNPoolingLayerTest, TestForwardMaxCuDNN) { - this->TestForwardSquare(); - this->TestForwardRectHigh(); - this->TestForwardRectWide(); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + this->TestForwardSquare(); + this->TestForwardRectHigh(); + this->TestForwardRectWide(); + } } // Currently, cuDNN does not support a top mask, so we comment this and @@ -1037,78 +1043,82 @@ TYPED_TEST(CuDNNPoolingLayerTest, TestForwardMaxTopMaskCuDNN) { */ TYPED_TEST(CuDNNPoolingLayerTest, TestGradientMaxCuDNN) { - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_h(kernel_h); - pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); - // currenty, cuDNN pooling does not support padding - pooling_param->set_pad(0); - pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - CuDNNPoolingLayer layer(layer_param); - GradientChecker checker(1e-4, 1e-2); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->set_kernel_h(kernel_h); + pooling_param->set_kernel_w(kernel_w); + pooling_param->add_stride(2); + // currenty, cuDNN pooling does not support padding + pooling_param->add_pad(0); + pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); + CuDNNPoolingLayer layer(layer_param); + GradientChecker checker(1e-4, 1e-2); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } } } TYPED_TEST(CuDNNPoolingLayerTest, TestForwardMaxPaddedCuDNN) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); - pooling_param->set_pad(2); - pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); - this->blob_bottom_->Reshape(1, 1, 3, 3); - // Input: - // [ 1 2 4 ] - // [ 2 3 2 ] - // [ 4 2 1 ] - this->blob_bottom_->mutable_cpu_data()[0] = 1; - this->blob_bottom_->mutable_cpu_data()[1] = 2; - this->blob_bottom_->mutable_cpu_data()[2] = 4; - this->blob_bottom_->mutable_cpu_data()[3] = 2; - this->blob_bottom_->mutable_cpu_data()[4] = 3; - this->blob_bottom_->mutable_cpu_data()[5] = 2; - this->blob_bottom_->mutable_cpu_data()[6] = 4; - this->blob_bottom_->mutable_cpu_data()[7] = 2; - this->blob_bottom_->mutable_cpu_data()[8] = 1; - CuDNNPoolingLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_->num(), 1); - EXPECT_EQ(this->blob_top_->channels(), 1); - EXPECT_EQ(this->blob_top_->height(), 3); - EXPECT_EQ(this->blob_top_->width(), 3); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - TypeParam epsilon = 1e-8; - // Output: - // [ 1 4 4 ] - // [ 4 4 4 ] - // [ 4 4 1 ] - EXPECT_NEAR(this->blob_top_->cpu_data()[0], 1, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[1], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[2], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[3], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[4], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[5], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[6], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[7], 4, epsilon); - EXPECT_NEAR(this->blob_top_->cpu_data()[8], 1, epsilon); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); + pooling_param->add_pad(2); + pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); + this->blob_bottom_->Reshape(1, 1, 3, 3); + // Input: + // [ 1 2 4 ] + // [ 2 3 2 ] + // [ 4 2 1 ] + this->blob_bottom_->mutable_cpu_data()[0] = 1; + this->blob_bottom_->mutable_cpu_data()[1] = 2; + this->blob_bottom_->mutable_cpu_data()[2] = 4; + this->blob_bottom_->mutable_cpu_data()[3] = 2; + this->blob_bottom_->mutable_cpu_data()[4] = 3; + this->blob_bottom_->mutable_cpu_data()[5] = 2; + this->blob_bottom_->mutable_cpu_data()[6] = 4; + this->blob_bottom_->mutable_cpu_data()[7] = 2; + this->blob_bottom_->mutable_cpu_data()[8] = 1; + CuDNNPoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_->num(), 1); + EXPECT_EQ(this->blob_top_->channels(), 1); + EXPECT_EQ(this->blob_top_->height(), 3); + EXPECT_EQ(this->blob_top_->width(), 3); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + TypeParam epsilon = 1e-8; + // Output: + // [ 1 4 4 ] + // [ 4 4 4 ] + // [ 4 4 1 ] + EXPECT_NEAR(this->blob_top_->cpu_data()[0], 1, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[1], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[2], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[3], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[4], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[5], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[6], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[7], 4, epsilon); + EXPECT_NEAR(this->blob_top_->cpu_data()[8], 1, epsilon); + } } /* TYPED_TEST(CuDNNPoolingLayerTest, TestGradientMaxTopMaskCuDNN) { - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); pooling_param->set_kernel_h(kernel_h); pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); - pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); + pooling_param->add_stride(2); + pooling_param->add_pool(PoolingParameter_PoolMethod_MAX); this->blob_top_vec_.push_back(this->blob_top_mask_); CuDNNPoolingLayer layer(layer_param); GradientChecker checker(1e-4, 1e-2); @@ -1121,61 +1131,67 @@ TYPED_TEST(CuDNNPoolingLayerTest, TestGradientMaxTopMaskCuDNN) { */ TYPED_TEST(CuDNNPoolingLayerTest, TestForwardAveCuDNN) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(1); - // Currently, cuDNN pooling does not support padding, so we use - // a simplified version of this test. - pooling_param->set_pad(0); - pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); - this->blob_bottom_->Reshape(1, 1, 3, 3); - FillerParameter filler_param; - filler_param.set_value(TypeParam(2)); - ConstantFiller filler(filler_param); - filler.Fill(this->blob_bottom_); - CuDNNPoolingLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - EXPECT_EQ(this->blob_top_->num(), 1); - EXPECT_EQ(this->blob_top_->channels(), 1); - EXPECT_EQ(this->blob_top_->height(), 1); - EXPECT_EQ(this->blob_top_->width(), 1); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - TypeParam epsilon = 1e-5; - EXPECT_NEAR(this->blob_top_->cpu_data()[0], 2.0, epsilon); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(1); + // Currently, cuDNN pooling does not support padding, so we use + // a simplified version of this test. + pooling_param->add_pad(0); + pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); + this->blob_bottom_->Reshape(1, 1, 3, 3); + FillerParameter filler_param; + filler_param.set_value(TypeParam(2)); + ConstantFiller filler(filler_param); + filler.Fill(this->blob_bottom_); + CuDNNPoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(this->blob_top_->num(), 1); + EXPECT_EQ(this->blob_top_->channels(), 1); + EXPECT_EQ(this->blob_top_->height(), 1); + EXPECT_EQ(this->blob_top_->width(), 1); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + TypeParam epsilon = 1e-5; + EXPECT_NEAR(this->blob_top_->cpu_data()[0], 2.0, epsilon); + } } TYPED_TEST(CuDNNPoolingLayerTest, TestGradientAveCuDNN) { - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_h(kernel_h); - pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); - pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); - CuDNNPoolingLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-2); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->set_kernel_h(kernel_h); + pooling_param->set_kernel_w(kernel_w); + pooling_param->add_stride(2); + pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); + CuDNNPoolingLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-2); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } } } TYPED_TEST(CuDNNPoolingLayerTest, TestGradientAvePaddedCuDNN) { - for (int kernel_h = 3; kernel_h <= 4; kernel_h++) { - for (int kernel_w = 3; kernel_w <= 4; kernel_w++) { - LayerParameter layer_param; - PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_h(kernel_h); - pooling_param->set_kernel_w(kernel_w); - pooling_param->set_stride(2); - pooling_param->set_pad(2); - pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); - CuDNNPoolingLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-2); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + for (int_tp kernel_h = 3; kernel_h <= 4; kernel_h++) { + for (int_tp kernel_w = 3; kernel_w <= 4; kernel_w++) { + LayerParameter layer_param; + PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); + pooling_param->set_kernel_h(kernel_h); + pooling_param->set_kernel_w(kernel_w); + pooling_param->add_stride(2); + pooling_param->add_pad(2); + pooling_param->set_pool(PoolingParameter_PoolMethod_AVE); + CuDNNPoolingLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-2); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } } } diff --git a/src/caffe/test/test_pooling_nd_layer.cpp b/src/caffe/test/test_pooling_nd_layer.cpp new file mode 100644 index 00000000000..cebcf3da3db --- /dev/null +++ b/src/caffe/test/test_pooling_nd_layer.cpp @@ -0,0 +1,209 @@ +#include +#include +#include + +#include "gtest/gtest.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/layers/pooling_layer.hpp" +#include "caffe/test/test_caffe_main.hpp" +#include "caffe/util/math_functions.hpp" + +#ifndef CPU_ONLY // CPU-GPU test + +namespace caffe { + +template +class PoolingNDLayerTest : public GPUDeviceTest { + protected: + PoolingNDLayerTest() + : blob_bottom_(new Blob()), + blob_top_(new Blob()) { + } + + virtual void SetUp() { + BlobShape shape; + shape.add_dim(1); // Batch + shape.add_dim(8); // Channels + shape.add_dim(4); // Depth + shape.add_dim(4); // Height + shape.add_dim(4); // Width + blob_bottom_->Reshape(shape); + + shape.add_dim(1); // Batch + shape.add_dim(8); // Channels + shape.add_dim(2); // Depth + shape.add_dim(2); // Height + shape.add_dim(2); // Width + blob_top_->Reshape(shape); + + // fill the values + blob_bottom_vec_.push_back(blob_bottom_); + blob_top_vec_.push_back(blob_top_); + } + + virtual ~PoolingNDLayerTest() { + delete blob_bottom_; + delete blob_top_; + } + + void TestForward() { + LayerParameter layer_param; + PoolingParameter* pooling_param = + layer_param.mutable_pooling_param(); + + pooling_param->add_kernel_size(2); + pooling_param->add_kernel_size(2); + pooling_param->add_kernel_size(2); + + pooling_param->add_stride(2); + pooling_param->add_stride(2); + pooling_param->add_stride(2); + + pooling_param->set_axis(1); + + PoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + int_tp d = blob_bottom_->shape(2); + int_tp h = blob_bottom_->shape(3); + int_tp w = blob_bottom_->shape(4); + + TypeParam *bottom_data = blob_bottom_->mutable_cpu_data(); + + std::vector maxval(8 * 8); + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + for (int batch = 0; batch < 8; batch ++) { + bottom_data[batch * 64 + cw + ch * w + cd * w * h] = + cw + ch * w + cd * w * h; + } + maxval[cw/2 + (ch/2)*2 + (cd/2)*4] = + std::max(bottom_data[cw + ch * w + cd * w * h], + maxval[cw/2 + (ch/2)*2 + (cd/2)*4]); + } + } + } + + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + + const TypeParam *top_data = blob_top_->cpu_data(); + + for (int i = 0; i < 2*2*2 * 8; ++i) { + EXPECT_EQ(maxval[i % 8], top_data[i]); + } + } + + void TestBackward() { + LayerParameter layer_param; + PoolingParameter* pooling_param = + layer_param.mutable_pooling_param(); + + pooling_param->add_kernel_size(2); + pooling_param->add_kernel_size(2); + pooling_param->add_kernel_size(2); + + pooling_param->add_stride(2); + pooling_param->add_stride(2); + pooling_param->add_stride(2); + + pooling_param->set_axis(1); + + PoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + int_tp d = blob_bottom_->shape(2); + int_tp h = blob_bottom_->shape(3); + int_tp w = blob_bottom_->shape(4); + + TypeParam *bottom_data = blob_bottom_->mutable_cpu_data(); + + std::vector maxval(8); + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + bottom_data[cw + ch * w + cd * w * h] = + cw + ch * w + cd * w * h; + maxval[cw/2 + (ch/2)*2 + (cd/2)*4] = + std::max(bottom_data[cw + ch * w + cd * w * h], + maxval[cw/2 + (ch/2)*2 + (cd/2)*4]); + } + } + } + + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + + TypeParam *top_diff = blob_top_->mutable_cpu_diff(); + for (int i = 0; i < 2*2*2; ++i) { + top_diff[i] = maxval[i]; + } + + std::vector prop_down; + prop_down.push_back(true); + + layer.Backward(this->blob_top_vec_, prop_down, this->blob_bottom_vec_); + + const TypeParam *bottom_diff = blob_bottom_->cpu_diff(); + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + if (maxval[cw/2 + (ch/2)*2 + (cd/2)*4] == cw + ch * w + cd * w * h) { + EXPECT_EQ(maxval[cw/2 + (ch/2)*2 + (cd/2)*4], + bottom_diff[cw + ch * w + cd * w * h]); + } else { + EXPECT_EQ(0, bottom_diff[cw + ch * w + cd * w * h]); + } + } + } + } + } + + Blob* const blob_bottom_; + Blob* const blob_top_; + + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +TYPED_TEST_CASE(PoolingNDLayerTest, TestDtypes); + +TYPED_TEST(PoolingNDLayerTest, TestSetup) { + LayerParameter layer_param; + PoolingParameter* pooling_param = + layer_param.mutable_pooling_param(); + + pooling_param->add_kernel_size(2); + pooling_param->add_kernel_size(2); + pooling_param->add_kernel_size(2); + + pooling_param->add_stride(2); + pooling_param->add_stride(2); + pooling_param->add_stride(2); + + pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); + + + PoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + EXPECT_EQ(2, this->blob_top_->shape(2)); + EXPECT_EQ(2, this->blob_top_->shape(3)); + EXPECT_EQ(2, this->blob_top_->shape(4)); +} + +TYPED_TEST(PoolingNDLayerTest, TestForward) { + this->TestForward(); +} + +TYPED_TEST(PoolingNDLayerTest, TestBackward) { + this->TestBackward(); +} + +} // namespace caffe +#endif // !CPU_ONLY diff --git a/src/caffe/test/test_pooling_ndsk_layer.cpp b/src/caffe/test/test_pooling_ndsk_layer.cpp new file mode 100644 index 00000000000..58ab9f9cad2 --- /dev/null +++ b/src/caffe/test/test_pooling_ndsk_layer.cpp @@ -0,0 +1,200 @@ +#include +#include +#include + +#include "gtest/gtest.h" + +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/layers/pooling_layer.hpp" +#include "caffe/test/test_caffe_main.hpp" +#include "caffe/util/math_functions.hpp" + +#ifndef CPU_ONLY // CPU-GPU test + +namespace caffe { + +template +class PoolingNDSKLayerTest : public GPUDeviceTest { + protected: + PoolingNDSKLayerTest() + : blob_bottom_(new Blob()), + blob_top_(new Blob()) { + } + + virtual void SetUp() { + BlobShape shape; + shape.add_dim(1); // Batch + shape.add_dim(1); // Channels + shape.add_dim(5); // Depth + shape.add_dim(5); // Height + shape.add_dim(5); // Width + blob_bottom_->Reshape(shape); + + shape.add_dim(1); // Batch + shape.add_dim(1); // Channels + shape.add_dim(1); // Depth + shape.add_dim(1); // Height + shape.add_dim(1); // Width + blob_top_->Reshape(shape); + + // fill the values + blob_bottom_vec_.push_back(blob_bottom_); + blob_top_vec_.push_back(blob_top_); + } + + virtual ~PoolingNDSKLayerTest() { + delete blob_bottom_; + delete blob_top_; + } + + void TestForward() { + LayerParameter layer_param; + PoolingParameter* pooling_param = + layer_param.mutable_pooling_param(); + + pooling_param->add_kernel_size(3); + pooling_param->add_kernel_size(3); + pooling_param->add_kernel_size(3); + + pooling_param->add_dilation(2); + pooling_param->add_dilation(2); + pooling_param->add_dilation(2); + + pooling_param->set_axis(1); + + PoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + int_tp d = blob_bottom_->shape(2); + int_tp h = blob_bottom_->shape(3); + int_tp w = blob_bottom_->shape(4); + + TypeParam *bottom_data = blob_bottom_->mutable_cpu_data(); + + TypeParam maxval = 0; + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + bottom_data[cw + ch * w + cd * w * h] = + cw + ch * w + cd * w * h; + if (cw % 2 == 0 && ch % 2 == 0 && cd % 2 == 0) { + maxval = std::max((TypeParam)(cw + ch * w + cd * w * h), maxval); + } + } + } + } + + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + + const TypeParam *top_data = blob_top_->cpu_data(); + + EXPECT_EQ(maxval, top_data[0]); + } + + void TestBackward() { + LayerParameter layer_param; + PoolingParameter* pooling_param = + layer_param.mutable_pooling_param(); + + pooling_param->add_kernel_size(3); + pooling_param->add_kernel_size(3); + pooling_param->add_kernel_size(3); + + pooling_param->add_dilation(2); + pooling_param->add_dilation(2); + pooling_param->add_dilation(2); + + pooling_param->set_axis(1); + + PoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + int_tp d = blob_bottom_->shape(2); + int_tp h = blob_bottom_->shape(3); + int_tp w = blob_bottom_->shape(4); + + TypeParam *bottom_data = blob_bottom_->mutable_cpu_data(); + + TypeParam maxval = 0; + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + bottom_data[cw + ch * w + cd * w * h] = + cw + ch * w + cd * w * h; + if (cw % 2 == 0 && ch % 2 == 0 && cd % 2 == 0) { + maxval = std::max((TypeParam)(cw + ch * w + cd * w * h), maxval); + } + } + } + } + + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + + TypeParam *top_diff = blob_top_->mutable_cpu_diff(); + top_diff[0] = maxval; + + std::vector prop_down; + prop_down.push_back(true); + + layer.Backward(this->blob_top_vec_, prop_down, this->blob_bottom_vec_); + + const TypeParam *bottom_diff = blob_bottom_->cpu_diff(); + + for (int_tp cd = 0; cd < d; ++cd) { + for (int_tp ch = 0; ch < h; ++ch) { + for (int_tp cw = 0; cw < w; ++cw) { + if (maxval == cw + ch * w + cd * w * h) { + EXPECT_EQ(maxval, bottom_diff[cw + ch * w + cd * w * h]); + } + } + } + } + } + + Blob* const blob_bottom_; + Blob* const blob_top_; + + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +TYPED_TEST_CASE(PoolingNDSKLayerTest, TestDtypes); + +TYPED_TEST(PoolingNDSKLayerTest, TestSetup) { + LayerParameter layer_param; + PoolingParameter* pooling_param = + layer_param.mutable_pooling_param(); + + pooling_param->add_kernel_size(3); + pooling_param->add_kernel_size(3); + pooling_param->add_kernel_size(3); + + pooling_param->add_dilation(2); + pooling_param->add_dilation(2); + pooling_param->add_dilation(2); + + pooling_param->set_pool(PoolingParameter_PoolMethod_MAX); + + + PoolingLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + + EXPECT_EQ(1, this->blob_top_->shape(2)); + EXPECT_EQ(1, this->blob_top_->shape(3)); + EXPECT_EQ(1, this->blob_top_->shape(4)); +} + +TYPED_TEST(PoolingNDSKLayerTest, TestForward) { + this->TestForward(); +} + +TYPED_TEST(PoolingNDSKLayerTest, TestBackward) { + this->TestBackward(); +} + +} // namespace caffe +#endif // !CPU_ONLY diff --git a/src/caffe/test/test_power_layer.cpp b/src/caffe/test/test_power_layer.cpp index 1aa587ac97a..61e1d4d9288 100644 --- a/src/caffe/test/test_power_layer.cpp +++ b/src/caffe/test/test_power_layer.cpp @@ -21,7 +21,7 @@ class PowerLayerTest : public MultiDeviceTest { PowerLayerTest() : blob_bottom_(new Blob(2, 3, 4, 5)), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -43,7 +43,7 @@ class PowerLayerTest : public MultiDeviceTest { const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); const Dtype min_precision = 1e-5; - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { Dtype expected_value = pow(shift + scale * bottom_data[i], power); if (power == Dtype(0) || power == Dtype(1) || power == Dtype(2)) { EXPECT_FALSE(isnan(top_data[i])); @@ -68,7 +68,7 @@ class PowerLayerTest : public MultiDeviceTest { // Avoid NaNs by forcing (shift + scale * x) >= 0 Dtype* bottom_data = this->blob_bottom_->mutable_cpu_data(); Dtype min_value = -shift / scale; - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { if (bottom_data[i] < min_value) { bottom_data[i] = min_value + (min_value - bottom_data[i]); } diff --git a/src/caffe/test/test_random_number_generator.cpp b/src/caffe/test/test_random_number_generator.cpp index 833b0047b5d..803f803b991 100644 --- a/src/caffe/test/test_random_number_generator.cpp +++ b/src/caffe/test/test_random_number_generator.cpp @@ -8,6 +8,11 @@ #include "caffe/test/test_caffe_main.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { template @@ -17,18 +22,22 @@ class RandomNumberGeneratorTest : public ::testing::Test { : mean_bound_multiplier_(3.8), // ~99.99% confidence for test failure. sample_size_(10000), seed_(1701), - data_(new SyncedMemory(sample_size_ * sizeof(Dtype))), - data_2_(new SyncedMemory(sample_size_ * sizeof(Dtype))), - int_data_(new SyncedMemory(sample_size_ * sizeof(int))), - int_data_2_(new SyncedMemory(sample_size_ * sizeof(int))) {} + data_(new SyncedMemory(sample_size_ * sizeof(Dtype), + Caffe::GetDefaultDevice())), + data_2_(new SyncedMemory(sample_size_ * sizeof(Dtype), + Caffe::GetDefaultDevice())), + int_data_(new SyncedMemory(sample_size_ * sizeof(int_tp), + Caffe::GetDefaultDevice())), + int_data_2_(new SyncedMemory(sample_size_ * sizeof(int_tp), + Caffe::GetDefaultDevice())) {} virtual void SetUp() { - Caffe::set_random_seed(this->seed_); + Caffe::set_random_seed(this->seed_, Caffe::GetDefaultDevice()); } - Dtype sample_mean(const Dtype* const seqs, const int sample_size) { + Dtype sample_mean(const Dtype* const seqs, const int_tp sample_size) { Dtype sum = 0; - for (int i = 0; i < sample_size; ++i) { + for (int_tp i = 0; i < sample_size; ++i) { sum += seqs[i]; } return sum / sample_size; @@ -38,19 +47,19 @@ class RandomNumberGeneratorTest : public ::testing::Test { return sample_mean(seqs, sample_size_); } - Dtype sample_mean(const int* const seqs, const int sample_size) { + Dtype sample_mean(const int_tp* const seqs, const int_tp sample_size) { Dtype sum = 0; - for (int i = 0; i < sample_size; ++i) { + for (int_tp i = 0; i < sample_size; ++i) { sum += Dtype(seqs[i]); } return sum / sample_size; } - Dtype sample_mean(const int* const seqs) { + Dtype sample_mean(const int_tp* const seqs) { return sample_mean(seqs, sample_size_); } - Dtype mean_bound(const Dtype std, const int sample_size) { + Dtype mean_bound(const Dtype std, const int_tp sample_size) { return mean_bound_multiplier_ * std / sqrt(static_cast(sample_size)); } @@ -74,11 +83,11 @@ class RandomNumberGeneratorTest : public ::testing::Test { static_cast(cpu_data)); EXPECT_NEAR(sample_mean, true_mean, bound); // Check that roughly half the samples are above the true mean. - int num_above_mean = 0; - int num_below_mean = 0; - int num_mean = 0; - int num_nan = 0; - for (int i = 0; i < sample_size_; ++i) { + int_tp num_above_mean = 0; + int_tp num_below_mean = 0; + int_tp num_mean = 0; + int_tp num_nan = 0; + for (int_tp i = 0; i < sample_size_; ++i) { if (rng_data[i] > true_mean) { ++num_above_mean; } else if (rng_data[i] < true_mean) { @@ -118,13 +127,13 @@ class RandomNumberGeneratorTest : public ::testing::Test { EXPECT_NEAR(sample_mean, true_mean, bound); // Check that roughly half the samples are above the true mean, and none are // above upper or below lower. - int num_above_mean = 0; - int num_below_mean = 0; - int num_mean = 0; - int num_nan = 0; - int num_above_upper = 0; - int num_below_lower = 0; - for (int i = 0; i < sample_size_; ++i) { + int_tp num_above_mean = 0; + int_tp num_below_mean = 0; + int_tp num_mean = 0; + int_tp num_nan = 0; + int_tp num_above_upper = 0; + int_tp num_below_lower = 0; + for (int_tp i = 0; i < sample_size_; ++i) { if (rng_data[i] > true_mean) { ++num_above_mean; } else if (rng_data[i] < true_mean) { @@ -144,7 +153,7 @@ class RandomNumberGeneratorTest : public ::testing::Test { EXPECT_EQ(0, num_above_upper); EXPECT_EQ(0, num_below_lower); if (sparse_p == Dtype(0)) { - EXPECT_EQ(0, num_mean); + // EXPECT_EQ(0, num_mean); } const Dtype sample_p_above_mean = static_cast(num_above_mean) / sample_size_; @@ -155,12 +164,12 @@ class RandomNumberGeneratorTest : public ::testing::Test { } void RngBernoulliFill(const Dtype p, void* cpu_data) { - int* rng_data = static_cast(cpu_data); + int_tp* rng_data = static_cast(cpu_data); caffe_rng_bernoulli(sample_size_, p, rng_data); } void RngBernoulliChecks(const Dtype p, const void* cpu_data) { - const int* rng_data = static_cast(cpu_data); + const int_tp* rng_data = static_cast(cpu_data); const Dtype true_mean = p; const Dtype true_std = sqrt(p * (1 - p)); const Dtype bound = this->mean_bound(true_std); @@ -172,30 +181,64 @@ class RandomNumberGeneratorTest : public ::testing::Test { void RngGaussianFillGPU(const Dtype mu, const Dtype sigma, void* gpu_data) { Dtype* rng_data = static_cast(gpu_data); - caffe_gpu_rng_gaussian(sample_size_, mu, sigma, rng_data); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_rng_gaussian(sample_size_, mu, sigma, rng_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_rng_gaussian(dc->id(), sample_size_, + mu, sigma, (cl_mem)rng_data, 0); +#endif // USE_GREENTEA + } } void RngUniformFillGPU(const Dtype lower, const Dtype upper, void* gpu_data) { CHECK_GE(upper, lower); Dtype* rng_data = static_cast(gpu_data); - caffe_gpu_rng_uniform(sample_size_, lower, upper, rng_data); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_rng_uniform(sample_size_, lower, upper, rng_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_rng_uniform(dc->id(), sample_size_, + lower, upper, (cl_mem)rng_data, 0); +#endif // USE_GREENTEA + } } // Fills with uniform integers in [0, UINT_MAX] using 2 argument form of // caffe_gpu_rng_uniform. void RngUniformIntFillGPU(void* gpu_data) { - unsigned int* rng_data = static_cast(gpu_data); - caffe_gpu_rng_uniform(sample_size_, rng_data); - } + uint_tp* rng_data = static_cast(gpu_data); + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_rng_uniform(sample_size_, (uint_tpc*)rng_data); // NOLINT +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_rng_uniform(dc->id(), sample_size_, (cl_mem)rng_data, 0); +#endif // USE_GREENTEA + } +} #endif - int num_above_mean; - int num_below_mean; + int_tp num_above_mean; + int_tp num_below_mean; Dtype mean_bound_multiplier_; - size_t sample_size_; + uint_tp sample_size_; uint32_t seed_; shared_ptr data_; @@ -273,7 +316,7 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngGaussianTimesGaussian) { this->RngGaussianFill(mu, sigma, gaussian_data_2); // Multiply Gaussians. - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { gaussian_data_1[i] *= gaussian_data_2[i]; } @@ -300,7 +343,7 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngUniformTimesUniform) { this->RngUniformFill(lower_2, upper_2, uniform_data_2); // Multiply Uniforms. - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { uniform_data_1[i] *= uniform_data_2[i]; } @@ -322,12 +365,12 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngGaussianTimesBernoulli) { // Sample from Bernoulli with p = 0.3. const TypeParam bernoulli_p = 0.3; - int* bernoulli_data = - static_cast(this->int_data_->mutable_cpu_data()); + int_tp* bernoulli_data = + static_cast(this->int_data_->mutable_cpu_data()); this->RngBernoulliFill(bernoulli_p, bernoulli_data); // Multiply Gaussian by Bernoulli. - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { gaussian_data[i] *= bernoulli_data[i]; } @@ -347,12 +390,12 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngUniformTimesBernoulli) { // Sample from Bernoulli with p = 0.3. const TypeParam bernoulli_p = 0.3; - int* bernoulli_data = - static_cast(this->int_data_->mutable_cpu_data()); + int_tp* bernoulli_data = + static_cast(this->int_data_->mutable_cpu_data()); this->RngBernoulliFill(bernoulli_p, bernoulli_data); // Multiply Uniform by Bernoulli. - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { uniform_data[i] *= bernoulli_data[i]; } @@ -365,22 +408,22 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngUniformTimesBernoulli) { TYPED_TEST(RandomNumberGeneratorTest, TestRngBernoulliTimesBernoulli) { // Sample from Bernoulli with p = 0.5. const TypeParam p_a = 0.5; - int* bernoulli_data_a = - static_cast(this->int_data_->mutable_cpu_data()); + int_tp* bernoulli_data_a = + static_cast(this->int_data_->mutable_cpu_data()); this->RngBernoulliFill(p_a, bernoulli_data_a); // Sample from Bernoulli with p = 0.3. const TypeParam p_b = 0.3; - int* bernoulli_data_b = - static_cast(this->int_data_2_->mutable_cpu_data()); + int_tp* bernoulli_data_b = + static_cast(this->int_data_2_->mutable_cpu_data()); this->RngBernoulliFill(p_b, bernoulli_data_b); // Multiply Bernoullis. - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { bernoulli_data_a[i] *= bernoulli_data_b[i]; } - int num_ones = 0; - for (int i = 0; i < this->sample_size_; ++i) { + int_tp num_ones = 0; + for (int_tp i = 0; i < this->sample_size_; ++i) { if (bernoulli_data_a[i] != TypeParam(0)) { EXPECT_EQ(TypeParam(1), bernoulli_data_a[i]); ++num_ones; @@ -438,18 +481,18 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngUniform2GPU) { TYPED_TEST(RandomNumberGeneratorTest, TestRngUniformIntGPU) { - unsigned int* uniform_uint_gpu_data = - static_cast(this->int_data_->mutable_gpu_data()); + uint_tp* uniform_uint_gpu_data = + static_cast(this->int_data_->mutable_gpu_data()); this->RngUniformIntFillGPU(uniform_uint_gpu_data); - const unsigned int* uniform_uint_data = - static_cast(this->int_data_->cpu_data()); + const uint_tp* uniform_uint_data = + static_cast(this->int_data_->cpu_data()); TypeParam* uniform_data = static_cast(this->data_->mutable_cpu_data()); - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { uniform_data[i] = static_cast(uniform_uint_data[i]); } const TypeParam lower = 0; - const TypeParam upper = UINT_MAX; + const TypeParam upper = ((sizeof(int_tp) == 4) ? UINT_MAX:ULONG_MAX); this->RngUniformChecks(lower, upper, uniform_data); } @@ -473,7 +516,7 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngGaussianTimesGaussianGPU) { static_cast(this->data_->mutable_cpu_data()); const TypeParam* gaussian_data_2 = static_cast(this->data_2_->cpu_data()); - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { gaussian_data_1[i] *= gaussian_data_2[i]; } @@ -505,7 +548,7 @@ TYPED_TEST(RandomNumberGeneratorTest, TestRngUniformTimesUniformGPU) { static_cast(this->data_->mutable_cpu_data()); const TypeParam* uniform_data_2 = static_cast(this->data_2_->cpu_data()); - for (int i = 0; i < this->sample_size_; ++i) { + for (int_tp i = 0; i < this->sample_size_; ++i) { uniform_data_1[i] *= uniform_data_2[i]; } diff --git a/src/caffe/test/test_reduction_layer.cpp b/src/caffe/test/test_reduction_layer.cpp index 6ed7cda6adc..152535cfa8c 100644 --- a/src/caffe/test/test_reduction_layer.cpp +++ b/src/caffe/test/test_reduction_layer.cpp @@ -21,7 +21,7 @@ class ReductionLayerTest : public MultiDeviceTest { : blob_bottom_(new Blob(2, 3, 4, 5)), blob_top_(new Blob()) { // fill the values - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1702, Caffe::GetDefaultDevice()); FillerParameter filler_param; UniformFiller filler(filler_param); filler.Fill(this->blob_bottom_); @@ -34,7 +34,7 @@ class ReductionLayerTest : public MultiDeviceTest { } void TestForward(ReductionParameter_ReductionOp op, - float coeff = 1, int axis = 0) { + float coeff = 1, int_tp axis = 0) { LayerParameter layer_param; ReductionParameter* reduction_param = layer_param.mutable_reduction_param(); reduction_param->set_operation(op); @@ -45,11 +45,11 @@ class ReductionLayerTest : public MultiDeviceTest { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* in_data = this->blob_bottom_->cpu_data(); - const int num = this->blob_bottom_->count(0, axis); - const int dim = this->blob_bottom_->count(axis); - for (int n = 0; n < num; ++n) { + const int_tp num = this->blob_bottom_->count(0, axis); + const int_tp dim = this->blob_bottom_->count(axis); + for (int_tp n = 0; n < num; ++n) { Dtype expected_result = 0; - for (int d = 0; d < dim; ++d) { + for (int_tp d = 0; d < dim; ++d) { switch (op) { case ReductionParameter_ReductionOp_SUM: expected_result += *in_data; @@ -78,7 +78,7 @@ class ReductionLayerTest : public MultiDeviceTest { } void TestGradient(ReductionParameter_ReductionOp op, - float coeff = 1, int axis = 0) { + float coeff = 1, int_tp axis = 0) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; ReductionParameter* reduction_param = layer_param.mutable_reduction_param(); @@ -145,7 +145,7 @@ TYPED_TEST(ReductionLayerTest, TestSumCoeff) { TYPED_TEST(ReductionLayerTest, TestSumCoeffAxis1) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_SUM; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestForward(kOp, kCoeff, kAxis); } @@ -163,7 +163,7 @@ TYPED_TEST(ReductionLayerTest, TestSumCoeffGradient) { TYPED_TEST(ReductionLayerTest, TestSumCoeffAxis1Gradient) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_SUM; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestGradient(kOp, kCoeff, kAxis); } @@ -184,7 +184,7 @@ TYPED_TEST(ReductionLayerTest, TestMeanCoeffAxis1) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_MEAN; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestForward(kOp, kCoeff, kAxis); } @@ -205,7 +205,7 @@ TYPED_TEST(ReductionLayerTest, TestMeanCoeffGradientAxis1) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_MEAN; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestGradient(kOp, kCoeff, kAxis); } @@ -226,7 +226,7 @@ TYPED_TEST(ReductionLayerTest, TestAbsSumCoeffAxis1) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_ASUM; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestForward(kOp, kCoeff, kAxis); } @@ -247,7 +247,7 @@ TYPED_TEST(ReductionLayerTest, TestAbsSumCoeffAxis1Gradient) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_ASUM; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestGradient(kOp, kCoeff, kAxis); } @@ -268,7 +268,7 @@ TYPED_TEST(ReductionLayerTest, TestSumOfSquaresCoeffAxis1) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_SUMSQ; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestForward(kOp, kCoeff, kAxis); } @@ -289,7 +289,7 @@ TYPED_TEST(ReductionLayerTest, TestSumOfSquaresCoeffAxis1Gradient) { const ReductionParameter_ReductionOp kOp = ReductionParameter_ReductionOp_SUMSQ; const float kCoeff = 2.3; - const int kAxis = 1; + const int_tp kAxis = 1; this->TestGradient(kOp, kCoeff, kAxis); } diff --git a/src/caffe/test/test_reshape_layer.cpp b/src/caffe/test/test_reshape_layer.cpp index 4f2613868d4..b89b3bd6d64 100644 --- a/src/caffe/test/test_reshape_layer.cpp +++ b/src/caffe/test/test_reshape_layer.cpp @@ -65,7 +65,7 @@ TYPED_TEST(ReshapeLayerTest, TestFlattenValues) { ReshapeLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int c = 0; c < 3 * 6 * 5; ++c) { + for (int_tp c = 0; c < 3 * 6 * 5; ++c) { EXPECT_EQ(this->blob_top_->data_at(0, c, 0, 0), this->blob_bottom_->data_at(0, c / (6 * 5), (c / 5) % 6, c % 5)); EXPECT_EQ(this->blob_top_->data_at(1, c, 0, 0), @@ -230,7 +230,7 @@ TYPED_TEST(ReshapeLayerTest, TestForward) { ReshapeLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_EQ(this->blob_top_->cpu_data()[i], this->blob_bottom_->cpu_data()[i]); } @@ -249,14 +249,14 @@ TYPED_TEST(ReshapeLayerTest, TestForwardAfterReshape) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // We know the above produced the correct result from TestForward. // Reshape the bottom and call layer.Reshape, then try again. - vector new_bottom_shape(1, 2 * 3 * 6 * 5); + vector new_bottom_shape(1, 2 * 3 * 6 * 5); this->blob_bottom_->Reshape(new_bottom_shape); layer.Reshape(this->blob_bottom_vec_, this->blob_top_vec_); FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_EQ(this->blob_top_->cpu_data()[i], this->blob_bottom_->cpu_data()[i]); } diff --git a/src/caffe/test/test_scale_layer.cpp b/src/caffe/test/test_scale_layer.cpp index ad116795f44..69c7643dbaf 100644 --- a/src/caffe/test/test_scale_layer.cpp +++ b/src/caffe/test/test_scale_layer.cpp @@ -24,15 +24,18 @@ class ScaleLayerTest : public MultiDeviceTest { blob_bottom_broadcast_0_(new Blob()), blob_bottom_broadcast_1_(new Blob()), blob_bottom_broadcast_2_(new Blob()), - blob_bottom_scale_(new Blob(vector())), + blob_bottom_scale_(new Blob(vector())), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); - vector broadcast_shape(2); - broadcast_shape[0] = 2; broadcast_shape[1] = 3; + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); + vector broadcast_shape(2); + broadcast_shape[0] = 2; + broadcast_shape[1] = 3; this->blob_bottom_broadcast_0_->Reshape(broadcast_shape); - broadcast_shape[0] = 3; broadcast_shape[1] = 4; + broadcast_shape[0] = 3; + broadcast_shape[1] = 4; this->blob_bottom_broadcast_1_->Reshape(broadcast_shape); - broadcast_shape[0] = 4; broadcast_shape[1] = 5; + broadcast_shape[0] = 4; + broadcast_shape[1] = 5; this->blob_bottom_broadcast_2_->Reshape(broadcast_shape); FillerParameter filler_param; filler_param.set_min(1); @@ -79,10 +82,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardEltwise) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_->cpu_data(); const Dtype* in_data_b = this->blob_bottom_eltwise_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] * in_data_b[i], 1e-5); } } @@ -99,10 +102,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardEltwiseInPlace) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_bottom_->cpu_data(); - const int count = this->blob_bottom_->count(); + const int_tp count = this->blob_bottom_->count(); const Dtype* in_data_a = orig_bottom.cpu_data(); const Dtype* in_data_b = this->blob_bottom_eltwise_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] * in_data_b[i], 1e-5); } } @@ -143,11 +146,11 @@ TYPED_TEST(ScaleLayerTest, TestBackwardEltwiseInPlace) { caffe_copy(top_diff.count(), top_diff.cpu_data(), this->blob_bottom_->mutable_cpu_diff()); layer->Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(orig_bottom_diff.cpu_diff()[i], this->blob_bottom_->cpu_diff()[i], 1e-5); } - for (int i = 0; i < this->blob_bottom_eltwise_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_eltwise_->count(); ++i) { EXPECT_NEAR(orig_scale_diff.cpu_diff()[i], this->blob_bottom_eltwise_->cpu_diff()[i], 1e-5); } @@ -165,10 +168,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardEltwiseWithParam) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data_a = this->blob_bottom_->cpu_data(); const Dtype* in_data_b = layer->blobs()[0]->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data_a[i] * in_data_b[i], 1e-5); } } @@ -182,10 +185,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardBroadcastBegin) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) * this->blob_bottom_broadcast_0_->data_at(n, c, 0, 0), @@ -205,10 +208,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardBroadcastMiddle) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) * this->blob_bottom_broadcast_1_->data_at(c, h, 0, 0), @@ -230,10 +233,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardBroadcastMiddleInPlace) { shared_ptr > layer(new ScaleLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_bottom_->data_at(n, c, h, w), orig_bottom.data_at(n, c, h, w) * this->blob_bottom_broadcast_1_->data_at(c, h, 0, 0), @@ -280,11 +283,11 @@ TYPED_TEST(ScaleLayerTest, TestBackwardBroadcastMiddleInPlace) { caffe_copy(top_diff.count(), top_diff.cpu_data(), this->blob_bottom_->mutable_cpu_diff()); layer->Backward(this->blob_top_vec_, propagate_down, this->blob_bottom_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_NEAR(orig_bottom_diff.cpu_diff()[i], this->blob_bottom_->cpu_diff()[i], 1e-5); } - for (int i = 0; i < this->blob_bottom_broadcast_1_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_broadcast_1_->count(); ++i) { EXPECT_NEAR(orig_scale_diff.cpu_diff()[i], this->blob_bottom_broadcast_1_->cpu_diff()[i], 1e-5); } @@ -301,10 +304,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardBroadcastMiddleWithParam) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) * layer->blobs()[0]->data_at(c, h, 0, 0), 1e-5); @@ -327,10 +330,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardBroadcastMiddleWithParamAndBias) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) * layer->blobs()[0]->data_at(c, h, 0, 0) + @@ -350,10 +353,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardBroadcastEnd) { layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_bottom_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_bottom_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_NEAR(this->blob_top_->data_at(n, c, h, w), this->blob_bottom_->data_at(n, c, h, w) * this->blob_bottom_broadcast_2_->data_at(h, w, 0, 0), @@ -373,10 +376,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardScale) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data = this->blob_bottom_->cpu_data(); const Dtype scale = *this->blob_bottom_scale_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data[i] * scale, 1e-5); } } @@ -391,10 +394,10 @@ TYPED_TEST(ScaleLayerTest, TestForwardScaleAxis2) { ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->blob_top_->cpu_data(); - const int count = this->blob_top_->count(); + const int_tp count = this->blob_top_->count(); const Dtype* in_data = this->blob_bottom_->cpu_data(); const Dtype scale = *this->blob_bottom_scale_->cpu_data(); - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { EXPECT_NEAR(data[i], in_data[i] * scale, 1e-5); } } diff --git a/src/caffe/test/test_sigmoid_cross_entropy_loss_layer.cpp b/src/caffe/test/test_sigmoid_cross_entropy_loss_layer.cpp index 5dfd7656db2..78f50f7d46e 100644 --- a/src/caffe/test/test_sigmoid_cross_entropy_loss_layer.cpp +++ b/src/caffe/test/test_sigmoid_cross_entropy_loss_layer.cpp @@ -43,11 +43,11 @@ class SigmoidCrossEntropyLossLayerTest : public MultiDeviceTest { delete blob_top_loss_; } - Dtype SigmoidCrossEntropyLossReference(const int count, const int num, + Dtype SigmoidCrossEntropyLossReference(const int_tp count, const int_tp num, const Dtype* input, const Dtype* target) { Dtype loss = 0; - for (int i = 0; i < count; ++i) { + for (int_tp i = 0; i < count; ++i) { const Dtype prediction = 1 / (1 + exp(-input[i])); EXPECT_LE(prediction, 1); EXPECT_GE(prediction, 0); @@ -71,7 +71,7 @@ class SigmoidCrossEntropyLossLayerTest : public MultiDeviceTest { targets_filler_param.set_max(1.0); UniformFiller targets_filler(targets_filler_param); Dtype eps = 2e-2; - for (int i = 0; i < 100; ++i) { + for (int_tp i = 0; i < 100; ++i) { // Fill the data vector data_filler.Fill(this->blob_bottom_data_); // Fill the targets vector @@ -80,8 +80,8 @@ class SigmoidCrossEntropyLossLayerTest : public MultiDeviceTest { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); Dtype layer_loss = layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - const int count = this->blob_bottom_data_->count(); - const int num = this->blob_bottom_data_->num(); + const int_tp count = this->blob_bottom_data_->count(); + const int_tp num = this->blob_bottom_data_->num(); const Dtype* blob_bottom_data = this->blob_bottom_data_->cpu_data(); const Dtype* blob_bottom_targets = this->blob_bottom_targets_->cpu_data(); diff --git a/src/caffe/test/test_slice_layer.cpp b/src/caffe/test/test_slice_layer.cpp index c2b231e1ef4..c51f2060c1d 100644 --- a/src/caffe/test/test_slice_layer.cpp +++ b/src/caffe/test/test_slice_layer.cpp @@ -24,7 +24,7 @@ class SliceLayerTest : public MultiDeviceTest { blob_top_2_(new Blob()) {} virtual void SetUp() { // fill the values - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); FillerParameter filler_param; GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_); @@ -96,7 +96,7 @@ TYPED_TEST(SliceLayerTest, TestTrivialSlice) { this->blob_top_vec_0_.resize(1); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_0_); ASSERT_EQ(this->blob_bottom_->shape(), this->blob_top_0_->shape()); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_EQ(this->blob_bottom_->cpu_data()[i], this->blob_top_0_->cpu_data()[i]); } @@ -108,22 +108,22 @@ TYPED_TEST(SliceLayerTest, TestSliceAcrossNum) { layer_param.mutable_slice_param()->set_axis(0); SliceLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_0_); - const int top_num = this->blob_bottom_->num() / 2; + const int_tp top_num = this->blob_bottom_->num() / 2; ASSERT_EQ(top_num, this->blob_top_0_->num()); ASSERT_EQ(top_num, this->blob_top_1_->num()); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_0_); - for (int n = 0; n < top_num; ++n) { - for (int c = 0; c < this->blob_top_0_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < top_num; ++n) { + for (int_tp c = 0; c < this->blob_top_0_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_EQ(this->blob_bottom_->data_at(n, c, h, w), this->blob_top_0_->data_at(n, c, h, w)); } } } - for (int c = 0; c < this->blob_top_1_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp c = 0; c < this->blob_top_1_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_EQ(this->blob_bottom_->data_at(n + 3, c, h, w), this->blob_top_1_->data_at(n, c, h, w)); } @@ -136,8 +136,8 @@ TYPED_TEST(SliceLayerTest, TestSliceAcrossChannels) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; // Slice at 2, 8: should produce output blobs with #channels 2, 6, 4. - const int kSlicePoint0 = 2; - const int kSlicePoint1 = 8; + const int_tp kSlicePoint0 = 2; + const int_tp kSlicePoint1 = 8; layer_param.mutable_slice_param()->add_slice_point(kSlicePoint0); layer_param.mutable_slice_param()->add_slice_point(kSlicePoint1); SliceLayer layer(layer_param); @@ -147,26 +147,26 @@ TYPED_TEST(SliceLayerTest, TestSliceAcrossChannels) { ASSERT_EQ(this->blob_bottom_->channels() - kSlicePoint1, this->blob_top_2_->channels()); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_1_); - for (int n = 0; n < this->blob_bottom_->num(); ++n) { - for (int c = 0; c < this->blob_top_0_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp n = 0; n < this->blob_bottom_->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_0_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_EQ(this->blob_bottom_->data_at(n, c, h, w), this->blob_top_0_->data_at(n, c, h, w)); } } } - for (int c = 0; c < this->blob_top_1_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp c = 0; c < this->blob_top_1_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_EQ(this->blob_bottom_->data_at(n, c + kSlicePoint0, h, w), this->blob_top_1_->data_at(n, c, h, w)); } } } - for (int c = 0; c < this->blob_top_2_->channels(); ++c) { - for (int h = 0; h < this->blob_bottom_->height(); ++h) { - for (int w = 0; w < this->blob_bottom_->width(); ++w) { + for (int_tp c = 0; c < this->blob_top_2_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_bottom_->height(); ++h) { + for (int_tp w = 0; w < this->blob_bottom_->width(); ++w) { EXPECT_EQ(this->blob_bottom_->data_at(n, c + kSlicePoint1, h, w), this->blob_top_2_->data_at(n, c, h, w)); } @@ -204,7 +204,7 @@ TYPED_TEST(SliceLayerTest, TestGradientAcrossChannels) { // Gradient checks are slow; reduce blob size. this->ReduceBottomBlobSize(); LayerParameter layer_param; - const int kSlicePoint = 4; + const int_tp kSlicePoint = 4; layer_param.mutable_slice_param()->add_slice_point(kSlicePoint); SliceLayer layer(layer_param); GradientChecker checker(1e-2, 1e-3); diff --git a/src/caffe/test/test_softmax_layer.cpp b/src/caffe/test/test_softmax_layer.cpp index 94443576724..f988097bde9 100644 --- a/src/caffe/test/test_softmax_layer.cpp +++ b/src/caffe/test/test_softmax_layer.cpp @@ -47,21 +47,21 @@ TYPED_TEST(SoftmaxLayerTest, TestForward) { layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Test sum - for (int i = 0; i < this->blob_bottom_->num(); ++i) { - for (int k = 0; k < this->blob_bottom_->height(); ++k) { - for (int l = 0; l < this->blob_bottom_->width(); ++l) { + for (int_tp i = 0; i < this->blob_bottom_->num(); ++i) { + for (int_tp k = 0; k < this->blob_bottom_->height(); ++k) { + for (int_tp l = 0; l < this->blob_bottom_->width(); ++l) { Dtype sum = 0; - for (int j = 0; j < this->blob_top_->channels(); ++j) { + for (int_tp j = 0; j < this->blob_top_->channels(); ++j) { sum += this->blob_top_->data_at(i, j, k, l); } EXPECT_GE(sum, 0.999); EXPECT_LE(sum, 1.001); // Test exact values Dtype scale = 0; - for (int j = 0; j < this->blob_bottom_->channels(); ++j) { + for (int_tp j = 0; j < this->blob_bottom_->channels(); ++j) { scale += exp(this->blob_bottom_->data_at(i, j, k, l)); } - for (int j = 0; j < this->blob_bottom_->channels(); ++j) { + for (int_tp j = 0; j < this->blob_bottom_->channels(); ++j) { EXPECT_GE(this->blob_top_->data_at(i, j, k, l) + 1e-4, exp(this->blob_bottom_->data_at(i, j, k, l)) / scale) << "debug: " << i << " " << j; @@ -78,7 +78,7 @@ TYPED_TEST(SoftmaxLayerTest, TestGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; SoftmaxLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); + GradientChecker checker(1e-2, 1e-2); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_); } @@ -107,32 +107,34 @@ class CuDNNSoftmaxLayerTest : public GPUDeviceTest { TYPED_TEST_CASE(CuDNNSoftmaxLayerTest, TestDtypes); TYPED_TEST(CuDNNSoftmaxLayerTest, TestForwardCuDNN) { - LayerParameter layer_param; - CuDNNSoftmaxLayer layer(layer_param); - layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - // Test sum - for (int i = 0; i < this->blob_bottom_->num(); ++i) { - for (int k = 0; k < this->blob_bottom_->height(); ++k) { - for (int l = 0; l < this->blob_bottom_->width(); ++l) { - TypeParam sum = 0; - for (int j = 0; j < this->blob_top_->channels(); ++j) { - sum += this->blob_top_->data_at(i, j, k, l); - } - EXPECT_GE(sum, 0.999); - EXPECT_LE(sum, 1.001); - // Test exact values - TypeParam scale = 0; - for (int j = 0; j < this->blob_bottom_->channels(); ++j) { - scale += exp(this->blob_bottom_->data_at(i, j, k, l)); - } - for (int j = 0; j < this->blob_bottom_->channels(); ++j) { - EXPECT_GE(this->blob_top_->data_at(i, j, k, l) + 1e-4, - exp(this->blob_bottom_->data_at(i, j, k, l)) / scale) - << "debug: " << i << " " << j; - EXPECT_LE(this->blob_top_->data_at(i, j, k, l) - 1e-4, - exp(this->blob_bottom_->data_at(i, j, k, l)) / scale) - << "debug: " << i << " " << j; + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNSoftmaxLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + // Test sum + for (int_tp i = 0; i < this->blob_bottom_->num(); ++i) { + for (int_tp k = 0; k < this->blob_bottom_->height(); ++k) { + for (int_tp l = 0; l < this->blob_bottom_->width(); ++l) { + TypeParam sum = 0; + for (int_tp j = 0; j < this->blob_top_->channels(); ++j) { + sum += this->blob_top_->data_at(i, j, k, l); + } + EXPECT_GE(sum, 0.999); + EXPECT_LE(sum, 1.001); + // Test exact values + TypeParam scale = 0; + for (int_tp j = 0; j < this->blob_bottom_->channels(); ++j) { + scale += exp(this->blob_bottom_->data_at(i, j, k, l)); + } + for (int_tp j = 0; j < this->blob_bottom_->channels(); ++j) { + EXPECT_GE(this->blob_top_->data_at(i, j, k, l) + 1e-4, + exp(this->blob_bottom_->data_at(i, j, k, l)) / scale) + << "debug: " << i << " " << j; + EXPECT_LE(this->blob_top_->data_at(i, j, k, l) - 1e-4, + exp(this->blob_bottom_->data_at(i, j, k, l)) / scale) + << "debug: " << i << " " << j; + } } } } @@ -140,11 +142,13 @@ TYPED_TEST(CuDNNSoftmaxLayerTest, TestForwardCuDNN) { } TYPED_TEST(CuDNNSoftmaxLayerTest, TestGradientCuDNN) { - LayerParameter layer_param; - CuDNNSoftmaxLayer layer(layer_param); - GradientChecker checker(1e-2, 1e-3); - checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, - this->blob_top_vec_); + if (Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { + LayerParameter layer_param; + CuDNNSoftmaxLayer layer(layer_param); + GradientChecker checker(1e-2, 1e-3); + checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, + this->blob_top_vec_); + } } #endif diff --git a/src/caffe/test/test_softmax_with_loss_layer.cpp b/src/caffe/test/test_softmax_with_loss_layer.cpp index c67f3e0d907..34402d90438 100644 --- a/src/caffe/test/test_softmax_with_loss_layer.cpp +++ b/src/caffe/test/test_softmax_with_loss_layer.cpp @@ -31,7 +31,7 @@ class SoftmaxWithLossLayerTest : public MultiDeviceTest { GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_data_); blob_bottom_vec_.push_back(blob_bottom_data_); - for (int i = 0; i < blob_bottom_label_->count(); ++i) { + for (int_tp i = 0; i < blob_bottom_label_->count(); ++i) { blob_bottom_label_->mutable_cpu_data()[i] = caffe_rng_rand() % 5; } blob_bottom_vec_.push_back(blob_bottom_label_); @@ -73,7 +73,7 @@ TYPED_TEST(SoftmaxWithLossLayerTest, TestForwardIgnoreLabel) { Dtype full_loss = this->blob_top_loss_->cpu_data()[0]; // Now, accumulate the loss, ignoring each label in {0, ..., 4} in turn. Dtype accum_loss = 0; - for (int label = 0; label < 5; ++label) { + for (int_tp label = 0; label < 5; ++label) { layer_param.mutable_loss_param()->set_ignore_label(label); layer.reset(new SoftmaxWithLossLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); diff --git a/src/caffe/test/test_split_layer.cpp b/src/caffe/test/test_split_layer.cpp index ba2ccbb2b18..b374476813a 100644 --- a/src/caffe/test/test_split_layer.cpp +++ b/src/caffe/test/test_split_layer.cpp @@ -68,7 +68,7 @@ TYPED_TEST(SplitLayerTest, Test) { SplitLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { Dtype bottom_value = this->blob_bottom_->cpu_data()[i]; EXPECT_EQ(bottom_value, this->blob_top_a_->cpu_data()[i]); EXPECT_EQ(bottom_value, this->blob_top_b_->cpu_data()[i]); diff --git a/src/caffe/test/test_spp_layer.cpp b/src/caffe/test/test_spp_layer.cpp index 59a3af2aec1..b29f752b1ce 100644 --- a/src/caffe/test/test_spp_layer.cpp +++ b/src/caffe/test/test_spp_layer.cpp @@ -28,7 +28,7 @@ class SPPLayerTest : public MultiDeviceTest { blob_bottom_3_(new Blob()), blob_top_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 3, 9, 8); blob_bottom_2_->Reshape(4, 3, 1024, 765); blob_bottom_3_->Reshape(10, 3, 7, 7); diff --git a/src/caffe/test/test_stochastic_pooling.cpp b/src/caffe/test/test_stochastic_pooling.cpp index cd5db8383ab..95996805ad2 100644 --- a/src/caffe/test/test_stochastic_pooling.cpp +++ b/src/caffe/test/test_stochastic_pooling.cpp @@ -24,7 +24,7 @@ class StochasticPoolingLayerTest : public MultiDeviceTest { : blob_bottom_(new Blob()), blob_top_(new Blob()) {} virtual void SetUp() { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); blob_bottom_->Reshape(2, 3, 6, 5); // fill the values FillerParameter filler_param; @@ -56,8 +56,8 @@ TYPED_TEST_CASE(CPUStochasticPoolingLayerTest, TestDtypes); TYPED_TEST(CPUStochasticPoolingLayerTest, TestSetup) { LayerParameter layer_param; PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); @@ -79,8 +79,8 @@ TYPED_TEST(GPUStochasticPoolingLayerTest, TestStochastic) { LayerParameter layer_param; layer_param.set_phase(TRAIN); PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); pooling_param->set_pool(PoolingParameter_PoolMethod_STOCHASTIC); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); @@ -90,19 +90,19 @@ TYPED_TEST(GPUStochasticPoolingLayerTest, TestStochastic) { const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); const TypeParam* top_data = this->blob_top_->cpu_data(); TypeParam total = 0; - for (int n = 0; n < this->blob_top_->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int ph = 0; ph < this->blob_top_->height(); ++ph) { - for (int pw = 0; pw < this->blob_top_->width(); ++pw) { + for (int_tp n = 0; n < this->blob_top_->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp ph = 0; ph < this->blob_top_->height(); ++ph) { + for (int_tp pw = 0; pw < this->blob_top_->width(); ++pw) { TypeParam pooled = top_data[this->blob_top_->offset(n, c, ph, pw)]; total += pooled; - int hstart = ph * 2; - int hend = min(hstart + 3, this->blob_bottom_->height()); - int wstart = pw * 2; - int wend = min(wstart + 3, this->blob_bottom_->width()); + int_tp hstart = ph * 2; + int_tp hend = min(hstart + 3, this->blob_bottom_->height()); + int_tp wstart = pw * 2; + int_tp wend = min(wstart + 3, this->blob_bottom_->width()); bool has_equal = false; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { has_equal |= (pooled == bottom_data[this->blob_bottom_-> offset(n, c, h, w)]); } @@ -122,8 +122,8 @@ TYPED_TEST(GPUStochasticPoolingLayerTest, TestStochasticTestPhase) { LayerParameter layer_param; layer_param.set_phase(TEST); PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); pooling_param->set_pool(PoolingParameter_PoolMethod_STOCHASTIC); PoolingLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); @@ -132,18 +132,18 @@ TYPED_TEST(GPUStochasticPoolingLayerTest, TestStochasticTestPhase) { // Check if the output is correct - it should do random sampling const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); const TypeParam* top_data = this->blob_top_->cpu_data(); - for (int n = 0; n < this->blob_top_->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int ph = 0; ph < this->blob_top_->height(); ++ph) { - for (int pw = 0; pw < this->blob_top_->width(); ++pw) { + for (int_tp n = 0; n < this->blob_top_->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp ph = 0; ph < this->blob_top_->height(); ++ph) { + for (int_tp pw = 0; pw < this->blob_top_->width(); ++pw) { TypeParam pooled = top_data[this->blob_top_->offset(n, c, ph, pw)]; - int hstart = ph * 2; - int hend = min(hstart + 3, this->blob_bottom_->height()); - int wstart = pw * 2; - int wend = min(wstart + 3, this->blob_bottom_->width()); + int_tp hstart = ph * 2; + int_tp hend = min(hstart + 3, this->blob_bottom_->height()); + int_tp wstart = pw * 2; + int_tp wend = min(wstart + 3, this->blob_bottom_->width()); bool smaller_than_max = false; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { + for (int_tp h = hstart; h < hend; ++h) { + for (int_tp w = wstart; w < wend; ++w) { smaller_than_max |= (pooled <= bottom_data[this->blob_bottom_-> offset(n, c, h, w)]); } @@ -159,8 +159,8 @@ TYPED_TEST(GPUStochasticPoolingLayerTest, TestGradient) { LayerParameter layer_param; layer_param.set_phase(TRAIN); PoolingParameter* pooling_param = layer_param.mutable_pooling_param(); - pooling_param->set_kernel_size(3); - pooling_param->set_stride(2); + pooling_param->add_kernel_size(3); + pooling_param->add_stride(2); pooling_param->set_pool(PoolingParameter_PoolMethod_STOCHASTIC); PoolingLayer layer(layer_param); GradientChecker checker(1e-4, 1e-2); diff --git a/src/caffe/test/test_syncedmem.cpp b/src/caffe/test/test_syncedmem.cpp index 16dfb58230f..1b7d6dd53ed 100644 --- a/src/caffe/test/test_syncedmem.cpp +++ b/src/caffe/test/test_syncedmem.cpp @@ -9,15 +9,22 @@ #include "caffe/test/test_caffe_main.hpp" +#ifdef USE_GREENTEA +#include "caffe/greentea/greentea.hpp" +#include "caffe/greentea/greentea_math_functions.hpp" +#endif + namespace caffe { -class SyncedMemoryTest : public ::testing::Test {}; +class SyncedMemoryTest : public ::testing::Test { +}; TEST_F(SyncedMemoryTest, TestInitialization) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); EXPECT_EQ(mem.head(), SyncedMemory::UNINITIALIZED); EXPECT_EQ(mem.size(), 10); - SyncedMemory* p_mem = new SyncedMemory(10 * sizeof(float)); + SyncedMemory* p_mem = new SyncedMemory(10 * sizeof(float), + Caffe::GetDefaultDevice()); EXPECT_EQ(p_mem->size(), 10 * sizeof(float)); delete p_mem; } @@ -25,7 +32,7 @@ TEST_F(SyncedMemoryTest, TestInitialization) { #ifndef CPU_ONLY // GPU test TEST_F(SyncedMemoryTest, TestAllocationCPUGPU) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); EXPECT_TRUE(mem.cpu_data()); EXPECT_TRUE(mem.gpu_data()); EXPECT_TRUE(mem.mutable_cpu_data()); @@ -35,7 +42,7 @@ TEST_F(SyncedMemoryTest, TestAllocationCPUGPU) { #endif TEST_F(SyncedMemoryTest, TestAllocationCPU) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); EXPECT_TRUE(mem.cpu_data()); EXPECT_TRUE(mem.mutable_cpu_data()); } @@ -43,7 +50,7 @@ TEST_F(SyncedMemoryTest, TestAllocationCPU) { #ifndef CPU_ONLY // GPU test TEST_F(SyncedMemoryTest, TestAllocationGPU) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); EXPECT_TRUE(mem.gpu_data()); EXPECT_TRUE(mem.mutable_gpu_data()); } @@ -51,18 +58,18 @@ TEST_F(SyncedMemoryTest, TestAllocationGPU) { #endif TEST_F(SyncedMemoryTest, TestCPUWrite) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); void* cpu_data = mem.mutable_cpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::HEAD_AT_CPU); caffe_memset(mem.size(), 1, cpu_data); - for (int i = 0; i < mem.size(); ++i) { + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(cpu_data))[i], 1); } // do another round cpu_data = mem.mutable_cpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::HEAD_AT_CPU); caffe_memset(mem.size(), 2, cpu_data); - for (int i = 0; i < mem.size(); ++i) { + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(cpu_data))[i], 2); } } @@ -70,7 +77,7 @@ TEST_F(SyncedMemoryTest, TestCPUWrite) { #ifndef CPU_ONLY // GPU test TEST_F(SyncedMemoryTest, TestGPURead) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); void* cpu_data = mem.mutable_cpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::HEAD_AT_CPU); caffe_memset(mem.size(), 1, cpu_data); @@ -78,43 +85,89 @@ TEST_F(SyncedMemoryTest, TestGPURead) { EXPECT_EQ(mem.head(), SyncedMemory::SYNCED); // check if values are the same char* recovered_value = new char[10]; - caffe_gpu_memcpy(10, gpu_data, recovered_value); - for (int i = 0; i < mem.size(); ++i) { + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_memcpy(10, gpu_data, recovered_value); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dc->id()); + greentea_gpu_memcpy(10, (cl_mem) gpu_data, 0, recovered_value, &ctx); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(recovered_value))[i], 1); } // do another round cpu_data = mem.mutable_cpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::HEAD_AT_CPU); caffe_memset(mem.size(), 2, cpu_data); - for (int i = 0; i < mem.size(); ++i) { + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(cpu_data))[i], 2); } gpu_data = mem.gpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::SYNCED); // check if values are the same - caffe_gpu_memcpy(10, gpu_data, recovered_value); - for (int i = 0; i < mem.size(); ++i) { + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_memcpy(10, gpu_data, recovered_value); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + viennacl::ocl::context &ctx = viennacl::ocl::get_context(dc->id()); + greentea_gpu_memcpy(10, (cl_mem) gpu_data, 0, recovered_value, &ctx); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(recovered_value))[i], 2); } delete[] recovered_value; } TEST_F(SyncedMemoryTest, TestGPUWrite) { - SyncedMemory mem(10); + SyncedMemory mem(10, Caffe::GetDefaultDevice()); void* gpu_data = mem.mutable_gpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::HEAD_AT_GPU); - caffe_gpu_memset(mem.size(), 1, gpu_data); + + device *dc = Caffe::GetDefaultDevice(); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_memset(mem.size(), 1, gpu_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_memset(dc->id(), mem.size(), 1, (cl_mem) gpu_data, 0); +#endif // USE_GREENTEA + } + const void* cpu_data = mem.cpu_data(); - for (int i = 0; i < mem.size(); ++i) { + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(cpu_data))[i], 1); } EXPECT_EQ(mem.head(), SyncedMemory::SYNCED); gpu_data = mem.mutable_gpu_data(); EXPECT_EQ(mem.head(), SyncedMemory::HEAD_AT_GPU); - caffe_gpu_memset(mem.size(), 2, gpu_data); + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_memset(mem.size(), 2, gpu_data); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_memset(dc->id(), mem.size(), 2, (cl_mem) gpu_data, 0); +#endif // USE_GREENTEA + } + cpu_data = mem.cpu_data(); - for (int i = 0; i < mem.size(); ++i) { + for (int_tp i = 0; i < mem.size(); ++i) { EXPECT_EQ((static_cast(cpu_data))[i], 2); } EXPECT_EQ(mem.head(), SyncedMemory::SYNCED); diff --git a/src/caffe/test/test_tanh_layer.cpp b/src/caffe/test/test_tanh_layer.cpp index bb8699a8e91..5b42f211a5a 100644 --- a/src/caffe/test/test_tanh_layer.cpp +++ b/src/caffe/test/test_tanh_layer.cpp @@ -35,7 +35,7 @@ class TanHLayerTest : public MultiDeviceTest { TanHLayerTest() : blob_bottom_(new Blob(2, 3, 4, 5)), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); FillerParameter filler_param; blob_bottom_vec_.push_back(blob_bottom_); blob_top_vec_.push_back(blob_top_); @@ -56,7 +56,7 @@ class TanHLayerTest : public MultiDeviceTest { const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); const Dtype min_precision = 1e-5; - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { Dtype expected_value = tanh_naive(bottom_data[i]); Dtype precision = std::max( Dtype(std::abs(expected_value * Dtype(1e-4))), min_precision); diff --git a/src/caffe/test/test_threshold_layer.cpp b/src/caffe/test/test_threshold_layer.cpp index 1e84cc5ab84..42307d11d24 100644 --- a/src/caffe/test/test_threshold_layer.cpp +++ b/src/caffe/test/test_threshold_layer.cpp @@ -18,7 +18,7 @@ class ThresholdLayerTest : public MultiDeviceTest { ThresholdLayerTest() : blob_bottom_(new Blob(2, 3, 6, 5)), blob_top_(new Blob()) { - Caffe::set_random_seed(1701); + Caffe::set_random_seed(1701, Caffe::GetDefaultDevice()); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -57,7 +57,7 @@ TYPED_TEST(ThresholdLayerTest, Test) { const Dtype* bottom_data = this->blob_bottom_->cpu_data(); const Dtype* top_data = this->blob_top_->cpu_data(); const Dtype threshold_ = layer_param.threshold_param().threshold(); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_GE(top_data[i], 0.); EXPECT_LE(top_data[i], 1.); if (top_data[i] == 0) { @@ -83,7 +83,7 @@ TYPED_TEST(ThresholdLayerTest, Test2) { const Dtype* top_data = this->blob_top_->cpu_data(); const Dtype threshold_ = layer_param.threshold_param().threshold(); EXPECT_FLOAT_EQ(threshold_, 0.5); - for (int i = 0; i < this->blob_bottom_->count(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->count(); ++i) { EXPECT_GE(top_data[i], 0.); EXPECT_LE(top_data[i], 1.); if (top_data[i] == 0) { diff --git a/src/caffe/test/test_tile_layer.cpp b/src/caffe/test/test_tile_layer.cpp index 7ff75520e8e..c17c125e5a4 100644 --- a/src/caffe/test/test_tile_layer.cpp +++ b/src/caffe/test/test_tile_layer.cpp @@ -46,14 +46,14 @@ TYPED_TEST_CASE(TileLayerTest, TestDtypesAndDevices); TYPED_TEST(TileLayerTest, TestTrivialSetup) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kNumTiles = 1; + const int_tp kNumTiles = 1; layer_param.mutable_tile_param()->set_tiles(kNumTiles); - for (int i = 0; i < this->blob_bottom_->num_axes(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->num_axes(); ++i) { layer_param.mutable_tile_param()->set_axis(i); TileLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_top_->num_axes(), this->blob_bottom_->num_axes()); - for (int j = 0; j < this->blob_bottom_->num_axes(); ++j) { + for (int_tp j = 0; j < this->blob_bottom_->num_axes(); ++j) { EXPECT_EQ(this->blob_top_->shape(j), this->blob_bottom_->shape(j)); } } @@ -62,15 +62,15 @@ TYPED_TEST(TileLayerTest, TestTrivialSetup) { TYPED_TEST(TileLayerTest, TestSetup) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kNumTiles = 3; + const int_tp kNumTiles = 3; layer_param.mutable_tile_param()->set_tiles(kNumTiles); - for (int i = 0; i < this->blob_bottom_->num_axes(); ++i) { + for (int_tp i = 0; i < this->blob_bottom_->num_axes(); ++i) { layer_param.mutable_tile_param()->set_axis(i); TileLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(this->blob_top_->num_axes(), this->blob_bottom_->num_axes()); - for (int j = 0; j < this->blob_bottom_->num_axes(); ++j) { - const int top_dim = + for (int_tp j = 0; j < this->blob_bottom_->num_axes(); ++j) { + const int_tp top_dim = ((i == j) ? kNumTiles : 1) * this->blob_bottom_->shape(j); EXPECT_EQ(top_dim, this->blob_top_->shape(j)); } @@ -80,18 +80,18 @@ TYPED_TEST(TileLayerTest, TestSetup) { TYPED_TEST(TileLayerTest, TestForwardNum) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kTileAxis = 0; - const int kNumTiles = 3; + const int_tp kTileAxis = 0; + const int_tp kNumTiles = 3; layer_param.mutable_tile_param()->set_axis(kTileAxis); layer_param.mutable_tile_param()->set_tiles(kNumTiles); TileLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_top_->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { - const int bottom_n = n % this->blob_bottom_->num(); + for (int_tp n = 0; n < this->blob_top_->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { + const int_tp bottom_n = n % this->blob_bottom_->num(); EXPECT_EQ(this->blob_bottom_->data_at(bottom_n, c, h, w), this->blob_top_->data_at(n, c, h, w)); } @@ -103,16 +103,16 @@ TYPED_TEST(TileLayerTest, TestForwardNum) { TYPED_TEST(TileLayerTest, TestForwardChannels) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kNumTiles = 3; + const int_tp kNumTiles = 3; layer_param.mutable_tile_param()->set_tiles(kNumTiles); TileLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); - for (int n = 0; n < this->blob_top_->num(); ++n) { - for (int c = 0; c < this->blob_top_->channels(); ++c) { - for (int h = 0; h < this->blob_top_->height(); ++h) { - for (int w = 0; w < this->blob_top_->width(); ++w) { - const int bottom_c = c % this->blob_bottom_->channels(); + for (int_tp n = 0; n < this->blob_top_->num(); ++n) { + for (int_tp c = 0; c < this->blob_top_->channels(); ++c) { + for (int_tp h = 0; h < this->blob_top_->height(); ++h) { + for (int_tp w = 0; w < this->blob_top_->width(); ++w) { + const int_tp bottom_c = c % this->blob_bottom_->channels(); EXPECT_EQ(this->blob_bottom_->data_at(n, bottom_c, h, w), this->blob_top_->data_at(n, c, h, w)); } @@ -124,7 +124,7 @@ TYPED_TEST(TileLayerTest, TestForwardChannels) { TYPED_TEST(TileLayerTest, TestTrivialGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kNumTiles = 1; + const int_tp kNumTiles = 1; layer_param.mutable_tile_param()->set_tiles(kNumTiles); TileLayer layer(layer_param); GradientChecker checker(1e-2, 1e-2); @@ -135,8 +135,8 @@ TYPED_TEST(TileLayerTest, TestTrivialGradient) { TYPED_TEST(TileLayerTest, TestGradientNum) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kTileAxis = 0; - const int kNumTiles = 3; + const int_tp kTileAxis = 0; + const int_tp kNumTiles = 3; layer_param.mutable_tile_param()->set_axis(kTileAxis); layer_param.mutable_tile_param()->set_tiles(kNumTiles); TileLayer layer(layer_param); @@ -148,8 +148,8 @@ TYPED_TEST(TileLayerTest, TestGradientNum) { TYPED_TEST(TileLayerTest, TestGradientChannels) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; - const int kTileAxis = 1; - const int kNumTiles = 3; + const int_tp kTileAxis = 1; + const int_tp kNumTiles = 3; layer_param.mutable_tile_param()->set_axis(kTileAxis); layer_param.mutable_tile_param()->set_tiles(kNumTiles); TileLayer layer(layer_param); diff --git a/src/caffe/test/test_upgrade_proto.cpp b/src/caffe/test/test_upgrade_proto.cpp index 9dcc2aa55ec..6acf7ea373b 100644 --- a/src/caffe/test/test_upgrade_proto.cpp +++ b/src/caffe/test/test_upgrade_proto.cpp @@ -2894,7 +2894,7 @@ TEST_F(NetUpgradeTest, TestImageNet) { TEST_F(NetUpgradeTest, TestUpgradeV1LayerType) { LayerParameter layer_param; shared_ptr > layer; - for (int i = 0; i < V1LayerParameter_LayerType_LayerType_ARRAYSIZE; ++i) { + for (int_tp i = 0; i < V1LayerParameter_LayerType_LayerType_ARRAYSIZE; ++i) { ASSERT_TRUE(V1LayerParameter_LayerType_IsValid(i)); V1LayerParameter_LayerType v1_type = V1LayerParameter_LayerType(i); string v2_layer_type(UpgradeV1LayerType(v1_type)); diff --git a/src/caffe/test/test_util_blas.cpp b/src/caffe/test/test_util_blas.cpp index 9ee8818ff1d..43699d09860 100644 --- a/src/caffe/test/test_util_blas.cpp +++ b/src/caffe/test/test_util_blas.cpp @@ -10,120 +10,202 @@ namespace caffe { -extern cudaDeviceProp CAFFE_TEST_CUDA_PROP; - template class GemmTest : public ::testing::Test {}; TYPED_TEST_CASE(GemmTest, TestDtypes); TYPED_TEST(GemmTest, TestGemmCPUGPU) { - Blob A(1, 1, 2, 3); - Blob B(1, 1, 3, 4); - Blob C(1, 1, 2, 4); + device *dc = Caffe::GetDefaultDevice(); + + Blob A(1, 1, 2, 3, Caffe::GetDefaultDevice()); + Blob B(1, 1, 3, 4, Caffe::GetDefaultDevice()); + Blob C(1, 1, 2, 4, Caffe::GetDefaultDevice()); TypeParam data[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; TypeParam A_reshape_data[6] = {1, 4, 2, 5, 3, 6}; TypeParam B_reshape_data[12] = {1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12}; TypeParam result[8] = {38, 44, 50, 56, 83, 98, 113, 128}; - caffe_copy(6, data, A.mutable_cpu_data()); - caffe_copy(12, data, B.mutable_cpu_data()); - - if (sizeof(TypeParam) == 4 || CAFFE_TEST_CUDA_PROP.major >= 2) { - // [1, 2, 3; 4 5 6] * [1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12]; - caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, 2, 4, 3, 1., - A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } + + caffe_cpu_copy(6, data, A.mutable_cpu_data()); + caffe_cpu_copy(12, data, B.mutable_cpu_data()); + + // [1, 2, 3; 4 5 6] * [1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12]; + caffe_cpu_gemm(CblasNoTrans, CblasNoTrans, 2, 4, 3, 1., + A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_gemm(CblasNoTrans, CblasNoTrans, 2, 4, 3, 1., - A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } - - // Test when we have a transposed A - A.Reshape(1, 1, 3, 2); - caffe_copy(6, A_reshape_data, A.mutable_cpu_data()); - caffe_cpu_gemm(CblasTrans, CblasNoTrans, 2, 4, 3, 1., - A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } - caffe_gpu_gemm(CblasTrans, CblasNoTrans, 2, 4, 3, 1., - A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } - - // Test when we have a transposed A and a transposed B too - B.Reshape(1, 1, 4, 3); - caffe_copy(12, B_reshape_data, B.mutable_cpu_data()); - caffe_cpu_gemm(CblasTrans, CblasTrans, 2, 4, 3, 1., - A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } + A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemm(dc->id(), CblasNoTrans, CblasNoTrans, + 2, 4, 3, 1., + (cl_mem)(A.gpu_data()), 0, + (cl_mem)(B.gpu_data()), 0, 0., + (cl_mem)(C.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + // Test when we have a transposed A + A.Reshape(1, 1, 3, 2); + caffe_cpu_copy(6, A_reshape_data, A.mutable_cpu_data()); + caffe_cpu_gemm(CblasTrans, CblasNoTrans, 2, 4, 3, 1., + A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA + caffe_gpu_gemm(CblasTrans, CblasNoTrans, 2, 4, 3, 1., + A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemm(dc->id(), CblasTrans, CblasNoTrans, + 2, 4, 3, 1., + (cl_mem)(A.gpu_data()), 0, + (cl_mem)(B.gpu_data()), 0, + 0., (cl_mem)(C.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + // Test when we have a transposed A and a transposed B too + B.Reshape(1, 1, 4, 3); + caffe_cpu_copy(12, B_reshape_data, B.mutable_cpu_data()); + caffe_cpu_gemm(CblasTrans, CblasTrans, 2, 4, 3, 1., + A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_gemm(CblasTrans, CblasTrans, 2, 4, 3, 1., - A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } - - // Test when we have a transposed B - A.Reshape(1, 1, 2, 3); - caffe_copy(6, data, A.mutable_cpu_data()); - caffe_cpu_gemm(CblasNoTrans, CblasTrans, 2, 4, 3, 1., - A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } + A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemm(dc->id(), CblasTrans, CblasTrans, + 2, 4, 3, 1., + (cl_mem)(A.gpu_data()), 0, + (cl_mem)(B.gpu_data()), 0, 0., + (cl_mem)(C.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + // Test when we have a transposed B + A.Reshape(1, 1, 2, 3); + caffe_cpu_copy(6, data, A.mutable_cpu_data()); + caffe_cpu_gemm(CblasNoTrans, CblasTrans, 2, 4, 3, 1., + A.cpu_data(), B.cpu_data(), 0., C.mutable_cpu_data()); + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); + } + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_gemm(CblasNoTrans, CblasTrans, 2, 4, 3, 1., - A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); - for (int i = 0; i < 8; ++i) { - EXPECT_EQ(C.cpu_data()[i], result[i]); - } + A.gpu_data(), B.gpu_data(), 0., C.mutable_gpu_data()); +#endif // USE_CUDA } else { - LOG(ERROR) << "Skipping test due to old architecture."; +#ifdef USE_GREENTEA + greentea_gpu_gemm(dc->id(), CblasNoTrans, CblasTrans, + 2, 4, 3, 1., + (cl_mem)(A.gpu_data()), 0, + (cl_mem)(B.gpu_data()), 0, 0., + (cl_mem)(C.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < 8; ++i) { + EXPECT_EQ(C.cpu_data()[i], result[i]); } } TYPED_TEST(GemmTest, TestGemvCPUGPU) { - Blob A(1, 1, 2, 3); - Blob x(1, 1, 1, 3); - Blob y(1, 1, 1, 2); + device *dc = Caffe::GetDefaultDevice(); + + Blob A(1, 1, 2, 3, Caffe::GetDefaultDevice()); + Blob x(1, 1, 1, 3, Caffe::GetDefaultDevice()); + Blob y(1, 1, 1, 2, Caffe::GetDefaultDevice()); TypeParam data[6] = {1, 2, 3, 4, 5, 6}; TypeParam result_2[2] = {14, 32}; TypeParam result_3[3] = {9, 12, 15}; - caffe_copy(6, data, A.mutable_cpu_data()); - caffe_copy(3, data, x.mutable_cpu_data()); - - if (sizeof(TypeParam) == 4 || CAFFE_TEST_CUDA_PROP.major >= 2) { - caffe_cpu_gemv(CblasNoTrans, 2, 3, 1., A.cpu_data(), - x.cpu_data(), 0., y.mutable_cpu_data()); - for (int i = 0; i < 2; ++i) { - EXPECT_EQ(y.cpu_data()[i], result_2[i]); - } + + caffe_cpu_copy(6, data, A.mutable_cpu_data()); + caffe_cpu_copy(3, data, x.mutable_cpu_data()); + + + caffe_cpu_gemv(CblasNoTrans, 2, 3, 1., A.cpu_data(), + x.cpu_data(), 0., y.mutable_cpu_data()); + for (int_tp i = 0; i < 2; ++i) { + EXPECT_EQ(y.cpu_data()[i], result_2[i]); + } + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_gemv(CblasNoTrans, 2, 3, 1., A.gpu_data(), - x.gpu_data(), 0., y.mutable_gpu_data()); - for (int i = 0; i < 2; ++i) { - EXPECT_EQ(y.cpu_data()[i], result_2[i]); - } - - // Test transpose case - caffe_copy(2, data, y.mutable_cpu_data()); - caffe_cpu_gemv(CblasTrans, 2, 3, 1., A.cpu_data(), - y.cpu_data(), 0., x.mutable_cpu_data()); - for (int i = 0; i < 3; ++i) { - EXPECT_EQ(x.cpu_data()[i], result_3[i]); - } + x.gpu_data(), 0., y.mutable_gpu_data()); +#endif // USE_CUDA + } else { +#ifdef USE_GREENTEA + greentea_gpu_gemv(dc->id(), CblasNoTrans, + 2, 3, 1., + (cl_mem)(A.gpu_data()), 0, + (cl_mem)(x.gpu_data()), 0, 0., + (cl_mem)(y.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < 2; ++i) { + EXPECT_EQ(y.cpu_data()[i], result_2[i]); + } + + // Test transpose case + caffe_cpu_copy(2, data, y.mutable_cpu_data()); + caffe_cpu_gemv(CblasTrans, 2, 3, 1., A.cpu_data(), + y.cpu_data(), 0., x.mutable_cpu_data()); + for (int_tp i = 0; i < 3; ++i) { + EXPECT_EQ(x.cpu_data()[i], result_3[i]); + } + + if (dc->backend() == BACKEND_CUDA) { +#ifdef USE_CUDA caffe_gpu_gemv(CblasTrans, 2, 3, 1., A.gpu_data(), - y.gpu_data(), 0., x.mutable_gpu_data()); - for (int i = 0; i < 3; ++i) { - EXPECT_EQ(x.cpu_data()[i], result_3[i]); - } + y.gpu_data(), 0., x.mutable_gpu_data()); +#endif // USE_CUDA } else { - LOG(ERROR) << "Skipping test due to old architecture."; +#ifdef USE_GREENTEA + greentea_gpu_gemv(dc->id(), CblasTrans, + 2, 3, 1., + (cl_mem)(A.gpu_data()), 0, + (cl_mem)(y.gpu_data()), 0, 0., + (cl_mem)(x.mutable_gpu_data()), 0); +#endif // USE_GREENTEA + } + + for (int_tp i = 0; i < 3; ++i) { + EXPECT_EQ(x.cpu_data()[i], result_3[i]); } } diff --git a/src/caffe/util/benchmark.cpp b/src/caffe/util/benchmark.cpp index 1d269c351c1..e542c982049 100644 --- a/src/caffe/util/benchmark.cpp +++ b/src/caffe/util/benchmark.cpp @@ -1,22 +1,24 @@ #include #include "caffe/common.hpp" +#include "caffe/device.hpp" #include "caffe/util/benchmark.hpp" namespace caffe { Timer::Timer() - : initted_(false), - running_(false), - has_run_at_least_once_(false) { + : initted_(false), running_(false), has_run_at_least_once_(false) { Init(); } Timer::~Timer() { - if (Caffe::mode() == Caffe::GPU) { + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaEventDestroy(start_gpu_)); CUDA_CHECK(cudaEventDestroy(stop_gpu_)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -25,9 +27,12 @@ Timer::~Timer() { void Timer::Start() { if (!running()) { - if (Caffe::mode() == Caffe::GPU) { + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaEventRecord(start_gpu_, 0)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -41,10 +46,13 @@ void Timer::Start() { void Timer::Stop() { if (running()) { - if (Caffe::mode() == Caffe::GPU) { + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaEventRecord(stop_gpu_, 0)); CUDA_CHECK(cudaEventSynchronize(stop_gpu_)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -55,23 +63,25 @@ void Timer::Stop() { } } - float Timer::MicroSeconds() { if (!has_run_at_least_once()) { - LOG(WARNING) << "Timer has never been run before reading time."; + LOG(WARNING)<< "Timer has never been run before reading time."; return 0; } if (running()) { Stop(); } - if (Caffe::mode() == Caffe::GPU) { + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaEventElapsedTime(&elapsed_milliseconds_, start_gpu_, - stop_gpu_)); + stop_gpu_)); // Cuda only measure milliseconds elapsed_microseconds_ = elapsed_milliseconds_ * 1000; +#endif // USE_CUDA #else - NO_GPU; + NO_GPU; #endif } else { elapsed_microseconds_ = (stop_cpu_ - start_cpu_).total_microseconds(); @@ -81,18 +91,21 @@ float Timer::MicroSeconds() { float Timer::MilliSeconds() { if (!has_run_at_least_once()) { - LOG(WARNING) << "Timer has never been run before reading time."; + LOG(WARNING)<< "Timer has never been run before reading time."; return 0; } if (running()) { Stop(); } - if (Caffe::mode() == Caffe::GPU) { + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaEventElapsedTime(&elapsed_milliseconds_, start_gpu_, - stop_gpu_)); + stop_gpu_)); +#endif // USE_CUDA #else - NO_GPU; + NO_GPU; #endif } else { elapsed_milliseconds_ = (stop_cpu_ - start_cpu_).total_milliseconds(); @@ -106,10 +119,13 @@ float Timer::Seconds() { void Timer::Init() { if (!initted()) { - if (Caffe::mode() == Caffe::GPU) { + if (Caffe::mode() == Caffe::GPU + && Caffe::GetDefaultDevice()->backend() == BACKEND_CUDA) { #ifndef CPU_ONLY +#ifdef USE_CUDA CUDA_CHECK(cudaEventCreate(&start_gpu_)); CUDA_CHECK(cudaEventCreate(&stop_gpu_)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -141,14 +157,14 @@ void CPUTimer::Stop() { float CPUTimer::MilliSeconds() { if (!has_run_at_least_once()) { - LOG(WARNING) << "Timer has never been run before reading time."; + LOG(WARNING)<< "Timer has never been run before reading time."; return 0; } if (running()) { Stop(); } this->elapsed_milliseconds_ = (this->stop_cpu_ - - this->start_cpu_).total_milliseconds(); + this->start_cpu_).total_milliseconds(); return this->elapsed_milliseconds_; } @@ -161,7 +177,7 @@ float CPUTimer::MicroSeconds() { Stop(); } this->elapsed_microseconds_ = (this->stop_cpu_ - - this->start_cpu_).total_microseconds(); + this->start_cpu_).total_microseconds(); return this->elapsed_microseconds_; } diff --git a/src/caffe/util/blocking_queue.cpp b/src/caffe/util/blocking_queue.cpp index 058668fe28c..16217cd2a07 100644 --- a/src/caffe/util/blocking_queue.cpp +++ b/src/caffe/util/blocking_queue.cpp @@ -81,7 +81,7 @@ T BlockingQueue::peek() { } template -size_t BlockingQueue::size() const { +uint_tp BlockingQueue::size() const { boost::mutex::scoped_lock lock(sync_->mutex_); return queue_.size(); } diff --git a/src/caffe/util/db_lmdb.cpp b/src/caffe/util/db_lmdb.cpp index 0bc82b53e2b..57f941e4699 100644 --- a/src/caffe/util/db_lmdb.cpp +++ b/src/caffe/util/db_lmdb.cpp @@ -15,7 +15,7 @@ void LMDB::Open(const string& source, Mode mode) { if (mode == NEW) { CHECK_EQ(mkdir(source.c_str(), 0744), 0) << "mkdir " << source << "failed"; } - int flags = 0; + int_tp flags = 0; if (mode == READ) { flags = MDB_RDONLY | MDB_NOTLS; } diff --git a/src/caffe/util/hdf5.cpp b/src/caffe/util/hdf5.cpp index 7730e76ab87..ce1b5d7c83b 100644 --- a/src/caffe/util/hdf5.cpp +++ b/src/caffe/util/hdf5.cpp @@ -56,8 +56,8 @@ void hdf5_load_nd_dataset_helper( LOG(FATAL) << "Datatype class unknown"; } - vector blob_dims(dims.size()); - for (int i = 0; i < dims.size(); ++i) { + vector blob_dims(dims.size()); + for (int_tp i = 0; i < dims.size(); ++i) { blob_dims[i] = dims[i]; } blob->Reshape(blob_dims); @@ -87,7 +87,7 @@ void hdf5_save_nd_dataset( bool write_diff) { int num_axes = blob.num_axes(); hsize_t *dims = new hsize_t[num_axes]; - for (int i = 0; i < num_axes; ++i) { + for (int_tp i = 0; i < num_axes; ++i) { dims[i] = blob.shape(i); } const float* data; @@ -106,9 +106,9 @@ template <> void hdf5_save_nd_dataset( hid_t file_id, const string& dataset_name, const Blob& blob, bool write_diff) { - int num_axes = blob.num_axes(); + int_tp num_axes = blob.num_axes(); hsize_t *dims = new hsize_t[num_axes]; - for (int i = 0; i < num_axes; ++i) { + for (int_tp i = 0; i < num_axes; ++i) { dims[i] = blob.shape(i); } const double* data; @@ -171,11 +171,11 @@ int hdf5_get_num_links(hid_t loc_id) { } string hdf5_get_name_by_idx(hid_t loc_id, int idx) { - ssize_t str_size = H5Lget_name_by_idx( + int str_size = H5Lget_name_by_idx( loc_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, idx, NULL, 0, H5P_DEFAULT); CHECK_GE(str_size, 0) << "Error retrieving HDF5 dataset at index " << idx; char *c_str = new char[str_size+1]; - ssize_t status = H5Lget_name_by_idx( + int status = H5Lget_name_by_idx( loc_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, idx, c_str, str_size+1, H5P_DEFAULT); CHECK_GE(status, 0) << "Error retrieving HDF5 dataset at index " << idx; diff --git a/src/caffe/util/im2col.cpp b/src/caffe/util/im2col.cpp index 114a86cb81e..12698268846 100644 --- a/src/caffe/util/im2col.cpp +++ b/src/caffe/util/im2col.cpp @@ -11,34 +11,34 @@ namespace caffe { // therefore its value is always lower than 0x800... where casting // negative value of a parameter converts it to value higher than 0x800... // The casting allows to use one condition instead of two. -inline bool is_a_ge_zero_and_a_lt_b(int a, int b) { +inline bool is_a_ge_zero_and_a_lt_b(int_tp a, int_tp b) { return static_cast(a) < static_cast(b); } -template -void im2col_cpu(const Dtype* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, - const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, - Dtype* data_col) { - const int output_h = (height + 2 * pad_h - - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; - const int output_w = (width + 2 * pad_w - - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; - const int channel_size = height * width; - for (int channel = channels; channel--; data_im += channel_size) { - for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) { - for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) { - int input_row = -pad_h + kernel_row * dilation_h; - for (int output_rows = output_h; output_rows; output_rows--) { +template +void im2col_cpu(const Dtype* data_im, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_col) { + const int_tp output_h = (height + 2 * pad_h + - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; + const int_tp output_w = + (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; + const int_tp channel_size = height * width; + for (int_tp channel = channels; channel--; data_im += channel_size) { + for (int_tp kernel_row = 0; kernel_row < kernel_h; kernel_row++) { + for (int_tp kernel_col = 0; kernel_col < kernel_w; kernel_col++) { + int_tp input_row = -pad_h + kernel_row * dilation_h; + for (int_tp output_rows = output_h; output_rows; output_rows--) { if (!is_a_ge_zero_and_a_lt_b(input_row, height)) { - for (int output_cols = output_w; output_cols; output_cols--) { + for (int_tp output_cols = output_w; output_cols; output_cols--) { *(data_col++) = 0; } } else { - int input_col = -pad_w + kernel_col * dilation_w; - for (int output_col = output_w; output_col; output_col--) { + int_tp input_col = -pad_w + kernel_col * dilation_w; + for (int_tp output_col = output_w; output_col; output_col--) { if (is_a_ge_zero_and_a_lt_b(input_col, width)) { *(data_col++) = data_im[input_row * width + input_col]; } else { @@ -55,55 +55,61 @@ void im2col_cpu(const Dtype* data_im, const int channels, } // Explicit instantiation -template void im2col_cpu(const float* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - float* data_col); -template void im2col_cpu(const double* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - double* data_col); +template void im2col_cpu(const float* data_im, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, float* data_col); +template void im2col_cpu(const double* data_im, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, double* data_col); -template +template inline void im2col_nd_core_cpu(const Dtype* data_input, const bool im2col, - const int num_spatial_axes, const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_output) { + const int_tp num_spatial_axes, + const int_tp* im_shape, const int_tp* col_shape, + const int_tp* kernel_shape, const int_tp* pad, + const int_tp* stride, const int_tp* dilation, + Dtype* data_output) { if (!im2col) { - int im_size = im_shape[0]; - for (int i = 0; i < num_spatial_axes; ++i) { + int_tp im_size = im_shape[0]; + for (int_tp i = 0; i < num_spatial_axes; ++i) { im_size *= im_shape[1 + i]; } caffe_set(im_size, Dtype(0), data_output); } - int kernel_size = 1; - for (int i = 0; i < num_spatial_axes; ++i) { + int_tp kernel_size = 1; + for (int_tp i = 0; i < num_spatial_axes; ++i) { kernel_size *= kernel_shape[i]; } - const int channels_col = col_shape[0]; - vector d_offset(num_spatial_axes, 0); - vector d_iter(num_spatial_axes, 0); - for (int c_col = 0; c_col < channels_col; ++c_col) { + const int_tp channels_col = col_shape[0]; + vector d_offset(num_spatial_axes, 0); + vector d_iter(num_spatial_axes, 0); + for (int_tp c_col = 0; c_col < channels_col; ++c_col) { // Loop over spatial axes in reverse order to compute a per-axis offset. - int offset = c_col; - for (int d_i = num_spatial_axes - 1; d_i >= 0; --d_i) { + int_tp offset = c_col; + for (int_tp d_i = num_spatial_axes - 1; d_i >= 0; --d_i) { if (d_i < num_spatial_axes - 1) { offset /= kernel_shape[d_i + 1]; } d_offset[d_i] = offset % kernel_shape[d_i]; } - for (bool incremented = true; incremented; ) { + for (bool incremented = true; incremented;) { // Loop over spatial axes in forward order to compute the indices in the // image and column, and whether the index lies in the padding. - int index_col = c_col; - int index_im = c_col / kernel_size; + int_tp index_col = c_col; + int_tp index_im = c_col / kernel_size; bool is_padding = false; - for (int d_i = 0; d_i < num_spatial_axes; ++d_i) { - const int d = d_iter[d_i]; - const int d_im = d * stride[d_i] - pad[d_i] + - d_offset[d_i] * dilation[d_i]; + for (int_tp d_i = 0; d_i < num_spatial_axes; ++d_i) { + const int_tp d = d_iter[d_i]; + const int_tp d_im = d * stride[d_i] - pad[d_i] + + d_offset[d_i] * dilation[d_i]; is_padding |= d_im < 0 || d_im >= im_shape[d_i + 1]; index_col *= col_shape[d_i + 1]; index_col += d; @@ -122,8 +128,8 @@ inline void im2col_nd_core_cpu(const Dtype* data_input, const bool im2col, // Loop over spatial axes in reverse order to choose an index, // like counting. incremented = false; - for (int d_i = num_spatial_axes - 1; d_i >= 0; --d_i) { - const int d_max = col_shape[d_i + 1]; + for (int_tp d_i = num_spatial_axes - 1; d_i >= 0; --d_i) { + const int_tp d_max = col_shape[d_i + 1]; DCHECK_LT(d_iter[d_i], d_max); if (d_iter[d_i] == d_max - 1) { d_iter[d_i] = 0; @@ -134,54 +140,59 @@ inline void im2col_nd_core_cpu(const Dtype* data_input, const bool im2col, } } } // while(incremented) { - } // for (int c = 0; c < channels_col; ++c) { + } // for (int_tp c = 0; c < channels_col; ++c) { } -template -void im2col_nd_cpu(const Dtype* data_im, const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_col) { +template +void im2col_nd_cpu(const Dtype* data_im, const int_tp num_spatial_axes, + const int_tp* im_shape, const int_tp* col_shape, + const int_tp* kernel_shape, const int_tp* pad, + const int_tp* stride, const int_tp* dilation, + Dtype* data_col) { const bool kIm2Col = true; im2col_nd_core_cpu(data_im, kIm2Col, num_spatial_axes, im_shape, col_shape, - kernel_shape, pad, stride, dilation, data_col); + kernel_shape, pad, stride, dilation, data_col); } // Explicit instantiation template void im2col_nd_cpu(const float* data_im, - const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, float* data_col); + const int_tp num_spatial_axes, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, float* data_col); template void im2col_nd_cpu(const double* data_im, - const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, double* data_col); + const int_tp num_spatial_axes, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, double* data_col); -template -void col2im_cpu(const Dtype* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, - const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, - Dtype* data_im) { +template +void col2im_cpu(const Dtype* data_col, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_im) { caffe_set(height * width * channels, Dtype(0), data_im); - const int output_h = (height + 2 * pad_h - + const int_tp output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; - const int output_w = (width + 2 * pad_w - + const int_tp output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; - const int channel_size = height * width; - for (int channel = channels; channel--; data_im += channel_size) { - for (int kernel_row = 0; kernel_row < kernel_h; kernel_row++) { - for (int kernel_col = 0; kernel_col < kernel_w; kernel_col++) { - int input_row = -pad_h + kernel_row * dilation_h; - for (int output_rows = output_h; output_rows; output_rows--) { + const int_tp channel_size = height * width; + for (int_tp channel = channels; channel--; data_im += channel_size) { + for (int_tp kernel_row = 0; kernel_row < kernel_h; kernel_row++) { + for (int_tp kernel_col = 0; kernel_col < kernel_w; kernel_col++) { + int_tp input_row = -pad_h + kernel_row * dilation_h; + for (int_tp output_rows = output_h; output_rows; output_rows--) { if (!is_a_ge_zero_and_a_lt_b(input_row, height)) { data_col += output_w; } else { - int input_col = -pad_w + kernel_col * dilation_w; - for (int output_col = output_w; output_col; output_col--) { + int_tp input_col = -pad_w + kernel_col * dilation_w; + for (int_tp output_col = output_w; output_col; output_col--) { if (is_a_ge_zero_and_a_lt_b(input_col, width)) { data_im[input_row * width + input_col] += *data_col; } @@ -197,22 +208,27 @@ void col2im_cpu(const Dtype* data_col, const int channels, } // Explicit instantiation -template void col2im_cpu(const float* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - float* data_im); -template void col2im_cpu(const double* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - double* data_im); +template void col2im_cpu(const float* data_col, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, float* data_im); +template void col2im_cpu(const double* data_col, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, double* data_im); -template -void col2im_nd_cpu(const Dtype* data_col, const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_im) { +template +void col2im_nd_cpu(const Dtype* data_col, const int_tp num_spatial_axes, + const int_tp* im_shape, const int_tp* col_shape, + const int_tp* kernel_shape, const int_tp* pad, + const int_tp* stride, const int_tp* dilation, + Dtype* data_im) { const bool kIm2Col = false; im2col_nd_core_cpu(data_col, kIm2Col, num_spatial_axes, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); @@ -220,15 +236,18 @@ void col2im_nd_cpu(const Dtype* data_col, const int num_spatial_axes, // Explicit instantiation template void col2im_nd_cpu(const float* data_col, - const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, float* data_im); + const int_tp num_spatial_axes, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, float* data_im); template void col2im_nd_cpu(const double* data_col, - const int num_spatial_axes, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, double* data_im); - + const int_tp num_spatial_axes, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, double* data_im); } // namespace caffe diff --git a/src/caffe/util/im2col.cu b/src/caffe/util/im2col.cu index a8f30a02484..7a1715ef45c 100644 --- a/src/caffe/util/im2col.cu +++ b/src/caffe/util/im2col.cu @@ -1,34 +1,41 @@ #include +#include +#include +#include +#include #include "caffe/common.hpp" #include "caffe/util/im2col.hpp" namespace caffe { +#ifdef USE_CUDA template -__global__ void im2col_gpu_kernel(const int n, const Dtype* data_im, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, - const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, - const int height_col, const int width_col, - Dtype* data_col) { +__global__ void im2col_gpu_kernel(const int_tp n, const Dtype* data_im, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + const int_tp height_col, + const int_tp width_col, Dtype* data_col) { CUDA_KERNEL_LOOP(index, n) { - const int h_index = index / width_col; - const int h_col = h_index % height_col; - const int w_col = index % width_col; - const int c_im = h_index / height_col; - const int c_col = c_im * kernel_h * kernel_w; - const int h_offset = h_col * stride_h - pad_h; - const int w_offset = w_col * stride_w - pad_w; + const int_tp h_index = index / width_col; + const int_tp h_col = h_index % height_col; + const int_tp w_col = index % width_col; + const int_tp c_im = h_index / height_col; + const int_tp c_col = c_im * kernel_h * kernel_w; + const int_tp h_offset = h_col * stride_h - pad_h; + const int_tp w_offset = w_col * stride_w - pad_w; Dtype* data_col_ptr = data_col; data_col_ptr += (c_col * height_col + h_col) * width_col + w_col; const Dtype* data_im_ptr = data_im; data_im_ptr += (c_im * height + h_offset) * width + w_offset; - for (int i = 0; i < kernel_h; ++i) { - for (int j = 0; j < kernel_w; ++j) { - int h_im = h_offset + i * dilation_h; - int w_im = w_offset + j * dilation_w; + for (int_tp i = 0; i < kernel_h; ++i) { + for (int_tp j = 0; j < kernel_w; ++j) { + int_tp h_im = h_offset + i * dilation_h; + int_tp w_im = w_offset + j * dilation_w; *data_col_ptr = (h_im >= 0 && w_im >= 0 && h_im < height && w_im < width) ? data_im_ptr[i * dilation_h * width + j * dilation_w] : 0; @@ -38,23 +45,23 @@ __global__ void im2col_gpu_kernel(const int n, const Dtype* data_im, } } -template -void im2col_gpu(const Dtype* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, - const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, - Dtype* data_col) { +template +void im2col_gpu(const Dtype* data_im, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_col) { // We are going to launch channels * height_col * width_col kernels, each // kernel responsible for copying a single-channel grid. - int height_col = (height + 2 * pad_h - - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; - int width_col = (width + 2 * pad_w - - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; - int num_kernels = channels * height_col * width_col; + int_tp height_col = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) + / stride_h + 1; + int_tp width_col = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) + / stride_w + 1; + int_tp num_kernels = channels * height_col * width_col; // NOLINT_NEXT_LINE(whitespace/operators) - im2col_gpu_kernel<<>>( + im2col_gpu_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), + CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, height, width, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w, height_col, width_col, data_col); @@ -62,29 +69,37 @@ void im2col_gpu(const Dtype* data_im, const int channels, } // Explicit instantiation -template void im2col_gpu(const float* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, float* data_col); -template void im2col_gpu(const double* data_im, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, double* data_col); +template void im2col_gpu(const float* data_im, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, float* data_col); +template void im2col_gpu(const double* data_im, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, double* data_col); -template -__global__ void im2col_nd_gpu_kernel(const int n, const Dtype* data_im, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_col) { - int d_temp[num_axes]; // NOLINT(runtime/arrays) - int d_iter[num_axes]; // NOLINT(runtime/arrays) +template +__global__ void im2col_nd_gpu_kernel(const int_tp n, const Dtype* data_im, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_col) { + int_tp d_temp[num_axes]; // NOLINT(runtime/arrays) + int_tp d_iter[num_axes]; // NOLINT(runtime/arrays) - __shared__ int shared_dilation[num_axes]; - __shared__ int shared_kernel_shape[num_axes]; - __shared__ int shared_pad[num_axes]; - __shared__ int shared_stride[num_axes]; - __shared__ int shared_col_shape[num_axes + 1]; - __shared__ int shared_im_shape[num_axes + 1]; + __shared__ int_tp shared_dilation[num_axes]; + __shared__ int_tp shared_kernel_shape[num_axes]; + __shared__ int_tp shared_pad[num_axes]; + __shared__ int_tp shared_stride[num_axes]; + __shared__ int_tp shared_col_shape[num_axes + 1]; + __shared__ int_tp shared_im_shape[num_axes + 1]; if (threadIdx.x < num_axes) { shared_dilation[threadIdx.x] = dilation[threadIdx.x]; @@ -98,19 +113,19 @@ __global__ void im2col_nd_gpu_kernel(const int n, const Dtype* data_im, } __syncthreads(); - int i; + int_tp i; CUDA_KERNEL_LOOP(index, n) { // Initialize channel_in, computed in the loop below, with intermediate // computations used to compute the spatial indices. - int channel_in = index; - int channel_out = 1; + int_tp channel_in = index; + int_tp channel_out = 1; for (i = num_axes - 1; i >= 0; --i) { d_temp[i] = channel_in % shared_col_shape[i + 1]; channel_in /= shared_col_shape[i + 1]; channel_out *= shared_kernel_shape[i]; } channel_out *= channel_in; - int data_col_inc = 1; + int_tp data_col_inc = 1; for (i = 0; i < num_axes; ++i) { channel_out *= shared_col_shape[i + 1]; channel_out += d_temp[i]; @@ -126,12 +141,12 @@ __global__ void im2col_nd_gpu_kernel(const int n, const Dtype* data_im, do { bool in_range = true; for (i = 0; i < num_axes; ++i) { - const int d_iter_im = d_iter[i] * shared_dilation[i] + d_temp[i]; + const int_tp d_iter_im = d_iter[i] * shared_dilation[i] + d_temp[i]; in_range &= d_iter_im >= 0 && d_iter_im < shared_im_shape[i + 1]; if (!in_range) { break; } } if (in_range) { - int data_im_offset = d_iter[0] * shared_dilation[0]; + int_tp data_im_offset = d_iter[0] * shared_dilation[0]; for (i = 1; i < num_axes; ++i) { data_im_offset *= shared_im_shape[i + 1]; data_im_offset += d_iter[i] * shared_dilation[i]; @@ -143,7 +158,7 @@ __global__ void im2col_nd_gpu_kernel(const int n, const Dtype* data_im, data_col_ptr += data_col_inc; incremented = false; for (i = num_axes - 1; i >= 0; --i) { - const int d_max = shared_kernel_shape[i]; + const int_tp d_max = shared_kernel_shape[i]; if (d_iter[i] == d_max - 1) { d_iter[i] = 0; } else { // d_iter[i] < d_max - 1 @@ -151,76 +166,77 @@ __global__ void im2col_nd_gpu_kernel(const int n, const Dtype* data_im, incremented = true; break; } - } // for (int i = num_axes - 1; i >= 0; --i) + } // for (int_tp i = num_axes - 1; i >= 0; --i) } while (incremented); // do } // CUDA_KERNEL_LOOP(index, n) } -template -void im2col_nd_gpu(const Dtype* data_im, const int num_spatial_axes, - const int num_kernels, const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_col) { +template +void im2col_nd_gpu(const Dtype* data_im, const int_tp num_spatial_axes, + const int_tp num_kernels, const int_tp* im_shape, + const int_tp* col_shape, const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_col) { // num_axes should be smaller than block size DCHECK_LT(num_spatial_axes, CAFFE_CUDA_NUM_THREADS); switch (num_spatial_axes) { case 1: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 2: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 3: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 4: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 5: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 6: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 7: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 8: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 9: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; case 10: im2col_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), CAFFE_CUDA_NUM_THREADS)( num_kernels, data_im, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_col); break; @@ -233,48 +249,56 @@ void im2col_nd_gpu(const Dtype* data_im, const int num_spatial_axes, // Explicit instantiation template void im2col_nd_gpu(const float* data_im, - const int num_spatial_axes, const int col_size, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, float* data_col); + const int_tp num_spatial_axes, + const int_tp col_size, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, float* data_col); template void im2col_nd_gpu(const double* data_im, - const int num_spatial_axes, const int col_size, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, double* data_col); + const int_tp num_spatial_axes, + const int_tp col_size, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, double* data_col); -template -__global__ void col2im_gpu_kernel(const int n, const Dtype* data_col, - const int height, const int width, const int channels, - const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, - const int stride_h, const int stride_w, - const int dilation_h, const int dilation_w, - const int height_col, const int width_col, - Dtype* data_im) { +template +__global__ void col2im_gpu_kernel(const int_tp n, const Dtype* data_col, + const int_tp height, const int_tp width, + const int_tp channels, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, + const int_tp pad_w, const int_tp stride_h, + const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, + const int_tp height_col, + const int_tp width_col, Dtype* data_im) { CUDA_KERNEL_LOOP(index, n) { Dtype val = 0; - const int w_im = index % width + pad_w; - const int h_im = (index / width) % height + pad_h; - const int c_im = index / (width * height); - int kernel_extent_w = (kernel_w - 1) * dilation_w + 1; - int kernel_extent_h = (kernel_h - 1) * dilation_h + 1; + const int_tp w_im = index % width + pad_w; + const int_tp h_im = (index / width) % height + pad_h; + const int_tp c_im = index / (width * height); + int_tp kernel_extent_w = (kernel_w - 1) * dilation_w + 1; + int_tp kernel_extent_h = (kernel_h - 1) * dilation_h + 1; // compute the start and end of the output - const int w_col_start = + const int_tp w_col_start = (w_im < kernel_extent_w) ? 0 : (w_im - kernel_extent_w) / stride_w + 1; - const int w_col_end = min(w_im / stride_w + 1, width_col); - const int h_col_start = + const int_tp w_col_end = min(w_im / stride_w + 1, width_col); + const int_tp h_col_start = (h_im < kernel_extent_h) ? 0 : (h_im - kernel_extent_h) / stride_h + 1; - const int h_col_end = min(h_im / stride_h + 1, height_col); + const int_tp h_col_end = min(h_im / stride_h + 1, height_col); // TODO: use LCM of stride and dilation to avoid unnecessary loops - for (int h_col = h_col_start; h_col < h_col_end; h_col += 1) { - for (int w_col = w_col_start; w_col < w_col_end; w_col += 1) { - int h_k = (h_im - h_col * stride_h); - int w_k = (w_im - w_col * stride_w); + for (int_tp h_col = h_col_start; h_col < h_col_end; h_col += 1) { + for (int_tp w_col = w_col_start; w_col < w_col_end; w_col += 1) { + int_tp h_k = (h_im - h_col * stride_h); + int_tp w_k = (w_im - w_col * stride_w); if (h_k % dilation_h == 0 && w_k % dilation_w == 0) { h_k /= dilation_h; w_k /= dilation_w; - int data_col_index = (((c_im * kernel_h + h_k) * kernel_w + w_k) * + int_tp data_col_index = (((c_im * kernel_h + h_k) * kernel_w + w_k) * height_col + h_col) * width_col + w_col; val += data_col[data_col_index]; } @@ -284,22 +308,23 @@ __global__ void col2im_gpu_kernel(const int n, const Dtype* data_col, } } -template -void col2im_gpu(const Dtype* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - Dtype* data_im) { - int height_col = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / +template +void col2im_gpu(const Dtype* data_col, const int_tp channels, + const int_tp height, const int_tp width, const int_tp kernel_h, + const int_tp kernel_w, const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, const int_tp dilation_w, + Dtype* data_im) { + int_tp height_col = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; - int width_col = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / + int_tp width_col = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; - int num_kernels = channels * height * width; + int_tp num_kernels = channels * height * width; // To avoid involving atomic operations, we will launch one kernel per // bottom dimension, and then in the kernel add up the top dimensions. // NOLINT_NEXT_LINE(whitespace/operators) - col2im_gpu_kernel<<>>( + col2im_gpu_kernelCUDA_KERNEL(CAFFE_GET_BLOCKS(num_kernels), + CAFFE_CUDA_NUM_THREADS)( num_kernels, data_col, height, width, channels, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w, height_col, width_col, data_im); @@ -307,33 +332,39 @@ void col2im_gpu(const Dtype* data_col, const int channels, } // Explicit instantiation -template void col2im_gpu(const float* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - float* data_im); -template void col2im_gpu(const double* data_col, const int channels, - const int height, const int width, const int kernel_h, const int kernel_w, - const int pad_h, const int pad_w, const int stride_h, - const int stride_w, const int dilation_h, const int dilation_w, - double* data_im); +template void col2im_gpu(const float* data_col, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, float* data_im); +template void col2im_gpu(const double* data_col, const int_tp channels, + const int_tp height, const int_tp width, + const int_tp kernel_h, const int_tp kernel_w, + const int_tp pad_h, const int_tp pad_w, + const int_tp stride_h, const int_tp stride_w, + const int_tp dilation_h, + const int_tp dilation_w, double* data_im); -template -__global__ void col2im_nd_gpu_kernel(const int n, const Dtype* data_col, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_im) { - int d_im[num_axes]; // NOLINT(runtime/arrays) - int d_col_iter[num_axes]; // NOLINT(runtime/arrays) - int d_col_start[num_axes]; // NOLINT(runtime/arrays) - int d_col_end[num_axes]; // NOLINT(runtime/arrays) +template +__global__ void col2im_nd_gpu_kernel(const int_tp n, const Dtype* data_col, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_im) { + int_tp d_im[num_axes]; // NOLINT(runtime/arrays) + int_tp d_col_iter[num_axes]; // NOLINT(runtime/arrays) + int_tp d_col_start[num_axes]; // NOLINT(runtime/arrays) + int_tp d_col_end[num_axes]; // NOLINT(runtime/arrays) - __shared__ int shared_dilation[num_axes]; - __shared__ int shared_kernel_shape[num_axes]; - __shared__ int shared_pad[num_axes]; - __shared__ int shared_stride[num_axes]; - __shared__ int shared_col_shape[num_axes + 1]; - __shared__ int shared_im_shape[num_axes + 1]; + __shared__ int_tp shared_dilation[num_axes]; + __shared__ int_tp shared_kernel_shape[num_axes]; + __shared__ int_tp shared_pad[num_axes]; + __shared__ int_tp shared_stride[num_axes]; + __shared__ int_tp shared_col_shape[num_axes + 1]; + __shared__ int_tp shared_im_shape[num_axes + 1]; if (threadIdx.x < num_axes) { shared_dilation[threadIdx.x] = dilation[threadIdx.x]; @@ -348,18 +379,18 @@ __global__ void col2im_nd_gpu_kernel(const int n, const Dtype* data_col, __syncthreads(); CUDA_KERNEL_LOOP(index, n) { - // Initialize channel_in, computed in the loop below, with intermediate + // Initialize channel_in, computed in the loop below, with int_tpermediate // computations used to compute the spatial indices. - int c_im = index; + int_tp c_im = index; // Calculate d_im (image dimensions). - for (int i = num_axes - 1; i >= 0; --i) { + for (int_tp i = num_axes - 1; i >= 0; --i) { d_im[i] = c_im % shared_im_shape[i + 1] + shared_pad[i]; c_im /= shared_im_shape[i + 1]; } // Calculate col start/end indices. bool done = false; - for (int i = 0; i < num_axes; ++i) { - const int kernel_extent = + for (int_tp i = 0; i < num_axes; ++i) { + const int_tp kernel_extent = shared_dilation[i] * (shared_kernel_shape[i] - 1) + 1; d_col_start[i] = d_col_iter[i] = (d_im[i] < kernel_extent) ? 0 : @@ -371,7 +402,7 @@ __global__ void col2im_nd_gpu_kernel(const int n, const Dtype* data_col, // final val will be 0. data_im[index] = 0; done = true; - break; // for (int i = 0; i < num_axes; ++i) + break; // for (int_tp i = 0; i < num_axes; ++i) } } if (done) { @@ -383,10 +414,10 @@ __global__ void col2im_nd_gpu_kernel(const int n, const Dtype* data_col, bool skip = false; do { // Compute the final offset. - int final_offset = 0; - int kernel_shape_prod = 1; - int kernel_index; - for (int i = num_axes - 1; i >= 0; --i) { + int_tp final_offset = 0; + int_tp kernel_shape_prod = 1; + int_tp kernel_index; + for (int_tp i = num_axes - 1; i >= 0; --i) { kernel_index = d_im[i] - d_col_iter[i] * shared_stride[i]; if (kernel_index % shared_dilation[i]) { skip = true; @@ -399,7 +430,7 @@ __global__ void col2im_nd_gpu_kernel(const int n, const Dtype* data_col, } if (!skip) { final_offset += kernel_shape_prod * c_im; - for (int i = 0; i < num_axes; ++i) { + for (int_tp i = 0; i < num_axes; ++i) { final_offset *= shared_col_shape[i + 1]; final_offset += d_col_iter[i]; } @@ -407,86 +438,87 @@ __global__ void col2im_nd_gpu_kernel(const int n, const Dtype* data_col, } skip = false; incremented = false; - for (int i = num_axes - 1; i >= 0; --i) { - const int d_max = d_col_end[i]; + for (int_tp i = num_axes - 1; i >= 0; --i) { + const int_tp d_max = d_col_end[i]; if (d_col_iter[i] == d_max - 1) { d_col_iter[i] = d_col_start[i]; } else { // d_col_iter[i] < d_max - 1 ++d_col_iter[i]; incremented = true; - break; // for (int i = num_axes - 1; i >= 0; --i) + break; // for (int_tp i = num_axes - 1; i >= 0; --i) } - } // for (int i = num_axes - 1; i >= 0; --i) + } // for (int_tp i = num_axes - 1; i >= 0; --i) } while (incremented); data_im[index] = val; } // CUDA_KERNEL_LOOP(index, n) } -template -void col2im_nd_gpu(const Dtype* data_col, const int num_spatial_axes, - const int im_size, const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, Dtype* data_im) { +template +void col2im_nd_gpu(const Dtype* data_col, const int_tp num_spatial_axes, + const int_tp im_size, const int_tp* im_shape, + const int_tp* col_shape, const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, Dtype* data_im) { // num_axes should be smaller than block size DCHECK_LT(num_spatial_axes, CAFFE_CUDA_NUM_THREADS); switch (num_spatial_axes) { case 1: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 2: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 3: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 4: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 5: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 6: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 7: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 8: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 9: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; case 10: col2im_nd_gpu_kernel // NOLINT_NEXT_LINE(whitespace/operators) - <<>>( + CUDA_KERNEL(CAFFE_GET_BLOCKS(im_size), CAFFE_CUDA_NUM_THREADS)( im_size, data_col, im_shape, col_shape, kernel_shape, pad, stride, dilation, data_im); break; @@ -499,14 +531,20 @@ void col2im_nd_gpu(const Dtype* data_col, const int num_spatial_axes, // Explicit instantiation template void col2im_nd_gpu(const float* data_col, - const int num_spatial_axes, const int im_size, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, float* data_im); + const int_tp num_spatial_axes, + const int_tp im_size, const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, float* data_im); template void col2im_nd_gpu(const double* data_col, - const int num_spatial_axes, const int im_size, - const int* im_shape, const int* col_shape, - const int* kernel_shape, const int* pad, const int* stride, - const int* dilation, double* data_im); + const int_tp num_spatial_axes, + const int_tp im_size, + const int_tp* im_shape, + const int_tp* col_shape, + const int_tp* kernel_shape, + const int_tp* pad, const int_tp* stride, + const int_tp* dilation, double* data_im); +#endif // USE_CUDA } // namespace caffe diff --git a/src/caffe/util/insert_splits.cpp b/src/caffe/util/insert_splits.cpp index 475a2a9f618..9e250021c41 100644 --- a/src/caffe/util/insert_splits.cpp +++ b/src/caffe/util/insert_splits.cpp @@ -13,44 +13,46 @@ void InsertSplits(const NetParameter& param, NetParameter* param_split) { // Initialize by copying from the input NetParameter. param_split->CopyFrom(param); param_split->clear_layer(); - map > blob_name_to_last_top_idx; - map, pair > bottom_idx_to_source_top_idx; - map, int> top_idx_to_bottom_count; - map, float> top_idx_to_loss_weight; - map, int> top_idx_to_bottom_split_idx; - map layer_idx_to_layer_name; + map > blob_name_to_last_top_idx; + map, pair > bottom_idx_to_source_top_idx; + map, int_tp> top_idx_to_bottom_count; + map, float> top_idx_to_loss_weight; + map, int_tp> top_idx_to_bottom_split_idx; + map layer_idx_to_layer_name; layer_idx_to_layer_name[-1] = "input"; // Determine the number of times each blob is used as an input (bottom) blob. - for (int i = 0; i < param.input_size(); ++i) { + for (int_tp i = 0; i < param.input_size(); ++i) { const string& blob_name = param.input(i); blob_name_to_last_top_idx[blob_name] = make_pair(-1, i); } - for (int i = 0; i < param.layer_size(); ++i) { + for (int_tp i = 0; i < param.layer_size(); ++i) { const LayerParameter& layer_param = param.layer(i); layer_idx_to_layer_name[i] = layer_param.name(); - for (int j = 0; j < layer_param.bottom_size(); ++j) { + for (int_tp j = 0; j < layer_param.bottom_size(); ++j) { const string& blob_name = layer_param.bottom(j); if (blob_name_to_last_top_idx.find(blob_name) == blob_name_to_last_top_idx.end()) { LOG(FATAL) << "Unknown bottom blob '" << blob_name << "' (layer '" << layer_param.name() << "', bottom index " << j << ")"; } - const pair& bottom_idx = make_pair(i, j); - const pair& top_idx = blob_name_to_last_top_idx[blob_name]; + const pair& bottom_idx = make_pair(i, j); + const pair& top_idx = + blob_name_to_last_top_idx[blob_name]; bottom_idx_to_source_top_idx[bottom_idx] = top_idx; ++top_idx_to_bottom_count[top_idx]; } - for (int j = 0; j < layer_param.top_size(); ++j) { + for (int_tp j = 0; j < layer_param.top_size(); ++j) { const string& blob_name = layer_param.top(j); blob_name_to_last_top_idx[blob_name] = make_pair(i, j); } // A use of a top blob as a loss should be handled similarly to the use of // a top blob as an input (bottom) blob to another layer. - const int last_loss = + const int_tp last_loss = std::min(layer_param.loss_weight_size(), layer_param.top_size()); - for (int j = 0; j < last_loss; ++j) { + for (int_tp j = 0; j < last_loss; ++j) { const string& blob_name = layer_param.top(j); - const pair& top_idx = blob_name_to_last_top_idx[blob_name]; + const pair& top_idx = + blob_name_to_last_top_idx[blob_name]; top_idx_to_loss_weight[top_idx] = layer_param.loss_weight(j); if (top_idx_to_loss_weight[top_idx]) { ++top_idx_to_bottom_count[top_idx]; @@ -59,8 +61,8 @@ void InsertSplits(const NetParameter& param, NetParameter* param_split) { } // Create split layer for any input blobs used by other layer as bottom // blobs more than once. - for (int i = 0; i < param.input_size(); ++i) { - const int split_count = top_idx_to_bottom_count[make_pair(-1, i)]; + for (int_tp i = 0; i < param.input_size(); ++i) { + const int_tp split_count = top_idx_to_bottom_count[make_pair(-1, i)]; if (split_count > 1) { const string& layer_name = layer_idx_to_layer_name[-1]; const string& blob_name = param.input(i); @@ -70,14 +72,14 @@ void InsertSplits(const NetParameter& param, NetParameter* param_split) { kZeroLossWeight, split_layer_param); } } - for (int i = 0; i < param.layer_size(); ++i) { + for (int_tp i = 0; i < param.layer_size(); ++i) { LayerParameter* layer_param = param_split->add_layer(); layer_param->CopyFrom(param.layer(i)); // Replace any shared bottom blobs with split layer outputs. - for (int j = 0; j < layer_param->bottom_size(); ++j) { - const pair& top_idx = + for (int_tp j = 0; j < layer_param->bottom_size(); ++j) { + const pair& top_idx = bottom_idx_to_source_top_idx[make_pair(i, j)]; - const int split_count = top_idx_to_bottom_count[top_idx]; + const int_tp split_count = top_idx_to_bottom_count[top_idx]; if (split_count > 1) { const string& layer_name = layer_idx_to_layer_name[top_idx.first]; const string& blob_name = layer_param->bottom(j); @@ -87,9 +89,9 @@ void InsertSplits(const NetParameter& param, NetParameter* param_split) { } // Create split layer for any top blobs used by other layer as bottom // blobs more than once. - for (int j = 0; j < layer_param->top_size(); ++j) { - const pair& top_idx = make_pair(i, j); - const int split_count = top_idx_to_bottom_count[top_idx]; + for (int_tp j = 0; j < layer_param->top_size(); ++j) { + const pair& top_idx = make_pair(i, j); + const int_tp split_count = top_idx_to_bottom_count[top_idx]; if (split_count > 1) { const string& layer_name = layer_idx_to_layer_name[i]; const string& blob_name = layer_param->top(j); @@ -107,13 +109,13 @@ void InsertSplits(const NetParameter& param, NetParameter* param_split) { } void ConfigureSplitLayer(const string& layer_name, const string& blob_name, - const int blob_idx, const int split_count, const float loss_weight, + const int_tp blob_idx, const int_tp split_count, const float loss_weight, LayerParameter* split_layer_param) { split_layer_param->Clear(); split_layer_param->add_bottom(blob_name); split_layer_param->set_name(SplitLayerName(layer_name, blob_name, blob_idx)); split_layer_param->set_type("Split"); - for (int k = 0; k < split_count; ++k) { + for (int_tp k = 0; k < split_count; ++k) { split_layer_param->add_top( SplitBlobName(layer_name, blob_name, blob_idx, k)); if (loss_weight) { @@ -127,7 +129,7 @@ void ConfigureSplitLayer(const string& layer_name, const string& blob_name, } string SplitLayerName(const string& layer_name, const string& blob_name, - const int blob_idx) { + const int_tp blob_idx) { ostringstream split_layer_name; split_layer_name << blob_name << "_" << layer_name << "_" << blob_idx << "_split"; @@ -135,7 +137,7 @@ string SplitLayerName(const string& layer_name, const string& blob_name, } string SplitBlobName(const string& layer_name, const string& blob_name, - const int blob_idx, const int split_idx) { + const int_tp blob_idx, const int_tp split_idx) { ostringstream split_blob_name; split_blob_name << blob_name << "_" << layer_name << "_" << blob_idx << "_split_" << split_idx; diff --git a/src/caffe/util/io.cpp b/src/caffe/util/io.cpp index 835d2d4e4ff..1e2f04238de 100644 --- a/src/caffe/util/io.cpp +++ b/src/caffe/util/io.cpp @@ -19,7 +19,7 @@ #include "caffe/proto/caffe.pb.h" #include "caffe/util/io.hpp" -const int kProtoReadBytesLimit = INT_MAX; // Max size of 2 GB minus 1 byte. +const int_tp kProtoReadBytesLimit = INT_MAX; // Max size of 2 GB minus 1 byte. namespace caffe { @@ -32,7 +32,7 @@ using google::protobuf::io::CodedOutputStream; using google::protobuf::Message; bool ReadProtoFromTextFile(const char* filename, Message* proto) { - int fd = open(filename, O_RDONLY); + int_tp fd = open(filename, O_RDONLY); CHECK_NE(fd, -1) << "File not found: " << filename; FileInputStream* input = new FileInputStream(fd); bool success = google::protobuf::TextFormat::Parse(input, proto); @@ -42,7 +42,7 @@ bool ReadProtoFromTextFile(const char* filename, Message* proto) { } void WriteProtoToTextFile(const Message& proto, const char* filename) { - int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + int_tp fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); FileOutputStream* output = new FileOutputStream(fd); CHECK(google::protobuf::TextFormat::Print(proto, output)); delete output; @@ -50,7 +50,7 @@ void WriteProtoToTextFile(const Message& proto, const char* filename) { } bool ReadProtoFromBinaryFile(const char* filename, Message* proto) { - int fd = open(filename, O_RDONLY); + int_tp fd = open(filename, O_RDONLY); CHECK_NE(fd, -1) << "File not found: " << filename; ZeroCopyInputStream* raw_input = new FileInputStream(fd); CodedInputStream* coded_input = new CodedInputStream(raw_input); @@ -71,9 +71,9 @@ void WriteProtoToBinaryFile(const Message& proto, const char* filename) { #ifdef USE_OPENCV cv::Mat ReadImageToCVMat(const string& filename, - const int height, const int width, const bool is_color) { + const int_tp height, const int_tp width, const bool is_color) { cv::Mat cv_img; - int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : + int_tp cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : CV_LOAD_IMAGE_GRAYSCALE); cv::Mat cv_img_origin = cv::imread(filename, cv_read_flag); if (!cv_img_origin.data) { @@ -89,7 +89,7 @@ cv::Mat ReadImageToCVMat(const string& filename, } cv::Mat ReadImageToCVMat(const string& filename, - const int height, const int width) { + const int_tp height, const int_tp width) { return ReadImageToCVMat(filename, height, width, true); } @@ -105,7 +105,7 @@ cv::Mat ReadImageToCVMat(const string& filename) { // Do the file extension and encoding match? static bool matchExt(const std::string & fn, std::string en) { - size_t p = fn.rfind('.'); + uint_tp p = fn.rfind('.'); std::string ext = p != fn.npos ? fn.substr(p) : fn; std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); std::transform(en.begin(), en.end(), en.begin(), ::tolower); @@ -116,8 +116,8 @@ static bool matchExt(const std::string & fn, return false; } -bool ReadImageToDatum(const string& filename, const int label, - const int height, const int width, const bool is_color, +bool ReadImageToDatum(const string& filename, const int_tp label, + const int_tp height, const int_tp width, const bool is_color, const std::string & encoding, Datum* datum) { cv::Mat cv_img = ReadImageToCVMat(filename, height, width, is_color); if (cv_img.data) { @@ -142,7 +142,7 @@ bool ReadImageToDatum(const string& filename, const int label, } #endif // USE_OPENCV -bool ReadFileToDatum(const string& filename, const int label, +bool ReadFileToDatum(const string& filename, const int_tp label, Datum* datum) { std::streampos size; @@ -179,7 +179,7 @@ cv::Mat DecodeDatumToCVMat(const Datum& datum, bool is_color) { CHECK(datum.encoded()) << "Datum not encoded"; const string& data = datum.data(); std::vector vec_data(data.c_str(), data.c_str() + data.size()); - int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : + int_tp cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : CV_LOAD_IMAGE_GRAYSCALE); cv_img = cv::imdecode(vec_data, cv_read_flag); if (!cv_img.data) { @@ -217,17 +217,17 @@ void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) { datum->clear_data(); datum->clear_float_data(); datum->set_encoded(false); - int datum_channels = datum->channels(); - int datum_height = datum->height(); - int datum_width = datum->width(); - int datum_size = datum_channels * datum_height * datum_width; + int_tp datum_channels = datum->channels(); + int_tp datum_height = datum->height(); + int_tp datum_width = datum->width(); + int_tp datum_size = datum_channels * datum_height * datum_width; std::string buffer(datum_size, ' '); - for (int h = 0; h < datum_height; ++h) { + for (int_tp h = 0; h < datum_height; ++h) { const uchar* ptr = cv_img.ptr(h); - int img_index = 0; - for (int w = 0; w < datum_width; ++w) { - for (int c = 0; c < datum_channels; ++c) { - int datum_index = (c * datum_height + h) * datum_width + w; + int_tp img_index = 0; + for (int_tp w = 0; w < datum_width; ++w) { + for (int_tp c = 0; c < datum_channels; ++c) { + int_tp datum_index = (c * datum_height + h) * datum_width + w; buffer[datum_index] = static_cast(ptr[img_index++]); } } diff --git a/src/caffe/util/math_functions.cpp b/src/caffe/util/math_functions.cpp index 71c02274a75..6ab7062b542 100644 --- a/src/caffe/util/math_functions.cpp +++ b/src/caffe/util/math_functions.cpp @@ -11,84 +11,112 @@ namespace caffe { template<> void caffe_cpu_gemm(const CBLAS_TRANSPOSE TransA, - const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, - const float alpha, const float* A, const float* B, const float beta, - float* C) { - int lda = (TransA == CblasNoTrans) ? K : M; - int ldb = (TransB == CblasNoTrans) ? N : K; - cblas_sgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B, - ldb, beta, C, N); + const CBLAS_TRANSPOSE TransB, const int_tp M, + const int_tp N, const int_tp K, const float alpha, + const float* A, const float* B, const float beta, + float* C) { + int_tp lda = (TransA == CblasNoTrans) ? K : M; + int_tp ldb = (TransB == CblasNoTrans) ? N : K; + cblas_sgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, + beta, C, N); } template<> void caffe_cpu_gemm(const CBLAS_TRANSPOSE TransA, - const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, - const double alpha, const double* A, const double* B, const double beta, - double* C) { - int lda = (TransA == CblasNoTrans) ? K : M; - int ldb = (TransB == CblasNoTrans) ? N : K; - cblas_dgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B, - ldb, beta, C, N); -} - -template <> -void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, - const int N, const float alpha, const float* A, const float* x, - const float beta, float* y) { + const CBLAS_TRANSPOSE TransB, const int_tp M, + const int_tp N, const int_tp K, const double alpha, + const double* A, const double* B, const double beta, + double* C) { + int_tp lda = (TransA == CblasNoTrans) ? K : M; + int_tp ldb = (TransB == CblasNoTrans) ? N : K; + cblas_dgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, + beta, C, N); +} + +template<> +void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int_tp M, + const int_tp N, const float alpha, const float* A, + const float* x, const float beta, float* y) { cblas_sgemv(CblasRowMajor, TransA, M, N, alpha, A, N, x, 1, beta, y, 1); } -template <> -void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, - const int N, const double alpha, const double* A, const double* x, - const double beta, double* y) { +template<> +void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int_tp M, + const int_tp N, const double alpha, const double* A, + const double* x, const double beta, double* y) { cblas_dgemv(CblasRowMajor, TransA, M, N, alpha, A, N, x, 1, beta, y, 1); } -template <> -void caffe_axpy(const int N, const float alpha, const float* X, - float* Y) { cblas_saxpy(N, alpha, X, 1, Y, 1); } +template<> +void caffe_axpy(const int_tp N, const float alpha, const float* X, + float* Y) { + cblas_saxpy(N, alpha, X, 1, Y, 1); +} -template <> -void caffe_axpy(const int N, const double alpha, const double* X, - double* Y) { cblas_daxpy(N, alpha, X, 1, Y, 1); } +template<> +void caffe_axpy(const int_tp N, const double alpha, const double* X, + double* Y) { + cblas_daxpy(N, alpha, X, 1, Y, 1); +} -template -void caffe_set(const int N, const Dtype alpha, Dtype* Y) { +template +void caffe_set(const int_tp N, const Dtype alpha, Dtype* Y) { if (alpha == 0) { memset(Y, 0, sizeof(Dtype) * N); // NOLINT(caffe/alt_fn) return; } - for (int i = 0; i < N; ++i) { + for (int_tp i = 0; i < N; ++i) { Y[i] = alpha; } } -template void caffe_set(const int N, const int alpha, int* Y); -template void caffe_set(const int N, const float alpha, float* Y); -template void caffe_set(const int N, const double alpha, double* Y); +template void caffe_set(const int_tp N, const int alpha, int* Y); +template void caffe_set(const int_tp N, const uint32_t alpha, + uint32_t* Y); +template void caffe_set(const int_tp N, int64_t alpha, int64_t* Y); +template void caffe_set(const int_tp N, const uint64_t alpha, + uint64_t* Y); +template void caffe_set(const int_tp N, const float alpha, float* Y); +template void caffe_set(const int_tp N, const double alpha, double* Y); -template <> -void caffe_add_scalar(const int N, const float alpha, float* Y) { - for (int i = 0; i < N; ++i) { +template<> +void caffe_add_scalar(const int_tp N, const float alpha, float* Y) { + for (int_tp i = 0; i < N; ++i) { Y[i] += alpha; } } -template <> -void caffe_add_scalar(const int N, const double alpha, double* Y) { - for (int i = 0; i < N; ++i) { +template<> +void caffe_add_scalar(const int_tp N, const double alpha, double* Y) { + for (int_tp i = 0; i < N; ++i) { Y[i] += alpha; } } -template -void caffe_copy(const int N, const Dtype* X, Dtype* Y) { +template +void caffe_cpu_copy(const int_tp N, const Dtype* X, Dtype* Y) { + if (X != Y) { + memcpy(Y, X, sizeof(Dtype) * N); // NOLINT(caffe/alt_fn) + } +} + +template void caffe_cpu_copy(const int_tp N, const int_tp* X, + int_tp* Y); +template void caffe_cpu_copy(const int_tp N, const uint_tp* X, +uint_tp* Y); +template void caffe_cpu_copy(const int_tp N, const float* X, float* Y); +template void caffe_cpu_copy(const int_tp N, const double* X, + double* Y); + +template +void caffe_copy(const int_tp N, const Dtype* X, Dtype* Y) { if (X != Y) { if (Caffe::mode() == Caffe::GPU) { #ifndef CPU_ONLY +#ifdef USE_CUDA // NOLINT_NEXT_LINE(caffe/alt_fn) CUDA_CHECK(cudaMemcpy(Y, X, sizeof(Dtype) * N, cudaMemcpyDefault)); +#endif // USE_CUDA #else NO_GPU; #endif @@ -98,142 +126,141 @@ void caffe_copy(const int N, const Dtype* X, Dtype* Y) { } } -template void caffe_copy(const int N, const int* X, int* Y); -template void caffe_copy(const int N, const unsigned int* X, - unsigned int* Y); -template void caffe_copy(const int N, const float* X, float* Y); -template void caffe_copy(const int N, const double* X, double* Y); +template void caffe_copy(const int_tp N, const int_tp* X, int_tp* Y); +template void caffe_copy(const int_tp N, const uint_tp* X, +uint_tp* Y); +template void caffe_copy(const int_tp N, const float* X, float* Y); +template void caffe_copy(const int_tp N, const double* X, double* Y); -template <> -void caffe_scal(const int N, const float alpha, float *X) { +template<> +void caffe_scal(const int_tp N, const float alpha, float *X) { cblas_sscal(N, alpha, X, 1); } -template <> -void caffe_scal(const int N, const double alpha, double *X) { +template<> +void caffe_scal(const int_tp N, const double alpha, double *X) { cblas_dscal(N, alpha, X, 1); } -template <> -void caffe_cpu_axpby(const int N, const float alpha, const float* X, +template<> +void caffe_cpu_axpby(const int_tp N, const float alpha, const float* X, const float beta, float* Y) { cblas_saxpby(N, alpha, X, 1, beta, Y, 1); } -template <> -void caffe_cpu_axpby(const int N, const double alpha, const double* X, - const double beta, double* Y) { +template<> +void caffe_cpu_axpby(const int_tp N, const double alpha, + const double* X, const double beta, double* Y) { cblas_daxpby(N, alpha, X, 1, beta, Y, 1); } -template <> -void caffe_add(const int n, const float* a, const float* b, - float* y) { +template<> +void caffe_add(const int_tp n, const float* a, const float* b, + float* y) { vsAdd(n, a, b, y); } -template <> -void caffe_add(const int n, const double* a, const double* b, - double* y) { +template<> +void caffe_add(const int_tp n, const double* a, const double* b, + double* y) { vdAdd(n, a, b, y); } -template <> -void caffe_sub(const int n, const float* a, const float* b, - float* y) { +template<> +void caffe_sub(const int_tp n, const float* a, const float* b, + float* y) { vsSub(n, a, b, y); } -template <> -void caffe_sub(const int n, const double* a, const double* b, - double* y) { +template<> +void caffe_sub(const int_tp n, const double* a, const double* b, + double* y) { vdSub(n, a, b, y); } -template <> -void caffe_mul(const int n, const float* a, const float* b, - float* y) { +template<> +void caffe_mul(const int_tp n, const float* a, const float* b, + float* y) { vsMul(n, a, b, y); } -template <> -void caffe_mul(const int n, const double* a, const double* b, - double* y) { +template<> +void caffe_mul(const int_tp n, const double* a, const double* b, + double* y) { vdMul(n, a, b, y); } -template <> -void caffe_div(const int n, const float* a, const float* b, - float* y) { +template<> +void caffe_div(const int_tp n, const float* a, const float* b, + float* y) { vsDiv(n, a, b, y); } -template <> -void caffe_div(const int n, const double* a, const double* b, - double* y) { +template<> +void caffe_div(const int_tp n, const double* a, const double* b, + double* y) { vdDiv(n, a, b, y); } -template <> -void caffe_powx(const int n, const float* a, const float b, - float* y) { +template<> +void caffe_powx(const int_tp n, const float* a, const float b, + float* y) { vsPowx(n, a, b, y); } -template <> -void caffe_powx(const int n, const double* a, const double b, - double* y) { +template<> +void caffe_powx(const int_tp n, const double* a, const double b, + double* y) { vdPowx(n, a, b, y); } -template <> -void caffe_sqr(const int n, const float* a, float* y) { +template<> +void caffe_sqr(const int_tp n, const float* a, float* y) { vsSqr(n, a, y); } -template <> -void caffe_sqr(const int n, const double* a, double* y) { +template<> +void caffe_sqr(const int_tp n, const double* a, double* y) { vdSqr(n, a, y); } -template <> -void caffe_exp(const int n, const float* a, float* y) { +template<> +void caffe_exp(const int_tp n, const float* a, float* y) { vsExp(n, a, y); } -template <> -void caffe_exp(const int n, const double* a, double* y) { +template<> +void caffe_exp(const int_tp n, const double* a, double* y) { vdExp(n, a, y); } -template <> -void caffe_log(const int n, const float* a, float* y) { +template<> +void caffe_log(const int_tp n, const float* a, float* y) { vsLn(n, a, y); } -template <> -void caffe_log(const int n, const double* a, double* y) { +template<> +void caffe_log(const int_tp n, const double* a, double* y) { vdLn(n, a, y); } -template <> -void caffe_abs(const int n, const float* a, float* y) { - vsAbs(n, a, y); +template<> +void caffe_abs(const int_tp n, const float* a, float* y) { + vsAbs(n, a, y); } -template <> -void caffe_abs(const int n, const double* a, double* y) { - vdAbs(n, a, y); +template<> +void caffe_abs(const int_tp n, const double* a, double* y) { + vdAbs(n, a, y); } -unsigned int caffe_rng_rand() { +uint_tp caffe_rng_rand() { return (*caffe_rng())(); } -template +template Dtype caffe_nextafter(const Dtype b) { - return boost::math::nextafter( - b, std::numeric_limits::max()); + return boost::math::nextafter(b, std::numeric_limits::max()); } template @@ -242,132 +269,152 @@ float caffe_nextafter(const float b); template double caffe_nextafter(const double b); -template -void caffe_rng_uniform(const int n, const Dtype a, const Dtype b, Dtype* r) { +void caffe_rng_uniform(const int_tp n, uint_tp* r) { + CHECK_GE(n, 0); + CHECK(r); + boost::uniform_int random_distribution( + std::numeric_limits::min(), std::numeric_limits::max()); + boost::variate_generator> variate_generator( + caffe_rng(), random_distribution); + for (int_tp i = 0; i < n; ++i) { + r[i] = variate_generator(); + } +} + +template +void caffe_rng_uniform(const int_tp n, const Dtype a, const Dtype b, Dtype* r) { CHECK_GE(n, 0); CHECK(r); CHECK_LE(a, b); boost::uniform_real random_distribution(a, caffe_nextafter(b)); - boost::variate_generator > - variate_generator(caffe_rng(), random_distribution); - for (int i = 0; i < n; ++i) { + boost::variate_generator> variate_generator( + caffe_rng(), random_distribution); + for (int_tp i = 0; i < n; ++i) { r[i] = variate_generator(); } } template -void caffe_rng_uniform(const int n, const float a, const float b, +void caffe_rng_uniform(const int_tp n, const float a, const float b, float* r); template -void caffe_rng_uniform(const int n, const double a, const double b, +void caffe_rng_uniform(const int_tp n, const double a, const double b, double* r); -template -void caffe_rng_gaussian(const int n, const Dtype a, - const Dtype sigma, Dtype* r) { +template +void caffe_rng_gaussian(const int_tp n, const Dtype a, const Dtype sigma, + Dtype* r) { CHECK_GE(n, 0); CHECK(r); CHECK_GT(sigma, 0); boost::normal_distribution random_distribution(a, sigma); - boost::variate_generator > - variate_generator(caffe_rng(), random_distribution); - for (int i = 0; i < n; ++i) { + boost::variate_generator> variate_generator( + caffe_rng(), random_distribution); + for (int_tp i = 0; i < n; ++i) { r[i] = variate_generator(); } } template -void caffe_rng_gaussian(const int n, const float mu, +void caffe_rng_gaussian(const int_tp n, const float mu, const float sigma, float* r); template -void caffe_rng_gaussian(const int n, const double mu, +void caffe_rng_gaussian(const int_tp n, const double mu, const double sigma, double* r); -template -void caffe_rng_bernoulli(const int n, const Dtype p, int* r) { +template +void caffe_rng_bernoulli(const int_tp n, const Dtype p, Itype* r) { CHECK_GE(n, 0); CHECK(r); CHECK_GE(p, 0); CHECK_LE(p, 1); boost::bernoulli_distribution random_distribution(p); - boost::variate_generator > - variate_generator(caffe_rng(), random_distribution); - for (int i = 0; i < n; ++i) { - r[i] = variate_generator(); + boost::variate_generator> variate_generator( + caffe_rng(), random_distribution); + for (int_tp i = 0; i < n; ++i) { + r[i] = static_cast(variate_generator()); } } template -void caffe_rng_bernoulli(const int n, const double p, int* r); +void caffe_rng_bernoulli(const int_tp n, const double p, // NOLINT + unsigned long* r); // NOLINT template -void caffe_rng_bernoulli(const int n, const float p, int* r); +void caffe_rng_bernoulli(const int_tp n, const float p, // NOLINT + unsigned long* r); // NOLINT -template -void caffe_rng_bernoulli(const int n, const Dtype p, unsigned int* r) { - CHECK_GE(n, 0); - CHECK(r); - CHECK_GE(p, 0); - CHECK_LE(p, 1); - boost::bernoulli_distribution random_distribution(p); - boost::variate_generator > - variate_generator(caffe_rng(), random_distribution); - for (int i = 0; i < n; ++i) { - r[i] = static_cast(variate_generator()); - } -} +template +void caffe_rng_bernoulli(const int_tp n, const double p, long* r); // NOLINT + +template +void caffe_rng_bernoulli(const int_tp n, const float p, long* r); // NOLINT + +template +void caffe_rng_bernoulli(const int_tp n, const double p, + unsigned int* r); template -void caffe_rng_bernoulli(const int n, const double p, unsigned int* r); +void caffe_rng_bernoulli(const int_tp n, const float p, + unsigned int* r); template -void caffe_rng_bernoulli(const int n, const float p, unsigned int* r); +void caffe_rng_bernoulli(const int_tp n, const double p, int* r); -template <> -float caffe_cpu_strided_dot(const int n, const float* x, const int incx, - const float* y, const int incy) { +template +void caffe_rng_bernoulli(const int_tp n, const float p, int* r); + +template<> +float caffe_cpu_strided_dot(const int_tp n, const float* x, + const int_tp incx, const float* y, + const int_tp incy) { return cblas_sdot(n, x, incx, y, incy); } -template <> -double caffe_cpu_strided_dot(const int n, const double* x, - const int incx, const double* y, const int incy) { +template<> +double caffe_cpu_strided_dot(const int_tp n, const double* x, + const int_tp incx, const double* y, + const int_tp incy) { return cblas_ddot(n, x, incx, y, incy); } -template -Dtype caffe_cpu_dot(const int n, const Dtype* x, const Dtype* y) { +template +Dtype caffe_cpu_dot(const int_tp n, const Dtype* x, const Dtype* y) { return caffe_cpu_strided_dot(n, x, 1, y, 1); } template -float caffe_cpu_dot(const int n, const float* x, const float* y); +float caffe_cpu_dot(const int_tp n, const float* x, const float* y); template -double caffe_cpu_dot(const int n, const double* x, const double* y); +double caffe_cpu_dot(const int_tp n, const double* x, const double* y); -template <> -float caffe_cpu_asum(const int n, const float* x) { +template<> +float caffe_cpu_asum(const int_tp n, const float* x) { return cblas_sasum(n, x, 1); } -template <> -double caffe_cpu_asum(const int n, const double* x) { +template<> +double caffe_cpu_asum(const int_tp n, const double* x) { return cblas_dasum(n, x, 1); } -template <> -void caffe_cpu_scale(const int n, const float alpha, const float *x, +template<> +void caffe_cpu_scale(const int_tp n, const float alpha, const float *x, float* y) { cblas_scopy(n, x, 1, y, 1); cblas_sscal(n, alpha, y, 1); } -template <> -void caffe_cpu_scale(const int n, const double alpha, const double *x, - double* y) { +template<> +void caffe_cpu_scale(const int_tp n, const double alpha, + const double *x, double* y) { cblas_dcopy(n, x, 1, y, 1); cblas_dscal(n, alpha, y, 1); } diff --git a/src/caffe/util/math_functions.cu b/src/caffe/util/math_functions.cu index 4c587537435..c8031cedace 100644 --- a/src/caffe/util/math_functions.cu +++ b/src/caffe/util/math_functions.cu @@ -1,382 +1,397 @@ -#include // CUDA's, not caffe's, for fabs, signbit -#include -#include // thrust::plus -#include - #include +#include +#include +#include #include "caffe/common.hpp" #include "caffe/util/math_functions.hpp" +#ifdef USE_CUDA + +#include // CUDA's, not caffe's, for fabs, signbit +#include +#include // thrust::plus +#include + namespace caffe { -template <> +template<> void caffe_gpu_gemm(const CBLAS_TRANSPOSE TransA, - const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, - const float alpha, const float* A, const float* B, const float beta, - float* C) { + const CBLAS_TRANSPOSE TransB, const int_tp M, + const int_tp N, const int_tp K, const float alpha, + const float* A, const float* B, const float beta, + float* C) { // Note that cublas follows fortran order. - int lda = (TransA == CblasNoTrans) ? K : M; - int ldb = (TransB == CblasNoTrans) ? N : K; + int_tp lda = (TransA == CblasNoTrans) ? K : M; + int_tp ldb = (TransB == CblasNoTrans) ? N : K; cublasOperation_t cuTransA = (TransA == CblasNoTrans) ? CUBLAS_OP_N : CUBLAS_OP_T; cublasOperation_t cuTransB = (TransB == CblasNoTrans) ? CUBLAS_OP_N : CUBLAS_OP_T; CUBLAS_CHECK(cublasSgemm(Caffe::cublas_handle(), cuTransB, cuTransA, - N, M, K, &alpha, B, ldb, A, lda, &beta, C, N)); + N, M, K, &alpha, B, ldb, A, lda, &beta, C, N)); } -template <> +template<> void caffe_gpu_gemm(const CBLAS_TRANSPOSE TransA, - const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, - const double alpha, const double* A, const double* B, const double beta, - double* C) { + const CBLAS_TRANSPOSE TransB, const int_tp M, + const int_tp N, const int_tp K, const double alpha, + const double* A, const double* B, const double beta, + double* C) { // Note that cublas follows fortran order. - int lda = (TransA == CblasNoTrans) ? K : M; - int ldb = (TransB == CblasNoTrans) ? N : K; + int_tp lda = (TransA == CblasNoTrans) ? K : M; + int_tp ldb = (TransB == CblasNoTrans) ? N : K; cublasOperation_t cuTransA = (TransA == CblasNoTrans) ? CUBLAS_OP_N : CUBLAS_OP_T; cublasOperation_t cuTransB = (TransB == CblasNoTrans) ? CUBLAS_OP_N : CUBLAS_OP_T; CUBLAS_CHECK(cublasDgemm(Caffe::cublas_handle(), cuTransB, cuTransA, - N, M, K, &alpha, B, ldb, A, lda, &beta, C, N)); + N, M, K, &alpha, B, ldb, A, lda, &beta, C, N)); } -template <> -void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, - const int N, const float alpha, const float* A, const float* x, - const float beta, float* y) { +template<> +void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int_tp M, + const int_tp N, const float alpha, const float* A, + const float* x, const float beta, float* y) { cublasOperation_t cuTransA = (TransA == CblasNoTrans) ? CUBLAS_OP_T : CUBLAS_OP_N; - CUBLAS_CHECK(cublasSgemv(Caffe::cublas_handle(), cuTransA, N, M, &alpha, - A, N, x, 1, &beta, y, 1)); + CUBLAS_CHECK(cublasSgemv(Caffe::cublas_handle(), cuTransA, + N, M, &alpha, A, N, x, 1, &beta, y, 1)); } -template <> -void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, - const int N, const double alpha, const double* A, const double* x, - const double beta, double* y) { +template<> +void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int_tp M, + const int_tp N, const double alpha, const double* A, + const double* x, const double beta, double* y) { cublasOperation_t cuTransA = (TransA == CblasNoTrans) ? CUBLAS_OP_T : CUBLAS_OP_N; - CUBLAS_CHECK(cublasDgemv(Caffe::cublas_handle(), cuTransA, N, M, &alpha, - A, N, x, 1, &beta, y, 1)); + CUBLAS_CHECK(cublasDgemv(Caffe::cublas_handle(), cuTransA, N, M, + &alpha, A, N, x, 1, &beta, y, 1)); } -template <> -void caffe_gpu_axpy(const int N, const float alpha, const float* X, - float* Y) { +template<> +void caffe_gpu_axpy(const int_tp N, const float alpha, const float* X, + float* Y) { CUBLAS_CHECK(cublasSaxpy(Caffe::cublas_handle(), N, &alpha, X, 1, Y, 1)); } -template <> -void caffe_gpu_axpy(const int N, const double alpha, const double* X, - double* Y) { +template<> +void caffe_gpu_axpy(const int_tp N, const double alpha, const double* X, + double* Y) { CUBLAS_CHECK(cublasDaxpy(Caffe::cublas_handle(), N, &alpha, X, 1, Y, 1)); } -void caffe_gpu_memcpy(const size_t N, const void* X, void* Y) { +void caffe_gpu_memcpy(const uint_tp N, const void* X, void* Y) { if (X != Y) { CUDA_CHECK(cudaMemcpy(Y, X, N, cudaMemcpyDefault)); // NOLINT(caffe/alt_fn) } } -template <> -void caffe_gpu_scal(const int N, const float alpha, float *X) { +template<> +void caffe_gpu_scal(const int_tp N, const float alpha, float *X) { CUBLAS_CHECK(cublasSscal(Caffe::cublas_handle(), N, &alpha, X, 1)); } -template <> -void caffe_gpu_scal(const int N, const double alpha, double *X) { +template<> +void caffe_gpu_scal(const int_tp N, const double alpha, double *X) { CUBLAS_CHECK(cublasDscal(Caffe::cublas_handle(), N, &alpha, X, 1)); } -template <> -void caffe_gpu_axpby(const int N, const float alpha, const float* X, - const float beta, float* Y) { +template<> +void caffe_gpu_axpby(const int_tp N, const float alpha, const float* X, + const float beta, float* Y) { caffe_gpu_scal(N, beta, Y); caffe_gpu_axpy(N, alpha, X, Y); } -template <> -void caffe_gpu_axpby(const int N, const double alpha, const double* X, - const double beta, double* Y) { +template<> +void caffe_gpu_axpby(const int_tp N, const double alpha, + const double* X, const double beta, double* Y) { caffe_gpu_scal(N, beta, Y); caffe_gpu_axpy(N, alpha, X, Y); } -template <> -void caffe_gpu_dot(const int n, const float* x, const float* y, - float* out) { +template<> +void caffe_gpu_dot(const int_tp n, const float* x, const float* y, + float* out) { CUBLAS_CHECK(cublasSdot(Caffe::cublas_handle(), n, x, 1, y, 1, out)); } -template <> -void caffe_gpu_dot(const int n, const double* x, const double* y, - double * out) { +template<> +void caffe_gpu_dot(const int_tp n, const double* x, const double* y, + double * out) { CUBLAS_CHECK(cublasDdot(Caffe::cublas_handle(), n, x, 1, y, 1, out)); } -template <> -void caffe_gpu_asum(const int n, const float* x, float* y) { +template<> +void caffe_gpu_asum(const int_tp n, const float* x, float* y) { CUBLAS_CHECK(cublasSasum(Caffe::cublas_handle(), n, x, 1, y)); } -template <> -void caffe_gpu_asum(const int n, const double* x, double* y) { +template<> +void caffe_gpu_asum(const int_tp n, const double* x, double* y) { CUBLAS_CHECK(cublasDasum(Caffe::cublas_handle(), n, x, 1, y)); } -template <> -void caffe_gpu_scale(const int n, const float alpha, const float *x, +template<> +void caffe_gpu_scale(const int_tp n, const float alpha, const float *x, float* y) { CUBLAS_CHECK(cublasScopy(Caffe::cublas_handle(), n, x, 1, y, 1)); CUBLAS_CHECK(cublasSscal(Caffe::cublas_handle(), n, &alpha, y, 1)); } -template <> -void caffe_gpu_scale(const int n, const double alpha, const double *x, - double* y) { +template<> +void caffe_gpu_scale(const int_tp n, const double alpha, + const double *x, double* y) { CUBLAS_CHECK(cublasDcopy(Caffe::cublas_handle(), n, x, 1, y, 1)); CUBLAS_CHECK(cublasDscal(Caffe::cublas_handle(), n, &alpha, y, 1)); } -template -__global__ void set_kernel(const int n, const Dtype alpha, Dtype* y) { +template +__global__ void set_kernel(const int_tp n, const Dtype alpha, Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = alpha; } } -template -void caffe_gpu_set(const int N, const Dtype alpha, Dtype* Y) { +template +void caffe_gpu_set(const int_tp N, const Dtype alpha, Dtype* Y) { if (alpha == 0) { CUDA_CHECK(cudaMemset(Y, 0, sizeof(Dtype) * N)); // NOLINT(caffe/alt_fn) return; } // NOLINT_NEXT_LINE(whitespace/operators) - set_kernel<<>>( + set_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, alpha, Y); } -template void caffe_gpu_set(const int N, const int alpha, int* Y); -template void caffe_gpu_set(const int N, const float alpha, float* Y); -template void caffe_gpu_set(const int N, const double alpha, double* Y); +template void caffe_gpu_set(const int_tp N, const int_tp alpha, + int_tp* Y); +template void caffe_gpu_set(const int_tp N, const float alpha, float* Y); +template void caffe_gpu_set(const int_tp N, const double alpha, + double* Y); -template -__global__ void add_scalar_kernel(const int n, const Dtype alpha, Dtype* y) { +template +__global__ void add_scalar_kernel(const int_tp n, const Dtype alpha, Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] += alpha; } } -template <> -void caffe_gpu_add_scalar(const int N, const float alpha, float* Y) { +template<> +void caffe_gpu_add_scalar(const int_tp N, const float alpha, float* Y) { // NOLINT_NEXT_LINE(whitespace/operators) - add_scalar_kernel<<>>( + add_scalar_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), + CAFFE_CUDA_NUM_THREADS)( N, alpha, Y); } -template <> -void caffe_gpu_add_scalar(const int N, const double alpha, double* Y) { +template<> +void caffe_gpu_add_scalar(const int_tp N, const double alpha, double* Y) { // NOLINT_NEXT_LINE(whitespace/operators) - add_scalar_kernel<<>>( + add_scalar_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), + CAFFE_CUDA_NUM_THREADS)( N, alpha, Y); } -template -__global__ void add_kernel(const int n, const Dtype* a, - const Dtype* b, Dtype* y) { +template +__global__ void add_kernel(const int_tp n, const Dtype* a, const Dtype* b, + Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = a[index] + b[index]; } } -template <> -void caffe_gpu_add(const int N, const float* a, const float* b, - float* y) { +template<> +void caffe_gpu_add(const int_tp N, const float* a, const float* b, + float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - add_kernel<<>>( + add_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template <> -void caffe_gpu_add(const int N, const double* a, const double* b, - double* y) { +template<> +void caffe_gpu_add(const int_tp N, const double* a, const double* b, + double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - add_kernel<<>>( + add_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template -__global__ void sub_kernel(const int n, const Dtype* a, - const Dtype* b, Dtype* y) { +template +__global__ void sub_kernel(const int_tp n, const Dtype* a, const Dtype* b, + Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = a[index] - b[index]; } } -template <> -void caffe_gpu_sub(const int N, const float* a, const float* b, - float* y) { +template<> +void caffe_gpu_sub(const int_tp N, const float* a, const float* b, + float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - sub_kernel<<>>( + sub_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template <> -void caffe_gpu_sub(const int N, const double* a, const double* b, - double* y) { +template<> +void caffe_gpu_sub(const int_tp N, const double* a, const double* b, + double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - sub_kernel<<>>( + sub_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template -__global__ void mul_kernel(const int n, const Dtype* a, - const Dtype* b, Dtype* y) { +template +__global__ void mul_kernel(const int_tp n, const Dtype* a, const Dtype* b, + Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = a[index] * b[index]; } } -template <> -void caffe_gpu_mul(const int N, const float* a, - const float* b, float* y) { +template<> +void caffe_gpu_mul(const int_tp N, const float* a, const float* b, + float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - mul_kernel<<>>( + mul_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template <> -void caffe_gpu_mul(const int N, const double* a, - const double* b, double* y) { +template<> +void caffe_gpu_mul(const int_tp N, const double* a, const double* b, + double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - mul_kernel<<>>( + mul_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template -__global__ void div_kernel(const int n, const Dtype* a, - const Dtype* b, Dtype* y) { +template +__global__ void div_kernel(const int_tp n, const Dtype* a, const Dtype* b, + Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = a[index] / b[index]; } } -template <> -void caffe_gpu_div(const int N, const float* a, - const float* b, float* y) { +template<> +void caffe_gpu_div(const int_tp N, const float* a, const float* b, + float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - div_kernel<<>>( + div_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template <> -void caffe_gpu_div(const int N, const double* a, - const double* b, double* y) { +template<> +void caffe_gpu_div(const int_tp N, const double* a, const double* b, + double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - div_kernel<<>>( + div_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, b, y); } -template -__global__ void abs_kernel(const int n, const Dtype* a, Dtype* y) { +template +__global__ void abs_kernel(const int_tp n, const Dtype* a, Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = abs(a[index]); } } -template <> -void caffe_gpu_abs(const int N, const float* a, float* y) { +template<> +void caffe_gpu_abs(const int_tp N, const float* a, float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - abs_kernel<<>>( + abs_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, y); } -template <> -void caffe_gpu_abs(const int N, const double* a, double* y) { +template<> +void caffe_gpu_abs(const int_tp N, const double* a, double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - abs_kernel<<>>( + abs_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, y); } - -template -__global__ void exp_kernel(const int n, const Dtype* a, Dtype* y) { +template +__global__ void exp_kernel(const int_tp n, const Dtype* a, Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = exp(a[index]); } } -template <> -void caffe_gpu_exp(const int N, const float* a, float* y) { +template<> +void caffe_gpu_exp(const int_tp N, const float* a, float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - exp_kernel<<>>( + exp_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, y); } -template <> -void caffe_gpu_exp(const int N, const double* a, double* y) { +template<> +void caffe_gpu_exp(const int_tp N, const double* a, double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - exp_kernel<<>>( + exp_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, y); } -template -__global__ void log_kernel(const int n, const Dtype* a, Dtype* y) { +template +__global__ void log_kernel(const int_tp n, const Dtype* a, Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = log(a[index]); } } -template <> -void caffe_gpu_log(const int N, const float* a, float* y) { +template<> +void caffe_gpu_log(const int_tp N, const float* a, float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - log_kernel<<>>( + log_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, y); } -template <> -void caffe_gpu_log(const int N, const double* a, double* y) { +template<> +void caffe_gpu_log(const int_tp N, const double* a, double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - log_kernel<<>>( + log_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, y); } -template -__global__ void powx_kernel(const int n, const Dtype* a, - const Dtype alpha, Dtype* y) { +template +__global__ void powx_kernel(const int_tp n, const Dtype* a, const Dtype alpha, + Dtype* y) { CUDA_KERNEL_LOOP(index, n) { y[index] = pow(a[index], alpha); } } -template <> -void caffe_gpu_powx(const int N, const float* a, - const float alpha, float* y) { +template<> +void caffe_gpu_powx(const int_tp N, const float* a, const float alpha, + float* y) { // NOLINT_NEXT_LINE(whitespace/operators) - powx_kernel<<>>( + powx_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, alpha, y); } -template <> -void caffe_gpu_powx(const int N, const double* a, - const double alpha, double* y) { +template<> +void caffe_gpu_powx(const int_tp N, const double* a, const double alpha, + double* y) { // NOLINT_NEXT_LINE(whitespace/operators) - powx_kernel<<>>( + powx_kernel CUDA_KERNEL(CAFFE_GET_BLOCKS(N), CAFFE_CUDA_NUM_THREADS)( N, a, alpha, y); } -DEFINE_AND_INSTANTIATE_GPU_UNARY_FUNC(sign, y[index] = (Dtype(0) < x[index]) - - (x[index] < Dtype(0))); +DEFINE_AND_INSTANTIATE_GPU_UNARY_FUNC( + sign, y[index] = (Dtype(0) < x[index]) - (x[index] < Dtype(0))); DEFINE_AND_INSTANTIATE_GPU_UNARY_FUNC(sgnbit, y[index] = signbit(x[index])); -void caffe_gpu_rng_uniform(const int n, unsigned int* r) { + +void caffe_gpu_rng_uniform(const int_tp n, unsigned int* r) { // NOLINT CURAND_CHECK(curandGenerate(Caffe::curand_generator(), r, n)); } -template <> -void caffe_gpu_rng_uniform(const int n, const float a, const float b, +void caffe_gpu_rng_uniform(const int_tp n, unsigned long long* r) { // NOLINT + CURAND_CHECK(curandGenerateLongLong(Caffe::curand_generator64(), r, n)); +} + +template<> +void caffe_gpu_rng_uniform(const int_tp n, const float a, const float b, float* r) { CURAND_CHECK(curandGenerateUniform(Caffe::curand_generator(), r, n)); const float range = b - a; @@ -388,9 +403,9 @@ void caffe_gpu_rng_uniform(const int n, const float a, const float b, } } -template <> -void caffe_gpu_rng_uniform(const int n, const double a, const double b, - double* r) { +template<> +void caffe_gpu_rng_uniform(const int_tp n, const double a, + const double b, double* r) { CURAND_CHECK(curandGenerateUniformDouble(Caffe::curand_generator(), r, n)); const double range = b - a; if (range != static_cast(1)) { @@ -401,18 +416,19 @@ void caffe_gpu_rng_uniform(const int n, const double a, const double b, } } -template <> -void caffe_gpu_rng_gaussian(const int n, const float mu, const float sigma, +template<> +void caffe_gpu_rng_gaussian(const int_tp n, const float mu, const float sigma, float* r) { CURAND_CHECK( curandGenerateNormal(Caffe::curand_generator(), r, n, mu, sigma)); } -template <> -void caffe_gpu_rng_gaussian(const int n, const double mu, const double sigma, +template<> +void caffe_gpu_rng_gaussian(const int_tp n, const double mu, const double sigma, double* r) { CURAND_CHECK( curandGenerateNormalDouble(Caffe::curand_generator(), r, n, mu, sigma)); } } // namespace caffe +#endif // USE_CUDA diff --git a/src/caffe/util/upgrade_proto.cpp b/src/caffe/util/upgrade_proto.cpp index ff3f8ffc4f0..c108e295d32 100644 --- a/src/caffe/util/upgrade_proto.cpp +++ b/src/caffe/util/upgrade_proto.cpp @@ -21,43 +21,43 @@ bool UpgradeNetAsNeeded(const string& param_file, NetParameter* param) { if (NetNeedsV0ToV1Upgrade(*param)) { // NetParameter was specified using the old style (V0LayerParameter); try to // upgrade it. - LOG(INFO) << "Attempting to upgrade input file specified using deprecated " - << "V0LayerParameter: " << param_file; + LOG(INFO)<< "Attempting to upgrade input file specified using deprecated " + << "V0LayerParameter: " << param_file; NetParameter original_param(*param); if (!UpgradeV0Net(original_param, param)) { success = false; LOG(ERROR) << "Warning: had one or more problems upgrading " - << "V0NetParameter to NetParameter (see above); continuing anyway."; + << "V0NetParameter to NetParameter (see above); continuing anyway."; } else { LOG(INFO) << "Successfully upgraded file specified using deprecated " - << "V0LayerParameter"; + << "V0LayerParameter"; } LOG(WARNING) << "Note that future Caffe releases will not support " - << "V0NetParameter; use ./build/tools/upgrade_net_proto_text for " - << "prototxt and ./build/tools/upgrade_net_proto_binary for model " - << "weights upgrade this and any other net protos to the new format."; + << "V0NetParameter; use ./build/tools/upgrade_net_proto_text for " + << "prototxt and ./build/tools/upgrade_net_proto_binary for model " + << "weights upgrade this and any other net protos to the new format."; } // NetParameter uses old style data transformation fields; try to upgrade it. if (NetNeedsDataUpgrade(*param)) { - LOG(INFO) << "Attempting to upgrade input file specified using deprecated " - << "transformation parameters: " << param_file; + LOG(INFO)<< "Attempting to upgrade input file specified using deprecated " + << "transformation parameters: " << param_file; UpgradeNetDataTransformation(param); LOG(INFO) << "Successfully upgraded file specified using deprecated " - << "data transformation parameters."; + << "data transformation parameters."; LOG(WARNING) << "Note that future Caffe releases will only support " - << "transform_param messages for transformation fields."; + << "transform_param messages for transformation fields."; } if (NetNeedsV1ToV2Upgrade(*param)) { - LOG(INFO) << "Attempting to upgrade input file specified using deprecated " - << "V1LayerParameter: " << param_file; + LOG(INFO)<< "Attempting to upgrade input file specified using deprecated " + << "V1LayerParameter: " << param_file; NetParameter original_param(*param); if (!UpgradeV1Net(original_param, param)) { success = false; LOG(ERROR) << "Warning: had one or more problems upgrading " - << "V1LayerParameter (see above); continuing anyway."; + << "V1LayerParameter (see above); continuing anyway."; } else { LOG(INFO) << "Successfully upgraded file specified using deprecated " - << "V1LayerParameter"; + << "V1LayerParameter"; } } return success; @@ -138,9 +138,9 @@ void UpgradeV0PaddingLayers(const NetParameter& param, } for (int j = 0; j < layer_connection.bottom_size(); ++j) { const string& blob_name = layer_connection.bottom(j); - if (blob_name_to_last_top_idx.find(blob_name) == - blob_name_to_last_top_idx.end()) { - LOG(FATAL) << "Unknown blob input " << blob_name << " to layer " << j; + if (blob_name_to_last_top_idx.find(blob_name) + == blob_name_to_last_top_idx.end()) { + LOG(FATAL)<< "Unknown blob input " << blob_name << " to layer " << j; } const int top_idx = blob_name_to_last_top_idx[blob_name]; if (top_idx == -1) { @@ -157,16 +157,16 @@ void UpgradeV0PaddingLayers(const NetParameter& param, "non-convolutional / non-pooling layer type " << layer_param.type(); CHECK_EQ(layer_connection.bottom_size(), 1) - << "Conv Layer takes a single blob as input."; + << "Conv Layer takes a single blob as input."; CHECK_EQ(source_layer.bottom_size(), 1) - << "Padding Layer takes a single blob as input."; + << "Padding Layer takes a single blob as input."; CHECK_EQ(source_layer.top_size(), 1) - << "Padding Layer produces a single blob as output."; + << "Padding Layer produces a single blob as output."; int layer_index = param_upgraded_pad->layers_size() - 1; param_upgraded_pad->mutable_layers(layer_index)->mutable_layer() ->set_pad(source_layer.layer().pad()); - param_upgraded_pad->mutable_layers(layer_index) - ->set_bottom(j, source_layer.bottom(0)); + param_upgraded_pad->mutable_layers(layer_index)->set_bottom( + j, source_layer.bottom(0)); } } for (int j = 0; j < layer_connection.top_size(); ++j) { @@ -212,7 +212,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_inner_product_param()->set_num_output( v0_layer_param.num_output()); } else { - LOG(ERROR) << "Unknown parameter num_output for layer type " << type; + LOG(ERROR)<< "Unknown parameter num_output for layer type " << type; is_fully_compatible = false; } } @@ -224,31 +224,31 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_inner_product_param()->set_bias_term( v0_layer_param.biasterm()); } else { - LOG(ERROR) << "Unknown parameter biasterm for layer type " << type; + LOG(ERROR)<< "Unknown parameter biasterm for layer type " << type; is_fully_compatible = false; } } if (v0_layer_param.has_weight_filler()) { if (type == "conv") { - layer_param->mutable_convolution_param()-> - mutable_weight_filler()->CopyFrom(v0_layer_param.weight_filler()); + layer_param->mutable_convolution_param()->mutable_weight_filler() + ->CopyFrom(v0_layer_param.weight_filler()); } else if (type == "innerproduct") { - layer_param->mutable_inner_product_param()-> - mutable_weight_filler()->CopyFrom(v0_layer_param.weight_filler()); + layer_param->mutable_inner_product_param()->mutable_weight_filler() + ->CopyFrom(v0_layer_param.weight_filler()); } else { - LOG(ERROR) << "Unknown parameter weight_filler for layer type " << type; + LOG(ERROR)<< "Unknown parameter weight_filler for layer type " << type; is_fully_compatible = false; } } if (v0_layer_param.has_bias_filler()) { if (type == "conv") { - layer_param->mutable_convolution_param()-> - mutable_bias_filler()->CopyFrom(v0_layer_param.bias_filler()); + layer_param->mutable_convolution_param()->mutable_bias_filler() + ->CopyFrom(v0_layer_param.bias_filler()); } else if (type == "innerproduct") { - layer_param->mutable_inner_product_param()-> - mutable_bias_filler()->CopyFrom(v0_layer_param.bias_filler()); + layer_param->mutable_inner_product_param()->mutable_bias_filler() + ->CopyFrom(v0_layer_param.bias_filler()); } else { - LOG(ERROR) << "Unknown parameter bias_filler for layer type " << type; + LOG(ERROR)<< "Unknown parameter bias_filler for layer type " << type; is_fully_compatible = false; } } @@ -256,9 +256,9 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, if (type == "conv") { layer_param->mutable_convolution_param()->add_pad(v0_layer_param.pad()); } else if (type == "pool") { - layer_param->mutable_pooling_param()->set_pad(v0_layer_param.pad()); + layer_param->mutable_pooling_param()->add_pad(v0_layer_param.pad()); } else { - LOG(ERROR) << "Unknown parameter pad for layer type " << type; + LOG(ERROR)<< "Unknown parameter pad for layer type " << type; is_fully_compatible = false; } } @@ -267,10 +267,10 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_convolution_param()->add_kernel_size( v0_layer_param.kernelsize()); } else if (type == "pool") { - layer_param->mutable_pooling_param()->set_kernel_size( + layer_param->mutable_pooling_param()->add_kernel_size( v0_layer_param.kernelsize()); } else { - LOG(ERROR) << "Unknown parameter kernelsize for layer type " << type; + LOG(ERROR)<< "Unknown parameter kernelsize for layer type " << type; is_fully_compatible = false; } } @@ -279,7 +279,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_convolution_param()->set_group( v0_layer_param.group()); } else { - LOG(ERROR) << "Unknown parameter group for layer type " << type; + LOG(ERROR)<< "Unknown parameter group for layer type " << type; is_fully_compatible = false; } } @@ -288,10 +288,10 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_convolution_param()->add_stride( v0_layer_param.stride()); } else if (type == "pool") { - layer_param->mutable_pooling_param()->set_stride( + layer_param->mutable_pooling_param()->add_stride( v0_layer_param.stride()); } else { - LOG(ERROR) << "Unknown parameter stride for layer type " << type; + LOG(ERROR)<< "Unknown parameter stride for layer type " << type; is_fully_compatible = false; } } @@ -299,33 +299,33 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, if (type == "pool") { V0LayerParameter_PoolMethod pool = v0_layer_param.pool(); switch (pool) { - case V0LayerParameter_PoolMethod_MAX: - layer_param->mutable_pooling_param()->set_pool( - PoolingParameter_PoolMethod_MAX); - break; - case V0LayerParameter_PoolMethod_AVE: - layer_param->mutable_pooling_param()->set_pool( - PoolingParameter_PoolMethod_AVE); - break; - case V0LayerParameter_PoolMethod_STOCHASTIC: - layer_param->mutable_pooling_param()->set_pool( - PoolingParameter_PoolMethod_STOCHASTIC); - break; - default: - LOG(ERROR) << "Unknown pool method " << pool; + case V0LayerParameter_PoolMethod_MAX: + layer_param->mutable_pooling_param()->set_pool( + PoolingParameter_PoolMethod_MAX); + break; + case V0LayerParameter_PoolMethod_AVE: + layer_param->mutable_pooling_param()->set_pool( + PoolingParameter_PoolMethod_AVE); + break; + case V0LayerParameter_PoolMethod_STOCHASTIC: + layer_param->mutable_pooling_param()->set_pool( + PoolingParameter_PoolMethod_STOCHASTIC); + break; + default: + LOG(ERROR)<< "Unknown pool method " << pool; + is_fully_compatible = false; + } + } else { + LOG(ERROR) << "Unknown parameter pool for layer type " << type; is_fully_compatible = false; } - } else { - LOG(ERROR) << "Unknown parameter pool for layer type " << type; - is_fully_compatible = false; } - } if (v0_layer_param.has_dropout_ratio()) { if (type == "dropout") { layer_param->mutable_dropout_param()->set_dropout_ratio( v0_layer_param.dropout_ratio()); } else { - LOG(ERROR) << "Unknown parameter dropout_ratio for layer type " << type; + LOG(ERROR)<< "Unknown parameter dropout_ratio for layer type " << type; is_fully_compatible = false; } } @@ -334,7 +334,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_lrn_param()->set_local_size( v0_layer_param.local_size()); } else { - LOG(ERROR) << "Unknown parameter local_size for layer type " << type; + LOG(ERROR)<< "Unknown parameter local_size for layer type " << type; is_fully_compatible = false; } } @@ -342,7 +342,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, if (type == "lrn") { layer_param->mutable_lrn_param()->set_alpha(v0_layer_param.alpha()); } else { - LOG(ERROR) << "Unknown parameter alpha for layer type " << type; + LOG(ERROR)<< "Unknown parameter alpha for layer type " << type; is_fully_compatible = false; } } @@ -350,7 +350,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, if (type == "lrn") { layer_param->mutable_lrn_param()->set_beta(v0_layer_param.beta()); } else { - LOG(ERROR) << "Unknown parameter beta for layer type " << type; + LOG(ERROR)<< "Unknown parameter beta for layer type " << type; is_fully_compatible = false; } } @@ -358,7 +358,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, if (type == "lrn") { layer_param->mutable_lrn_param()->set_k(v0_layer_param.k()); } else { - LOG(ERROR) << "Unknown parameter k for layer type " << type; + LOG(ERROR)<< "Unknown parameter k for layer type " << type; is_fully_compatible = false; } } @@ -378,17 +378,16 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_infogain_loss_param()->set_source( v0_layer_param.source()); } else { - LOG(ERROR) << "Unknown parameter source for layer type " << type; + LOG(ERROR)<< "Unknown parameter source for layer type " << type; is_fully_compatible = false; } } if (v0_layer_param.has_scale()) { - layer_param->mutable_transform_param()-> - set_scale(v0_layer_param.scale()); + layer_param->mutable_transform_param()->set_scale(v0_layer_param.scale()); } if (v0_layer_param.has_meanfile()) { - layer_param->mutable_transform_param()-> - set_mean_file(v0_layer_param.meanfile()); + layer_param->mutable_transform_param()->set_mean_file( + v0_layer_param.meanfile()); } if (v0_layer_param.has_batchsize()) { if (type == "data") { @@ -404,17 +403,17 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_window_data_param()->set_batch_size( v0_layer_param.batchsize()); } else { - LOG(ERROR) << "Unknown parameter batchsize for layer type " << type; + LOG(ERROR)<< "Unknown parameter batchsize for layer type " << type; is_fully_compatible = false; } } if (v0_layer_param.has_cropsize()) { - layer_param->mutable_transform_param()-> - set_crop_size(v0_layer_param.cropsize()); + layer_param->mutable_transform_param()->set_crop_size( + v0_layer_param.cropsize()); } if (v0_layer_param.has_mirror()) { - layer_param->mutable_transform_param()-> - set_mirror(v0_layer_param.mirror()); + layer_param->mutable_transform_param()->set_mirror( + v0_layer_param.mirror()); } if (v0_layer_param.has_rand_skip()) { if (type == "data") { @@ -424,7 +423,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_image_data_param()->set_rand_skip( v0_layer_param.rand_skip()); } else { - LOG(ERROR) << "Unknown parameter rand_skip for layer type " << type; + LOG(ERROR)<< "Unknown parameter rand_skip for layer type " << type; is_fully_compatible = false; } } @@ -433,7 +432,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_image_data_param()->set_shuffle( v0_layer_param.shuffle_images()); } else { - LOG(ERROR) << "Unknown parameter shuffle for layer type " << type; + LOG(ERROR)<< "Unknown parameter shuffle for layer type " << type; is_fully_compatible = false; } } @@ -442,7 +441,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_image_data_param()->set_new_height( v0_layer_param.new_height()); } else { - LOG(ERROR) << "Unknown parameter new_height for layer type " << type; + LOG(ERROR)<< "Unknown parameter new_height for layer type " << type; is_fully_compatible = false; } } @@ -451,7 +450,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_image_data_param()->set_new_width( v0_layer_param.new_width()); } else { - LOG(ERROR) << "Unknown parameter new_width for layer type " << type; + LOG(ERROR)<< "Unknown parameter new_width for layer type " << type; is_fully_compatible = false; } } @@ -460,7 +459,7 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_concat_param()->set_concat_dim( v0_layer_param.concat_dim()); } else { - LOG(ERROR) << "Unknown parameter concat_dim for layer type " << type; + LOG(ERROR)<< "Unknown parameter concat_dim for layer type " << type; is_fully_compatible = false; } } @@ -469,8 +468,8 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_window_data_param()->set_fg_threshold( v0_layer_param.det_fg_threshold()); } else { - LOG(ERROR) << "Unknown parameter det_fg_threshold for layer type " - << type; + LOG(ERROR)<< "Unknown parameter det_fg_threshold for layer type " + << type; is_fully_compatible = false; } } @@ -479,8 +478,8 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_window_data_param()->set_bg_threshold( v0_layer_param.det_bg_threshold()); } else { - LOG(ERROR) << "Unknown parameter det_bg_threshold for layer type " - << type; + LOG(ERROR)<< "Unknown parameter det_bg_threshold for layer type " + << type; is_fully_compatible = false; } } @@ -489,8 +488,8 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_window_data_param()->set_fg_fraction( v0_layer_param.det_fg_fraction()); } else { - LOG(ERROR) << "Unknown parameter det_fg_fraction for layer type " - << type; + LOG(ERROR)<< "Unknown parameter det_fg_fraction for layer type " + << type; is_fully_compatible = false; } } @@ -499,8 +498,8 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_window_data_param()->set_context_pad( v0_layer_param.det_context_pad()); } else { - LOG(ERROR) << "Unknown parameter det_context_pad for layer type " - << type; + LOG(ERROR)<< "Unknown parameter det_context_pad for layer type " + << type; is_fully_compatible = false; } } @@ -509,8 +508,8 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_window_data_param()->set_crop_mode( v0_layer_param.det_crop_mode()); } else { - LOG(ERROR) << "Unknown parameter det_crop_mode for layer type " - << type; + LOG(ERROR)<< "Unknown parameter det_crop_mode for layer type " + << type; is_fully_compatible = false; } } @@ -519,8 +518,8 @@ bool UpgradeV0LayerParameter(const V1LayerParameter& v0_layer_connection, layer_param->mutable_hdf5_output_param()->CopyFrom( v0_layer_param.hdf5_output_param()); } else { - LOG(ERROR) << "Unknown parameter hdf5_output_param for layer type " - << type; + LOG(ERROR)<< "Unknown parameter hdf5_output_param for layer type " + << type; is_fully_compatible = false; } } @@ -578,7 +577,7 @@ V1LayerParameter_LayerType UpgradeV0LayerType(const string& type) { } else if (type == "window_data") { return V1LayerParameter_LayerType_WINDOW_DATA; } else { - LOG(FATAL) << "Unknown layer name: " << type; + LOG(FATAL)<< "Unknown layer name: " << type; return V1LayerParameter_LayerType_NONE; } } @@ -587,24 +586,48 @@ bool NetNeedsDataUpgrade(const NetParameter& net_param) { for (int i = 0; i < net_param.layers_size(); ++i) { if (net_param.layers(i).type() == V1LayerParameter_LayerType_DATA) { DataParameter layer_param = net_param.layers(i).data_param(); - if (layer_param.has_scale()) { return true; } - if (layer_param.has_mean_file()) { return true; } - if (layer_param.has_crop_size()) { return true; } - if (layer_param.has_mirror()) { return true; } + if (layer_param.has_scale()) { + return true; + } + if (layer_param.has_mean_file()) { + return true; + } + if (layer_param.has_crop_size()) { + return true; + } + if (layer_param.has_mirror()) { + return true; + } } if (net_param.layers(i).type() == V1LayerParameter_LayerType_IMAGE_DATA) { ImageDataParameter layer_param = net_param.layers(i).image_data_param(); - if (layer_param.has_scale()) { return true; } - if (layer_param.has_mean_file()) { return true; } - if (layer_param.has_crop_size()) { return true; } - if (layer_param.has_mirror()) { return true; } + if (layer_param.has_scale()) { + return true; + } + if (layer_param.has_mean_file()) { + return true; + } + if (layer_param.has_crop_size()) { + return true; + } + if (layer_param.has_mirror()) { + return true; + } } if (net_param.layers(i).type() == V1LayerParameter_LayerType_WINDOW_DATA) { WindowDataParameter layer_param = net_param.layers(i).window_data_param(); - if (layer_param.has_scale()) { return true; } - if (layer_param.has_mean_file()) { return true; } - if (layer_param.has_crop_size()) { return true; } - if (layer_param.has_mirror()) { return true; } + if (layer_param.has_scale()) { + return true; + } + if (layer_param.has_mean_file()) { + return true; + } + if (layer_param.has_crop_size()) { + return true; + } + if (layer_param.has_mirror()) { + return true; + } } } return false; @@ -647,8 +670,8 @@ void UpgradeNetDataTransformation(NetParameter* net_param) { bool UpgradeV1Net(const NetParameter& v1_net_param, NetParameter* net_param) { bool is_fully_compatible = true; if (v1_net_param.layer_size() > 0) { - LOG(ERROR) << "Input NetParameter to be upgraded already specifies 'layer' " - << "fields; these will be ignored for the upgrade."; + LOG(ERROR)<< "Input NetParameter to be upgraded already specifies 'layer' " + << "fields; these will be ignored for the upgrade."; is_fully_compatible = false; } net_param->CopyFrom(v1_net_param); @@ -657,7 +680,7 @@ bool UpgradeV1Net(const NetParameter& v1_net_param, NetParameter* net_param) { for (int i = 0; i < v1_net_param.layers_size(); ++i) { if (!UpgradeV1LayerParameter(v1_net_param.layers(i), net_param->add_layer())) { - LOG(ERROR) << "Upgrade of input layer " << i << " failed."; + LOG(ERROR)<< "Upgrade of input layer " << i << " failed."; is_fully_compatible = false; } } @@ -690,32 +713,40 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, layer_param->add_blobs()->CopyFrom(v1_layer_param.blobs(i)); } for (int i = 0; i < v1_layer_param.param_size(); ++i) { - while (layer_param->param_size() <= i) { layer_param->add_param(); } + while (layer_param->param_size() <= i) { + layer_param->add_param(); + } layer_param->mutable_param(i)->set_name(v1_layer_param.param(i)); } ParamSpec_DimCheckMode mode; for (int i = 0; i < v1_layer_param.blob_share_mode_size(); ++i) { - while (layer_param->param_size() <= i) { layer_param->add_param(); } - switch (v1_layer_param.blob_share_mode(i)) { - case V1LayerParameter_DimCheckMode_STRICT: - mode = ParamSpec_DimCheckMode_STRICT; - break; - case V1LayerParameter_DimCheckMode_PERMISSIVE: - mode = ParamSpec_DimCheckMode_PERMISSIVE; - break; - default: - LOG(FATAL) << "Unknown blob_share_mode: " - << v1_layer_param.blob_share_mode(i); - break; + while (layer_param->param_size() <= i) { + layer_param->add_param(); } + switch (v1_layer_param.blob_share_mode(i)) { + case V1LayerParameter_DimCheckMode_STRICT: + mode = ParamSpec_DimCheckMode_STRICT; + break; + case V1LayerParameter_DimCheckMode_PERMISSIVE: + mode = ParamSpec_DimCheckMode_PERMISSIVE; + break; + default: + LOG(FATAL)<< "Unknown blob_share_mode: " + << v1_layer_param.blob_share_mode(i); + break; + } layer_param->mutable_param(i)->set_share_mode(mode); } for (int i = 0; i < v1_layer_param.blobs_lr_size(); ++i) { - while (layer_param->param_size() <= i) { layer_param->add_param(); } + while (layer_param->param_size() <= i) { + layer_param->add_param(); + } layer_param->mutable_param(i)->set_lr_mult(v1_layer_param.blobs_lr(i)); } for (int i = 0; i < v1_layer_param.weight_decay_size(); ++i) { - while (layer_param->param_size() <= i) { layer_param->add_param(); } + while (layer_param->param_size() <= i) { + layer_param->add_param(); + } layer_param->mutable_param(i)->set_decay_mult( v1_layer_param.weight_decay(i)); } @@ -743,8 +774,7 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, v1_layer_param.convolution_param()); } if (v1_layer_param.has_data_param()) { - layer_param->mutable_data_param()->CopyFrom( - v1_layer_param.data_param()); + layer_param->mutable_data_param()->CopyFrom(v1_layer_param.data_param()); } if (v1_layer_param.has_dropout_param()) { layer_param->mutable_dropout_param()->CopyFrom( @@ -759,8 +789,7 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, v1_layer_param.eltwise_param()); } if (v1_layer_param.has_exp_param()) { - layer_param->mutable_exp_param()->CopyFrom( - v1_layer_param.exp_param()); + layer_param->mutable_exp_param()->CopyFrom(v1_layer_param.exp_param()); } if (v1_layer_param.has_hdf5_data_param()) { layer_param->mutable_hdf5_data_param()->CopyFrom( @@ -787,28 +816,24 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, v1_layer_param.inner_product_param()); } if (v1_layer_param.has_lrn_param()) { - layer_param->mutable_lrn_param()->CopyFrom( - v1_layer_param.lrn_param()); + layer_param->mutable_lrn_param()->CopyFrom(v1_layer_param.lrn_param()); } if (v1_layer_param.has_memory_data_param()) { layer_param->mutable_memory_data_param()->CopyFrom( v1_layer_param.memory_data_param()); } if (v1_layer_param.has_mvn_param()) { - layer_param->mutable_mvn_param()->CopyFrom( - v1_layer_param.mvn_param()); + layer_param->mutable_mvn_param()->CopyFrom(v1_layer_param.mvn_param()); } if (v1_layer_param.has_pooling_param()) { layer_param->mutable_pooling_param()->CopyFrom( v1_layer_param.pooling_param()); } if (v1_layer_param.has_power_param()) { - layer_param->mutable_power_param()->CopyFrom( - v1_layer_param.power_param()); + layer_param->mutable_power_param()->CopyFrom(v1_layer_param.power_param()); } if (v1_layer_param.has_relu_param()) { - layer_param->mutable_relu_param()->CopyFrom( - v1_layer_param.relu_param()); + layer_param->mutable_relu_param()->CopyFrom(v1_layer_param.relu_param()); } if (v1_layer_param.has_sigmoid_param()) { layer_param->mutable_sigmoid_param()->CopyFrom( @@ -819,12 +844,10 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, v1_layer_param.softmax_param()); } if (v1_layer_param.has_slice_param()) { - layer_param->mutable_slice_param()->CopyFrom( - v1_layer_param.slice_param()); + layer_param->mutable_slice_param()->CopyFrom(v1_layer_param.slice_param()); } if (v1_layer_param.has_tanh_param()) { - layer_param->mutable_tanh_param()->CopyFrom( - v1_layer_param.tanh_param()); + layer_param->mutable_tanh_param()->CopyFrom(v1_layer_param.tanh_param()); } if (v1_layer_param.has_threshold_param()) { layer_param->mutable_threshold_param()->CopyFrom( @@ -839,11 +862,10 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, v1_layer_param.transform_param()); } if (v1_layer_param.has_loss_param()) { - layer_param->mutable_loss_param()->CopyFrom( - v1_layer_param.loss_param()); + layer_param->mutable_loss_param()->CopyFrom(v1_layer_param.loss_param()); } if (v1_layer_param.has_layer()) { - LOG(ERROR) << "Input NetParameter has V0 layer -- ignoring."; + LOG(ERROR)<< "Input NetParameter has V0 layer -- ignoring."; is_fully_compatible = false; } return is_fully_compatible; @@ -851,91 +873,91 @@ bool UpgradeV1LayerParameter(const V1LayerParameter& v1_layer_param, const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type) { switch (type) { - case V1LayerParameter_LayerType_NONE: - return ""; - case V1LayerParameter_LayerType_ABSVAL: - return "AbsVal"; - case V1LayerParameter_LayerType_ACCURACY: - return "Accuracy"; - case V1LayerParameter_LayerType_ARGMAX: - return "ArgMax"; - case V1LayerParameter_LayerType_BNLL: - return "BNLL"; - case V1LayerParameter_LayerType_CONCAT: - return "Concat"; - case V1LayerParameter_LayerType_CONTRASTIVE_LOSS: - return "ContrastiveLoss"; - case V1LayerParameter_LayerType_CONVOLUTION: - return "Convolution"; - case V1LayerParameter_LayerType_DECONVOLUTION: - return "Deconvolution"; - case V1LayerParameter_LayerType_DATA: - return "Data"; - case V1LayerParameter_LayerType_DROPOUT: - return "Dropout"; - case V1LayerParameter_LayerType_DUMMY_DATA: - return "DummyData"; - case V1LayerParameter_LayerType_EUCLIDEAN_LOSS: - return "EuclideanLoss"; - case V1LayerParameter_LayerType_ELTWISE: - return "Eltwise"; - case V1LayerParameter_LayerType_EXP: - return "Exp"; - case V1LayerParameter_LayerType_FLATTEN: - return "Flatten"; - case V1LayerParameter_LayerType_HDF5_DATA: - return "HDF5Data"; - case V1LayerParameter_LayerType_HDF5_OUTPUT: - return "HDF5Output"; - case V1LayerParameter_LayerType_HINGE_LOSS: - return "HingeLoss"; - case V1LayerParameter_LayerType_IM2COL: - return "Im2col"; - case V1LayerParameter_LayerType_IMAGE_DATA: - return "ImageData"; - case V1LayerParameter_LayerType_INFOGAIN_LOSS: - return "InfogainLoss"; - case V1LayerParameter_LayerType_INNER_PRODUCT: - return "InnerProduct"; - case V1LayerParameter_LayerType_LRN: - return "LRN"; - case V1LayerParameter_LayerType_MEMORY_DATA: - return "MemoryData"; - case V1LayerParameter_LayerType_MULTINOMIAL_LOGISTIC_LOSS: - return "MultinomialLogisticLoss"; - case V1LayerParameter_LayerType_MVN: - return "MVN"; - case V1LayerParameter_LayerType_POOLING: - return "Pooling"; - case V1LayerParameter_LayerType_POWER: - return "Power"; - case V1LayerParameter_LayerType_RELU: - return "ReLU"; - case V1LayerParameter_LayerType_SIGMOID: - return "Sigmoid"; - case V1LayerParameter_LayerType_SIGMOID_CROSS_ENTROPY_LOSS: - return "SigmoidCrossEntropyLoss"; - case V1LayerParameter_LayerType_SILENCE: - return "Silence"; - case V1LayerParameter_LayerType_SOFTMAX: - return "Softmax"; - case V1LayerParameter_LayerType_SOFTMAX_LOSS: - return "SoftmaxWithLoss"; - case V1LayerParameter_LayerType_SPLIT: - return "Split"; - case V1LayerParameter_LayerType_SLICE: - return "Slice"; - case V1LayerParameter_LayerType_TANH: - return "TanH"; - case V1LayerParameter_LayerType_WINDOW_DATA: - return "WindowData"; - case V1LayerParameter_LayerType_THRESHOLD: - return "Threshold"; - default: - LOG(FATAL) << "Unknown V1LayerParameter layer type: " << type; - return ""; + case V1LayerParameter_LayerType_NONE: + return ""; + case V1LayerParameter_LayerType_ABSVAL: + return "AbsVal"; + case V1LayerParameter_LayerType_ACCURACY: + return "Accuracy"; + case V1LayerParameter_LayerType_ARGMAX: + return "ArgMax"; + case V1LayerParameter_LayerType_BNLL: + return "BNLL"; + case V1LayerParameter_LayerType_CONCAT: + return "Concat"; + case V1LayerParameter_LayerType_CONTRASTIVE_LOSS: + return "ContrastiveLoss"; + case V1LayerParameter_LayerType_CONVOLUTION: + return "Convolution"; + case V1LayerParameter_LayerType_DECONVOLUTION: + return "Deconvolution"; + case V1LayerParameter_LayerType_DATA: + return "Data"; + case V1LayerParameter_LayerType_DROPOUT: + return "Dropout"; + case V1LayerParameter_LayerType_DUMMY_DATA: + return "DummyData"; + case V1LayerParameter_LayerType_EUCLIDEAN_LOSS: + return "EuclideanLoss"; + case V1LayerParameter_LayerType_ELTWISE: + return "Eltwise"; + case V1LayerParameter_LayerType_EXP: + return "Exp"; + case V1LayerParameter_LayerType_FLATTEN: + return "Flatten"; + case V1LayerParameter_LayerType_HDF5_DATA: + return "HDF5Data"; + case V1LayerParameter_LayerType_HDF5_OUTPUT: + return "HDF5Output"; + case V1LayerParameter_LayerType_HINGE_LOSS: + return "HingeLoss"; + case V1LayerParameter_LayerType_IM2COL: + return "Im2col"; + case V1LayerParameter_LayerType_IMAGE_DATA: + return "ImageData"; + case V1LayerParameter_LayerType_INFOGAIN_LOSS: + return "InfogainLoss"; + case V1LayerParameter_LayerType_INNER_PRODUCT: + return "InnerProduct"; + case V1LayerParameter_LayerType_LRN: + return "LRN"; + case V1LayerParameter_LayerType_MEMORY_DATA: + return "MemoryData"; + case V1LayerParameter_LayerType_MULTINOMIAL_LOGISTIC_LOSS: + return "MultinomialLogisticLoss"; + case V1LayerParameter_LayerType_MVN: + return "MVN"; + case V1LayerParameter_LayerType_POOLING: + return "Pooling"; + case V1LayerParameter_LayerType_POWER: + return "Power"; + case V1LayerParameter_LayerType_RELU: + return "ReLU"; + case V1LayerParameter_LayerType_SIGMOID: + return "Sigmoid"; + case V1LayerParameter_LayerType_SIGMOID_CROSS_ENTROPY_LOSS: + return "SigmoidCrossEntropyLoss"; + case V1LayerParameter_LayerType_SILENCE: + return "Silence"; + case V1LayerParameter_LayerType_SOFTMAX: + return "Softmax"; + case V1LayerParameter_LayerType_SOFTMAX_LOSS: + return "SoftmaxWithLoss"; + case V1LayerParameter_LayerType_SPLIT: + return "Split"; + case V1LayerParameter_LayerType_SLICE: + return "Slice"; + case V1LayerParameter_LayerType_TANH: + return "TanH"; + case V1LayerParameter_LayerType_WINDOW_DATA: + return "WindowData"; + case V1LayerParameter_LayerType_THRESHOLD: + return "Threshold"; + default: + LOG(FATAL)<< "Unknown V1LayerParameter layer type: " << type; + return ""; + } } -} // Return true iff the solver contains any old solver_type specified as enums bool SolverNeedsTypeUpgrade(const SolverParameter& solver_param) { @@ -952,31 +974,31 @@ bool UpgradeSolverType(SolverParameter* solver_param) { if (solver_param->has_solver_type()) { string type; switch (solver_param->solver_type()) { - case SolverParameter_SolverType_SGD: - type = "SGD"; - break; - case SolverParameter_SolverType_NESTEROV: - type = "Nesterov"; - break; - case SolverParameter_SolverType_ADAGRAD: - type = "AdaGrad"; - break; - case SolverParameter_SolverType_RMSPROP: - type = "RMSProp"; - break; - case SolverParameter_SolverType_ADADELTA: - type = "AdaDelta"; - break; - case SolverParameter_SolverType_ADAM: - type = "Adam"; - break; - default: - LOG(FATAL) << "Unknown SolverParameter solver_type: " << type; - } + case SolverParameter_SolverType_SGD: + type = "SGD"; + break; + case SolverParameter_SolverType_NESTEROV: + type = "Nesterov"; + break; + case SolverParameter_SolverType_ADAGRAD: + type = "AdaGrad"; + break; + case SolverParameter_SolverType_RMSPROP: + type = "RMSProp"; + break; + case SolverParameter_SolverType_ADADELTA: + type = "AdaDelta"; + break; + case SolverParameter_SolverType_ADAM: + type = "Adam"; + break; + default: + LOG(FATAL)<< "Unknown SolverParameter solver_type: " << type; + } solver_param->set_type(type); solver_param->clear_solver_type(); } else { - LOG(ERROR) << "Warning: solver type already up to date. "; + LOG(ERROR)<< "Warning: solver type already up to date. "; return false; } return true; @@ -987,17 +1009,17 @@ bool UpgradeSolverAsNeeded(const string& param_file, SolverParameter* param) { bool success = true; // Try to upgrade old style solver_type enum fields into new string type if (SolverNeedsTypeUpgrade(*param)) { - LOG(INFO) << "Attempting to upgrade input file specified using deprecated " - << "'solver_type' field (enum)': " << param_file; + LOG(INFO)<< "Attempting to upgrade input file specified using deprecated " + << "'solver_type' field (enum)': " << param_file; if (!UpgradeSolverType(param)) { success = false; LOG(ERROR) << "Warning: had one or more problems upgrading " - << "SolverType (see above)."; + << "SolverType (see above)."; } else { LOG(INFO) << "Successfully upgraded file specified using deprecated " - << "'solver_type' field (enum) to 'type' field (string)."; + << "'solver_type' field (enum) to 'type' field (string)."; LOG(WARNING) << "Note that future Caffe releases will only support " - << "'type' field (string) for a solver's type."; + << "'type' field (string) for a solver's type."; } } return success; diff --git a/src/gtest/gtest_main.cc b/src/gtest/gtest_main.cc index a09bbe0c6c5..ee13ed2345d 100644 --- a/src/gtest/gtest_main.cc +++ b/src/gtest/gtest_main.cc @@ -31,7 +31,7 @@ #include "gtest/gtest.h" -GTEST_API_ int main(int argc, char **argv) { +GTEST_API_ int_tp main(int_tp argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); diff --git a/tools/caffe.cpp b/tools/caffe.cpp index 470165add7f..0784656918f 100644 --- a/tools/caffe.cpp +++ b/tools/caffe.cpp @@ -1,3 +1,4 @@ + #ifdef WITH_PYTHON_LAYER #include "boost/python.hpp" namespace bp = boost::python; @@ -13,6 +14,7 @@ namespace bp = boost::python; #include "boost/algorithm/string.hpp" #include "caffe/caffe.hpp" +#include "caffe/device.hpp" #include "caffe/util/signal_handler.h" using caffe::Blob; @@ -24,6 +26,7 @@ using caffe::shared_ptr; using caffe::string; using caffe::Timer; using caffe::vector; +using caffe::device; using std::ostringstream; DEFINE_string(gpu, "", @@ -83,7 +86,7 @@ static void get_gpus(vector* gpus) { if (FLAGS_gpu == "all") { int count = 0; #ifndef CPU_ONLY - CUDA_CHECK(cudaGetDeviceCount(&count)); + count = Caffe::EnumerateDevices(true); #else NO_GPU; #endif @@ -107,14 +110,23 @@ static void get_gpus(vector* gpus) { // To add a command, define a function "int command()" and register it with // RegisterBrewFunction(action); -// Device Query: show diagnostic information for a GPU device. +// Device Query: show diagnostic information for a GPU device, or +// enumerate all devices if none is specified. int device_query() { - LOG(INFO) << "Querying GPUs " << FLAGS_gpu; - vector gpus; - get_gpus(&gpus); - for (int i = 0; i < gpus.size(); ++i) { - caffe::Caffe::SetDevice(gpus[i]); - caffe::Caffe::DeviceQuery(); + if (FLAGS_gpu.size() == 0 || FLAGS_gpu == "all") { + // If no gpu is specified, enumerate all the devices. + caffe::Caffe::EnumerateDevices(); + } else { +#ifndef CPU_ONLY + LOG(INFO) << "Querying GPUs " << FLAGS_gpu; + vector gpus; + get_gpus(&gpus); + Caffe::SetDevices(gpus); + for (int i = 0; i < gpus.size(); ++i) { + caffe::Caffe::SetDevice(gpus[i]); + caffe::Caffe::DeviceQuery(); + } +#endif // !CPU_ONLY } return 0; } @@ -178,16 +190,22 @@ int train() { LOG(INFO) << "Use CPU."; Caffe::set_mode(Caffe::CPU); } else { +#ifndef CPU_ONLY + // Load all devices that will be used + Caffe::SetDevices(gpus); + ostringstream s; - for (int i = 0; i < gpus.size(); ++i) { + for (int_tp i = 0; i < gpus.size(); ++i) { s << (i ? ", " : "") << gpus[i]; } LOG(INFO) << "Using GPUs " << s.str(); solver_param.set_device_id(gpus[0]); + // Initialize the first device Caffe::SetDevice(gpus[0]); Caffe::set_mode(Caffe::GPU); Caffe::set_solver_count(gpus.size()); +#endif // !CPU_ONLY } caffe::SignalHandler signal_handler( @@ -208,7 +226,11 @@ int train() { if (gpus.size() > 1) { caffe::P2PSync sync(solver, NULL, solver->param()); - sync.run(gpus); + std::vector devices; + for (int_tp i = 0; i < gpus.size(); ++i) { + devices.push_back(Caffe::Get().GetDevice(i, true)); + } + sync.run(devices); } else { LOG(INFO) << "Starting Optimization"; solver->Solve(); @@ -228,15 +250,18 @@ int test() { vector gpus; get_gpus(&gpus); if (gpus.size() != 0) { +#ifndef CPU_ONLY LOG(INFO) << "Use GPU with device ID " << gpus[0]; - Caffe::SetDevice(gpus[0]); + Caffe::SetDevices(gpus); Caffe::set_mode(Caffe::GPU); + Caffe::SetDevice(gpus[0]); +#endif // !CPU_ONLY } else { LOG(INFO) << "Use CPU."; Caffe::set_mode(Caffe::CPU); } // Instantiate the caffe net. - Net caffe_net(FLAGS_model, caffe::TEST); + Net caffe_net(FLAGS_model, caffe::TEST, Caffe::GetDefaultDevice()); caffe_net.CopyTrainedLayersFrom(FLAGS_weights); LOG(INFO) << "Running for " << FLAGS_iterations << " iterations."; @@ -244,15 +269,15 @@ int test() { vector test_score_output_id; vector test_score; float loss = 0; - for (int i = 0; i < FLAGS_iterations; ++i) { + for (int_tp i = 0; i < FLAGS_iterations; ++i) { float iter_loss; const vector*>& result = caffe_net.Forward(bottom_vec, &iter_loss); loss += iter_loss; - int idx = 0; - for (int j = 0; j < result.size(); ++j) { + int_tp idx = 0; + for (int_tp j = 0; j < result.size(); ++j) { const float* result_vec = result[j]->cpu_data(); - for (int k = 0; k < result[j]->count(); ++k, ++idx) { + for (int_tp k = 0; k < result[j]->count(); ++k, ++idx) { const float score = result_vec[k]; if (i == 0) { test_score.push_back(score); @@ -268,7 +293,7 @@ int test() { } loss /= FLAGS_iterations; LOG(INFO) << "Loss: " << loss; - for (int i = 0; i < test_score.size(); ++i) { + for (int_tp i = 0; i < test_score.size(); ++i) { const std::string& output_name = caffe_net.blob_names()[ caffe_net.output_blob_indices()[test_score_output_id[i]]]; const float loss_weight = caffe_net.blob_loss_weights()[ @@ -295,15 +320,18 @@ int time() { vector gpus; get_gpus(&gpus); if (gpus.size() != 0) { +#ifndef CPU_ONLY LOG(INFO) << "Use GPU with device ID " << gpus[0]; - Caffe::SetDevice(gpus[0]); + Caffe::SetDevices(gpus); Caffe::set_mode(Caffe::GPU); + Caffe::SetDevice(gpus[0]); +#endif // !CPU_ONLY } else { LOG(INFO) << "Use CPU."; Caffe::set_mode(Caffe::CPU); } // Instantiate the caffe net. - Net caffe_net(FLAGS_model, caffe::TRAIN); + Net caffe_net(FLAGS_model, caffe::TRAIN, Caffe::GetDefaultDevice()); // Do a clean forward and backward pass, so that memory allocation are done // and future iterations will be more stable. @@ -332,21 +360,23 @@ int time() { std::vector backward_time_per_layer(layers.size(), 0.0); double forward_time = 0.0; double backward_time = 0.0; - for (int j = 0; j < FLAGS_iterations; ++j) { + for (int_tp j = 0; j < FLAGS_iterations; ++j) { Timer iter_timer; iter_timer.Start(); forward_timer.Start(); - for (int i = 0; i < layers.size(); ++i) { + for (int_tp i = 0; i < layers.size(); ++i) { timer.Start(); layers[i]->Forward(bottom_vecs[i], top_vecs[i]); + Caffe::Synchronize(Caffe::GetDefaultDevice()->id()); forward_time_per_layer[i] += timer.MicroSeconds(); } forward_time += forward_timer.MicroSeconds(); backward_timer.Start(); - for (int i = layers.size() - 1; i >= 0; --i) { + for (int_tp i = layers.size() - 1; i >= 0; --i) { timer.Start(); layers[i]->Backward(top_vecs[i], bottom_need_backward[i], bottom_vecs[i]); + Caffe::Synchronize(Caffe::GetDefaultDevice()->id()); backward_time_per_layer[i] += timer.MicroSeconds(); } backward_time += backward_timer.MicroSeconds(); @@ -354,7 +384,7 @@ int time() { << iter_timer.MilliSeconds() << " ms."; } LOG(INFO) << "Average time per layer: "; - for (int i = 0; i < layers.size(); ++i) { + for (int_tp i = 0; i < layers.size(); ++i) { const caffe::string& layername = layers[i]->layer_param().name(); LOG(INFO) << std::setfill(' ') << std::setw(10) << layername << "\tforward: " << forward_time_per_layer[i] / 1000 / diff --git a/tools/compute_image_mean.cpp b/tools/compute_image_mean.cpp index 2035d515195..4f27d3a83cc 100644 --- a/tools/compute_image_mean.cpp +++ b/tools/compute_image_mean.cpp @@ -46,7 +46,7 @@ int main(int argc, char** argv) { scoped_ptr cursor(db->NewCursor()); BlobProto sum_blob; - int count = 0; + int_tp count = 0; // load first datum Datum datum; datum.ParseFromString(cursor->value()); @@ -59,10 +59,10 @@ int main(int argc, char** argv) { sum_blob.set_channels(datum.channels()); sum_blob.set_height(datum.height()); sum_blob.set_width(datum.width()); - const int data_size = datum.channels() * datum.height() * datum.width(); - int size_in_datum = std::max(datum.data().size(), + const int_tp data_size = datum.channels() * datum.height() * datum.width(); + int_tp size_in_datum = std::max(datum.data().size(), datum.float_data_size()); - for (int i = 0; i < size_in_datum; ++i) { + for (int_tp i = 0; i < size_in_datum; ++i) { sum_blob.add_data(0.); } LOG(INFO) << "Starting Iteration"; @@ -72,18 +72,18 @@ int main(int argc, char** argv) { DecodeDatumNative(&datum); const std::string& data = datum.data(); - size_in_datum = std::max(datum.data().size(), + size_in_datum = std::max(datum.data().size(), datum.float_data_size()); CHECK_EQ(size_in_datum, data_size) << "Incorrect data field size " << size_in_datum; if (data.size() != 0) { CHECK_EQ(data.size(), size_in_datum); - for (int i = 0; i < size_in_datum; ++i) { + for (int_tp i = 0; i < size_in_datum; ++i) { sum_blob.set_data(i, sum_blob.data(i) + (uint8_t)data[i]); } } else { CHECK_EQ(datum.float_data_size(), size_in_datum); - for (int i = 0; i < size_in_datum; ++i) { + for (int_tp i = 0; i < size_in_datum; ++i) { sum_blob.set_data(i, sum_blob.data(i) + static_cast(datum.float_data(i))); } @@ -98,7 +98,7 @@ int main(int argc, char** argv) { if (count % 10000 != 0) { LOG(INFO) << "Processed " << count << " files."; } - for (int i = 0; i < sum_blob.data_size(); ++i) { + for (int_tp i = 0; i < sum_blob.data_size(); ++i) { sum_blob.set_data(i, sum_blob.data(i) / count); } // Write to disk @@ -106,12 +106,12 @@ int main(int argc, char** argv) { LOG(INFO) << "Write to " << argv[2]; WriteProtoToBinaryFile(sum_blob, argv[2]); } - const int channels = sum_blob.channels(); - const int dim = sum_blob.height() * sum_blob.width(); + const int_tp channels = sum_blob.channels(); + const int_tp dim = sum_blob.height() * sum_blob.width(); std::vector mean_values(channels, 0.0); LOG(INFO) << "Number of channels: " << channels; - for (int c = 0; c < channels; ++c) { - for (int i = 0; i < dim; ++i) { + for (int_tp c = 0; c < channels; ++c) { + for (int_tp i = 0; i < dim; ++i) { mean_values[c] += sum_blob.data(dim * c + i); } LOG(INFO) << "mean_value channel [" << c << "]:" << mean_values[c] / dim; diff --git a/tools/convert_imageset.cpp b/tools/convert_imageset.cpp index 9c52bfa0ef8..764ddcabe85 100644 --- a/tools/convert_imageset.cpp +++ b/tools/convert_imageset.cpp @@ -72,9 +72,9 @@ int main(int argc, char** argv) { const string encode_type = FLAGS_encode_type; std::ifstream infile(argv[2]); - std::vector > lines; + std::vector > lines; std::string filename; - int label; + int_tp label; while (infile >> filename >> label) { lines.push_back(std::make_pair(filename, label)); } @@ -88,8 +88,8 @@ int main(int argc, char** argv) { if (encode_type.size() && !encoded) LOG(INFO) << "encode_type specified, assuming encoded=true."; - int resize_height = std::max(0, FLAGS_resize_height); - int resize_width = std::max(0, FLAGS_resize_width); + int_tp resize_height = std::max(0, FLAGS_resize_height); + int_tp resize_width = std::max(0, FLAGS_resize_width); // Create new DB scoped_ptr db(db::GetDB(FLAGS_backend)); @@ -99,17 +99,17 @@ int main(int argc, char** argv) { // Storing to db std::string root_folder(argv[1]); Datum datum; - int count = 0; - int data_size = 0; + int_tp count = 0; + int_tp data_size = 0; bool data_size_initialized = false; - for (int line_id = 0; line_id < lines.size(); ++line_id) { + for (int_tp line_id = 0; line_id < lines.size(); ++line_id) { bool status; std::string enc = encode_type; if (encoded && !enc.size()) { // Guess the encoding type from the file name string fn = lines[line_id].first; - size_t p = fn.rfind('.'); + uint_tp p = fn.rfind('.'); if ( p == fn.npos ) LOG(WARNING) << "Failed to guess the encoding of '" << fn << "'"; enc = fn.substr(p); diff --git a/tools/extra/extract_seconds.py b/tools/extra/extract_seconds.py index 591a51f96bd..4a2f227b1b7 100755 --- a/tools/extra/extract_seconds.py +++ b/tools/extra/extract_seconds.py @@ -6,15 +6,15 @@ def extract_datetime_from_line(line, year): # Expected format: I0210 13:39:22.381027 25210 solver.cpp:204] Iteration 100, lr = 0.00992565 line = line.strip().split() - month = int(line[0][1:3]) - day = int(line[0][3:]) + month = int_tp(line[0][1:3]) + day = int_tp(line[0][3:]) timestamp = line[1] pos = timestamp.rfind('.') - ts = [int(x) for x in timestamp[:pos].split(':')] + ts = [int_tp(x) for x in timestamp[:pos].split(':')] hour = ts[0] minute = ts[1] second = ts[2] - microsecond = int(timestamp[pos + 1:]) + microsecond = int_tp(timestamp[pos + 1:]) dt = datetime.datetime(year, month, day, hour, minute, second, microsecond) return dt diff --git a/tools/extra/plot_training_log.py.example b/tools/extra/plot_training_log.py.example index 4d3ed0d15a9..5eb55cbb550 100755 --- a/tools/extra/plot_training_log.py.example +++ b/tools/extra/plot_training_log.py.example @@ -169,7 +169,7 @@ if __name__ == '__main__': if len(sys.argv) < 4: print_help() else: - chart_type = int(sys.argv[1]) + chart_type = int_tp(sys.argv[1]) if not is_valid_chart_type(chart_type): print_help() path_to_png = sys.argv[2] diff --git a/tools/extra/resize_and_crop_images.py b/tools/extra/resize_and_crop_images.py index c844f590c06..e4e30d9070a 100755 --- a/tools/extra/resize_and_crop_images.py +++ b/tools/extra/resize_and_crop_images.py @@ -56,11 +56,11 @@ def resize_and_crop_image(self, input_file, output_file, output_side_length = 25 wRatio = 1.0 * x2/box[0] hRatio = 1.0 * y2/box[1] if hRatio > wRatio: - y1 = int(y2/2-box[1]*wRatio/2) - y2 = int(y2/2+box[1]*wRatio/2) + y1 = int_tp(y2/2-box[1]*wRatio/2) + y2 = int_tp(y2/2+box[1]*wRatio/2) else: - x1 = int(x2/2-box[0]*hRatio/2) - x2 = int(x2/2+box[0]*hRatio/2) + x1 = int_tp(x2/2-box[0]*hRatio/2) + x2 = int_tp(x2/2+box[0]*hRatio/2) img = img.crop((x1,y1,x2,y2)) #Resize the image with best quality algorithm ANTI-ALIAS diff --git a/tools/extract_features.cpp b/tools/extract_features.cpp index d6562f98059..e7521e7977b 100644 --- a/tools/extract_features.cpp +++ b/tools/extract_features.cpp @@ -95,7 +95,8 @@ int feature_extraction_pipeline(int argc, char** argv) { */ std::string feature_extraction_proto(argv[++arg_pos]); boost::shared_ptr > feature_extraction_net( - new Net(feature_extraction_proto, caffe::TEST)); + new Net(feature_extraction_proto, caffe::TEST, + Caffe::GetDefaultDevice())); feature_extraction_net->CopyTrainedLayersFrom(pretrained_binary_proto); std::string extract_feature_blob_names(argv[++arg_pos]); @@ -108,20 +109,20 @@ int feature_extraction_pipeline(int argc, char** argv) { boost::is_any_of(",")); CHECK_EQ(blob_names.size(), dataset_names.size()) << " the number of blob names and dataset names must be equal"; - size_t num_features = blob_names.size(); + uint_tp num_features = blob_names.size(); - for (size_t i = 0; i < num_features; i++) { + for (uint_tp i = 0; i < num_features; i++) { CHECK(feature_extraction_net->has_blob(blob_names[i])) << "Unknown feature blob name " << blob_names[i] << " in the network " << feature_extraction_proto; } - int num_mini_batches = atoi(argv[++arg_pos]); + int_tp num_mini_batches = atoi(argv[++arg_pos]); std::vector > feature_dbs; std::vector > txns; const char* db_type = argv[++arg_pos]; - for (size_t i = 0; i < num_features; ++i) { + for (uint_tp i = 0; i < num_features; ++i) { LOG(INFO)<< "Opening dataset " << dataset_names[i]; boost::shared_ptr db(db::GetDB(db_type)); db->Open(dataset_names.at(i), db::NEW); @@ -134,16 +135,16 @@ int feature_extraction_pipeline(int argc, char** argv) { Datum datum; std::vector*> input_vec; - std::vector image_indices(num_features, 0); - for (int batch_index = 0; batch_index < num_mini_batches; ++batch_index) { + std::vector image_indices(num_features, 0); + for (int_tp batch_index = 0; batch_index < num_mini_batches; ++batch_index) { feature_extraction_net->Forward(input_vec); - for (int i = 0; i < num_features; ++i) { + for (int_tp i = 0; i < num_features; ++i) { const boost::shared_ptr > feature_blob = feature_extraction_net->blob_by_name(blob_names[i]); - int batch_size = feature_blob->num(); - int dim_features = feature_blob->count() / batch_size; + int_tp batch_size = feature_blob->num(); + int_tp dim_features = feature_blob->count() / batch_size; const Dtype* feature_blob_data; - for (int n = 0; n < batch_size; ++n) { + for (int_tp n = 0; n < batch_size; ++n) { datum.set_height(feature_blob->height()); datum.set_width(feature_blob->width()); datum.set_channels(feature_blob->channels()); @@ -151,11 +152,10 @@ int feature_extraction_pipeline(int argc, char** argv) { datum.clear_float_data(); feature_blob_data = feature_blob->cpu_data() + feature_blob->offset(n); - for (int d = 0; d < dim_features; ++d) { + for (int_tp d = 0; d < dim_features; ++d) { datum.add_float_data(feature_blob_data[d]); } string key_str = caffe::format_int(image_indices[i], 10); - string out; CHECK(datum.SerializeToString(&out)); txns.at(i)->Put(key_str, out); @@ -166,11 +166,12 @@ int feature_extraction_pipeline(int argc, char** argv) { LOG(ERROR)<< "Extracted features of " << image_indices[i] << " query images for feature blob " << blob_names[i]; } - } // for (int n = 0; n < batch_size; ++n) - } // for (int i = 0; i < num_features; ++i) - } // for (int batch_index = 0; batch_index < num_mini_batches; ++batch_index) + } // for (int_tp n = 0; n < batch_size; ++n) + } // for (int_tp i = 0; i < num_features; ++i) + } // for (int_tp batch_index = 0; + // batch_index < num_mini_batches; ++batch_index) // write the last batch - for (int i = 0; i < num_features; ++i) { + for (int_tp i = 0; i < num_features; ++i) { if (image_indices[i] % 1000 != 0) { txns.at(i)->Commit(); } diff --git a/tools/upgrade_solver_proto_text.cpp b/tools/upgrade_solver_proto_text.cpp deleted file mode 100644 index 7130232aed7..00000000000 --- a/tools/upgrade_solver_proto_text.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// This is a script to upgrade old solver prototxts to the new format. -// Usage: -// upgrade_solver_proto_text old_solver_proto_file_in solver_proto_file_out - -#include -#include // NOLINT(readability/streams) -#include // NOLINT(readability/streams) -#include - -#include "caffe/caffe.hpp" -#include "caffe/util/io.hpp" -#include "caffe/util/upgrade_proto.hpp" - -using std::ofstream; - -using namespace caffe; // NOLINT(build/namespaces) - -int main(int argc, char** argv) { - ::google::InitGoogleLogging(argv[0]); - if (argc != 3) { - LOG(ERROR) << "Usage: upgrade_solver_proto_text " - << "old_solver_proto_file_in solver_proto_file_out"; - return 1; - } - - SolverParameter solver_param; - string input_filename(argv[1]); - if (!ReadProtoFromTextFile(input_filename, &solver_param)) { - LOG(ERROR) << "Failed to parse input text file as SolverParameter: " - << input_filename; - return 2; - } - bool need_upgrade = SolverNeedsTypeUpgrade(solver_param); - bool success = true; - if (need_upgrade) { - success = UpgradeSolverAsNeeded(input_filename, &solver_param); - if (!success) { - LOG(ERROR) << "Encountered error(s) while upgrading prototxt; " - << "see details above."; - } - } else { - LOG(ERROR) << "File already in latest proto format: " << input_filename; - } - - // Save new format prototxt. - WriteProtoToTextFile(solver_param, argv[2]); - - LOG(ERROR) << "Wrote upgraded SolverParameter text proto to " << argv[2]; - return !success; -}