diff --git a/CMakeLists.txt b/CMakeLists.txt index 88f929b7c..846279696 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,14 @@ find_program(MAKE_NSIS_EXE makensis) find_program(RPMBUILD_EXE rpmbuild) find_program(DPKG_EXE dpkg) -set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path") +# ROCM Path +if(DEFINED ENV{ROCM_PATH}) + set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path") +elseif(ROCM_PATH) + message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}") +else() + set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path") +endif() # avoid setting the default installation path to /usr/local if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX ${ROCM_PATH} CACHE PATH "rocAL default installation path" FORCE) diff --git a/README.md b/README.md index 82cb4b391..21d95b031 100644 --- a/README.md +++ b/README.md @@ -79,14 +79,15 @@ rocAL can be currently used to perform the following operations either with rand * [ROCm](https://rocmdocs.amd.com/en/latest/deploy/linux/installer/install.html) with --usecase=graphics,rocm * [AMD RPP](https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp) - MIVisionX Component * [AMD OpenVX™](https://github.com/GPUOpen-ProfessionalCompute-Libraries/MIVisionX/tree/master/amd_openvx) and AMD OpenVX™ Extensions: `VX_RPP` and `AMD Media` - MIVisionX Components -* [Boost library](https://www.boost.org) - Version `1.72` or higher * [Turbo JPEG](https://libjpeg-turbo.org/) - Version 2.0.6.2 from `https://github.com/rrawther/libjpeg-turbo.git` * [Half-precision floating-point](https://half.sourceforge.net) library - Version `1.12.0` or higher * [Google Protobuf](https://developers.google.com/protocol-buffers) - Version `3.12.4` or higher * [LMBD Library](http://www.lmdb.tech/doc/) * [RapidJSON](https://github.com/Tencent/rapidjson) * [PyBind11](https://github.com/pybind/pybind11) - +* [HIP](https://github.com/ROCm-Developer-Tools/HIP) +* OpenMP +* C++17 ## Build instructions ### Prerequisites setup script for Linux - `rocAL-setup.py` @@ -175,7 +176,6 @@ For the convenience of the developer, we here provide the setup script which wil * ROCm: rocm-core - `5.7.0.50700-6` * RPP - [1.2.0](https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp/releases/tag/1.2.0) * MIVisionX - [master](https://github.com/GPUOpen-ProfessionalCompute-Libraries/MIVisionX) -* Boost - [1.72.0](https://www.boost.org/users/history/version_1_72_0.html) * Protobuf - [V3.12.4](https://github.com/protocolbuffers/protobuf/releases/tag/v3.12.4) * OpenCV - [4.6.0](https://github.com/opencv/opencv/releases/tag/4.6.0) * FFMPEG - [n4.4.2](https://github.com/FFmpeg/FFmpeg/releases/tag/n4.4.2) diff --git a/cmake/FindHALF.cmake b/cmake/FindHALF.cmake new file mode 100644 index 000000000..398a4b651 --- /dev/null +++ b/cmake/FindHALF.cmake @@ -0,0 +1,60 @@ +################################################################################ +# +# MIT License +# +# Copyright (c) 2023 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################ +find_path(HALF_INCLUDE_DIRS + NAMES half/half.hpp + HINTS + $ENV{HALF_DIR}/include + $ENV{ROCM_PATH}/include + PATHS + ${HALF_DIR}/include + /usr/include + /usr/local/include + ${ROCM_PATH}/include +) +mark_as_advanced(HALF_INCLUDE_DIRS) + +if(HALF_INCLUDE_DIRS) + set(HALF_FOUND TRUE) +endif( ) + +include( FindPackageHandleStandardArgs ) +find_package_handle_standard_args( HALF + FOUND_VAR HALF_FOUND + REQUIRED_VARS + HALF_INCLUDE_DIRS +) + +set(HALF_FOUND ${HALF_FOUND} CACHE INTERNAL "") +set(HALF_INCLUDE_DIRS ${HALF_INCLUDE_DIRS} CACHE INTERNAL "") + +if(HALF_FOUND) + message("-- ${White}Using HALF -- \n\tIncludes:${HALF_INCLUDE_DIRS}${ColourReset}") +else() + if(HALF_FIND_REQUIRED) + message(FATAL_ERROR "{Red}FindHALF -- NOT FOUND${ColourReset}") + endif() + message( "-- ${Yellow}NOTE: FindHALF failed to find -- half.hpp${ColourReset}" ) +endif() diff --git a/cmake/FindStdFilesystem.cmake b/cmake/FindStdFilesystem.cmake new file mode 100644 index 000000000..1d24e72f9 --- /dev/null +++ b/cmake/FindStdFilesystem.cmake @@ -0,0 +1,58 @@ +################################################################################ +# +# MIT License +# +# Copyright (c) 2023 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################ +include(CheckCXXSourceCompiles) +include(CMakePushCheckState) + +cmake_push_check_state(RESET) + +set(CMAKE_REQUIRED_FLAGS "-std=c++17") + +check_cxx_source_compiles(" +#include +int main() { + std::filesystem::path p; + return 0; +} +" STD_FILESYSTEM_PRESENT) + +cmake_pop_check_state() + +if(NOT STD_FILESYSTEM_PRESENT) + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_FLAGS "-std=c++17") + + check_cxx_source_compiles(" + #include + int main() { + std::experimental::filesystem::path p; + return 0; + } + " EXPERIMENTAL_FILESYSTEM_PRESENT) + + cmake_pop_check_state() +endif() + +set(FILESYSTEM_FOUND TRUE) \ No newline at end of file diff --git a/docker/rocal-on-rhel-09.dockerfile b/docker/rocal-on-rhel-09.dockerfile index 9598daec8..c831c8038 100644 --- a/docker/rocal-on-rhel-09.dockerfile +++ b/docker/rocal-on-rhel-09.dockerfile @@ -23,13 +23,7 @@ RUN apt-get update -y && apt-get -y install autoconf automake libbz2-dev libssl- git clone -b 2.0.6.2 https://github.com/rrawther/libjpeg-turbo.git && cd libjpeg-turbo && mkdir build && cd build && \ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_STATIC=FALSE -DCMAKE_INSTALL_DOCDIR=/usr/share/doc/libjpeg-turbo-2.0.3 \ -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib ../ && make -j4 && sudo make install && cd -RUN apt-get -y install sqlite3 libsqlite3-dev libtool build-essential && \ - wget https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.bz2 && tar xjvf boost_1_80_0.tar.bz2 && \ - cd boost_1_80_0 && ./bootstrap.sh --prefix=/usr/local --with-python=python3 && \ - ./b2 stage -j16 threading=multi link=shared cxxflags="-std=c++11" && \ - sudo ./b2 install threading=multi link=shared --with-system --with-filesystem && \ - ./b2 stage -j16 threading=multi link=static cxxflags="-std=c++11 -fpic" cflags="-fpic" && \ - sudo ./b2 install threading=multi link=static --with-system --with-filesystem +RUN apt-get -y install sqlite3 libsqlite3-dev libtool build-essential RUN git clone -b v3.21.9 https://github.com/protocolbuffers/protobuf.git && cd protobuf && git submodule update --init --recursive && \ ./autogen.sh && ./configure && make -j8 && make check -j8 && sudo make install && sudo ldconfig && cd RUN git clone -b 0.99 https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp.git && cd rpp && mkdir build && cd build && \ diff --git a/docker/rocal-on-ubuntu-20-with-pytorch-with-mesa.dockerfile b/docker/rocal-on-ubuntu-20-with-pytorch-with-mesa.dockerfile index 935223482..0ca865469 100644 --- a/docker/rocal-on-ubuntu-20-with-pytorch-with-mesa.dockerfile +++ b/docker/rocal-on-ubuntu-20-with-pytorch-with-mesa.dockerfile @@ -47,12 +47,6 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get -y install wget libbz2-dev libssl-dev git clone -b 2.0.6.2 https://github.com/rrawther/libjpeg-turbo.git && cd libjpeg-turbo && mkdir build && cd build && \ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_STATIC=FALSE -DCMAKE_INSTALL_DOCDIR=/usr/share/doc/libjpeg-turbo-2.0.3 \ -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib ../ && make -j4 && sudo make install && cd ../../ && \ - wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2 && tar xjvf boost_1_72_0.tar.bz2 && \ - cd boost_1_72_0 && ./bootstrap.sh --prefix=/usr/local --with-python=python3 && \ - ./b2 stage -j16 threading=multi link=shared cxxflags="-std=c++11" && \ - sudo ./b2 install threading=multi link=shared --with-system --with-filesystem && \ - ./b2 stage -j16 threading=multi link=static cxxflags="-std=c++11 -fpic" cflags="-fpic" && \ - sudo ./b2 install threading=multi link=static --with-system --with-filesystem && cd ../ && \ git clone -b 1.1.0 https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp.git && cd rpp && mkdir build && cd build && \ cmake -DBACKEND=HIP ../ && make -j4 && sudo make install && cd ../../ && \ git clone -b v3.12.4 https://github.com/protocolbuffers/protobuf.git && cd protobuf && git submodule update --init --recursive && \ diff --git a/docker/rocal-on-ubuntu-20.dockerfile b/docker/rocal-on-ubuntu-20.dockerfile index a38d5de0f..c72add09a 100644 --- a/docker/rocal-on-ubuntu-20.dockerfile +++ b/docker/rocal-on-ubuntu-20.dockerfile @@ -44,12 +44,6 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get -y install wget libbz2-dev libssl-dev git clone -b 2.0.6.2 https://github.com/rrawther/libjpeg-turbo.git && cd libjpeg-turbo && mkdir build && cd build && \ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_STATIC=FALSE -DCMAKE_INSTALL_DOCDIR=/usr/share/doc/libjpeg-turbo-2.0.3 \ -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib ../ && make -j4 && sudo make install && cd ../../ && \ - wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2 && tar xjvf boost_1_72_0.tar.bz2 && \ - cd boost_1_72_0 && ./bootstrap.sh --prefix=/usr/local --with-python=python3 && \ - ./b2 stage -j16 threading=multi link=shared cxxflags="-std=c++11" && \ - sudo ./b2 install threading=multi link=shared --with-system --with-filesystem && \ - ./b2 stage -j16 threading=multi link=static cxxflags="-std=c++11 -fpic" cflags="-fpic" && \ - sudo ./b2 install threading=multi link=static --with-system --with-filesystem && cd ../ && \ git clone -b 1.1.0 https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp.git && cd rpp && mkdir build && cd build && \ cmake -DBACKEND=HIP ../ && make -j4 && sudo make install && cd ../../ && \ git clone -b v3.12.4 https://github.com/protocolbuffers/protobuf.git && cd protobuf && git submodule update --init --recursive && \ diff --git a/docker/rocal-on-ubuntu-22.dockerfile b/docker/rocal-on-ubuntu-22.dockerfile index c5164fb02..b813a21db 100644 --- a/docker/rocal-on-ubuntu-22.dockerfile +++ b/docker/rocal-on-ubuntu-22.dockerfile @@ -45,13 +45,7 @@ RUN apt-get update -y && apt-get -y install autoconf automake libbz2-dev libssl- git clone -b 2.0.6.2 https://github.com/rrawther/libjpeg-turbo.git && cd libjpeg-turbo && mkdir build && cd build && \ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_STATIC=FALSE -DCMAKE_INSTALL_DOCDIR=/usr/share/doc/libjpeg-turbo-2.0.3 \ -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib ../ && make -j4 && sudo make install && cd -RUN apt-get -y install sqlite3 libsqlite3-dev libtool build-essential && \ - wget https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.bz2 && tar xjvf boost_1_80_0.tar.bz2 && \ - cd boost_1_80_0 && ./bootstrap.sh --prefix=/usr/local --with-python=python3 && \ - ./b2 stage -j16 threading=multi link=shared cxxflags="-std=c++11" && \ - sudo ./b2 install threading=multi link=shared --with-system --with-filesystem && \ - ./b2 stage -j16 threading=multi link=static cxxflags="-std=c++11 -fpic" cflags="-fpic" && \ - sudo ./b2 install threading=multi link=static --with-system --with-filesystem +RUN apt-get -y install sqlite3 libsqlite3-dev libtool build-essential RUN git clone -b v3.21.9 https://github.com/protocolbuffers/protobuf.git && cd protobuf && git submodule update --init --recursive && \ ./autogen.sh && ./configure && make -j8 && make check -j8 && sudo make install && sudo ldconfig && cd RUN git clone -b 1.1.0 https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp.git && cd rpp && mkdir build && cd build && \ diff --git a/docker/rocal-with-pytorch.dockerfile b/docker/rocal-with-pytorch.dockerfile index 8dd7043a4..a26a845c0 100644 --- a/docker/rocal-with-pytorch.dockerfile +++ b/docker/rocal-with-pytorch.dockerfile @@ -34,12 +34,6 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get -y install wget libbz2-dev libssl-dev git clone -b 2.0.6.2 https://github.com/rrawther/libjpeg-turbo.git && cd libjpeg-turbo && mkdir build && cd build && \ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_STATIC=FALSE -DCMAKE_INSTALL_DOCDIR=/usr/share/doc/libjpeg-turbo-2.0.3 \ -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib ../ && make -j4 && sudo make install && cd ../../ && \ - wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2 && tar xjvf boost_1_72_0.tar.bz2 && \ - cd boost_1_72_0 && ./bootstrap.sh --prefix=/usr/local --with-python=python3 && \ - ./b2 stage -j16 threading=multi link=shared cxxflags="-std=c++11" && \ - sudo ./b2 install threading=multi link=shared --with-system --with-filesystem && \ - ./b2 stage -j16 threading=multi link=static cxxflags="-std=c++11 -fpic" cflags="-fpic" && \ - sudo ./b2 install threading=multi link=static --with-system --with-filesystem && cd ../ && \ git clone -b 1.1.0 https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp.git && cd rpp && mkdir build && cd build && \ cmake -DBACKEND=HIP ../ && make -j4 && sudo make install && cd ../../ && \ git clone -b v3.12.4 https://github.com/protocolbuffers/protobuf.git && cd protobuf && git submodule update --init --recursive && \ diff --git a/docs/user_guide/ch3.md b/docs/user_guide/ch3.md index 912dec236..aa64b032a 100644 --- a/docs/user_guide/ch3.md +++ b/docs/user_guide/ch3.md @@ -7,7 +7,6 @@ This chapter provides information about the installation of rocAL and related pa * Linux distribution * [AMD RPP](https://github.com/GPUOpen-ProfessionalCompute-Libraries/rpp) * [AMD OpenVX™](https://github.com/GPUOpen-ProfessionalCompute-Libraries/MIVisionX/tree/master/amd_openvx) and AMD OpenVX™ Extensions: `VX_RPP` and `AMD Media` -* [Boost library](https://www.boost.org) - Version `1.72` or higher * [Turbo JPEG](https://libjpeg-turbo.org/) - Version `2.0` or higher * [Half-precision floating-point](https://half.sourceforge.net) library - Version `1.12.0` or higher * [Google Protobuf](https://developers.google.com/protocol-buffers) - Version `3.12.4` or higher diff --git a/rocAL-setup.py b/rocAL-setup.py index 5c651b359..fa6b5de91 100644 --- a/rocAL-setup.py +++ b/rocAL-setup.py @@ -43,8 +43,8 @@ help='OpenCV Version - optional (default:4.6.0)') parser.add_argument('--protobuf', type=str, default='3.12.4', help='ProtoBuf Version - optional (default:3.12.4)') -parser.add_argument('--rpp', type=str, default='1.2.0', - help='RPP Version - optional (default:1.2.0)') +parser.add_argument('--rpp', type=str, default='master', + help='RPP Version - optional (default:master)') parser.add_argument('--mivisionx', type=str, default='master', help='MIVisionX Version - optional (default:master)') parser.add_argument('--pybind11', type=str, default='v2.10.4', @@ -229,24 +229,6 @@ elif "SLES" in platfromInfo: os.system('sudo '+linuxFlag+' '+linuxSystemInstall+' ' + linuxSystemInstall_check+' install sqlite3 sqlite3-devel libbz2-devel libopenssl-devel python3-devel autoconf automake libtool curl make gcc-c++ unzip') - # Boost V 1.72.0 from source - os.system( - '(cd '+deps_dir+'; wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.bz2 )') - os.system('(cd '+deps_dir+'; tar xjvf boost_1_72_0.tar.bz2 )') - if "centos-8" in platfromInfo or "redhat-8" in platfromInfo or "SLES" in platfromInfo: - os.system( - '(cd '+deps_dir+'/boost_1_72_0/; ./bootstrap.sh --prefix=/usr/local --with-python=python36 )') - else: - os.system( - '(cd '+deps_dir+'/boost_1_72_0/; ./bootstrap.sh --prefix=/usr/local --with-python=python3 )') - os.system( - '(cd '+deps_dir+'/boost_1_72_0/; ./b2 stage -j16 threading=multi link=shared cxxflags="-std=c++11" )') - os.system( - '(cd '+deps_dir+'/boost_1_72_0/; sudo ./b2 install threading=multi link=shared --with-system --with-filesystem)') - os.system( - '(cd '+deps_dir+'/boost_1_72_0/; ./b2 stage -j16 threading=multi link=static cxxflags="-std=c++11 -fpic" cflags="-fpic" )') - os.system( - '(cd '+deps_dir+'/boost_1_72_0/; sudo ./b2 install threading=multi link=static --with-system --with-filesystem)') # Install half.hpp os.system( '(cd '+deps_dir+'; wget https://sourceforge.net/projects/half/files/half/1.12.0/half-1.12.0.zip )') @@ -324,10 +306,6 @@ os.system('sudo -v') os.system('sudo '+linuxFlag+' '+linuxSystemInstall+' ' + linuxSystemInstall_check+' install jsoncpp-devel') - # boost - os.system('sudo -v') - os.system('sudo '+linuxFlag+' '+linuxSystemInstall+' ' + - linuxSystemInstall_check+' install boost-devel') # lmbd os.system('sudo -v') os.system('sudo '+linuxFlag+' '+linuxSystemInstall+' ' + @@ -344,6 +322,12 @@ linuxCMake+' -DBACKEND='+backend+' -DCMAKE_INSTALL_PREFIX='+ROCM_PATH+' ../; make -j4; sudo make install)') # RapidJSON os.system('sudo -v') + if "Ubuntu" in platfromInfo: + os.system('sudo '+linuxFlag+' '+linuxSystemInstall + ' ' + + linuxSystemInstall_check+' install -y rapidjson-dev') + else: + os.system('sudo '+linuxFlag+' '+linuxSystemInstall + ' ' + + linuxSystemInstall_check+' install -y rapidjson-devel') os.system('(cd '+deps_dir+'; git clone https://github.com/Tencent/rapidjson.git; cd rapidjson; mkdir build; cd build; ' + linuxCMake+' ../; make -j4; sudo make install)') # PyBind11 diff --git a/rocAL/CMakeLists.txt b/rocAL/CMakeLists.txt index 54edb201c..1dc4630e1 100644 --- a/rocAL/CMakeLists.txt +++ b/rocAL/CMakeLists.txt @@ -35,12 +35,12 @@ find_package(Protobuf QUIET) find_package(FFmpeg QUIET) find_package(OpenCV QUIET) find_package(OpenMP QUIET) -set(BOOST_COMPONENTS filesystem system) -find_package(Boost COMPONENTS ${BOOST_COMPONENTS} QUIET) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads QUIET) find_package(LMDB QUIET) find_package(RapidJSON QUIET) +find_package(StdFilesystem QUIET) +find_package(HALF QUIET) # HIP Backend if(GPU_SUPPORT AND "${BACKEND}" STREQUAL "HIP") @@ -160,11 +160,6 @@ if(NOT OpenMP_FOUND) set(BUILD_ROCAL false) message("-- ${Yellow}NOTE: rocAL library requires OpenMP, Not Found ${ColourReset}") endif() -# BOOST -if(NOT Boost_FOUND) - set(BUILD_ROCAL false) - message("-- ${Yellow}NOTE: rocAL library requires Boost, Not Found ${ColourReset}") -endif() # Threads if(NOT Threads_FOUND) set(BUILD_ROCAL false) @@ -178,6 +173,14 @@ if(NOT RapidJSON_FOUND) set(BUILD_ROCAL false) message("-- ${Yellow}NOTE: rocAL library requires RapidJSON, Not Found ${ColourReset}") endif() +if(NOT FILESYSTEM_FOUND) + set(BUILD_ROCAL false) + message("-- ${Yellow}NOTE: rocAL library requires FileSystem, Not Found ${ColourReset}") +endif() +if(NOT HALF_FOUND) + set(BUILD_ROCAL false) + message("-- ${Yellow}NOTE: rocAL library requires HALF, Not Found ${ColourReset}") +endif() if(${BUILD_ROCAL}) # AMD RPP @@ -192,9 +195,6 @@ if(${BUILD_ROCAL}) set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} OpenMP::OpenMP_CXX) # Threads set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} Threads::Threads) - # BOOST - include_directories(${Boost_INCLUDE_DIRS}) - set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) # TurboJPEG include_directories(${TurboJpeg_INCLUDE_DIRS}) set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${TurboJpeg_LIBRARIES}) @@ -206,6 +206,11 @@ if(${BUILD_ROCAL}) set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${LMDB_LIBRARIES}) # RapidJSON include_directories(${RapidJSON_INCLUDE_DIRS}) + # Filesystem + include_directories(${FILESYSTEM_INCLUDE_DIRS}) + set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${FILESYSTEM_LIBRARIES}) + # half + include_directories(${HALF_INCLUDE_DIRS}) # rocAL uses C++ 17 features set(CMAKE_CXX_STANDARD 17) @@ -293,7 +298,14 @@ if(${BUILD_ROCAL}) message("-- ${White}rocAL built with FFmpeg Video Decode Functionality${ColourReset}") target_compile_definitions(${PROJECT_NAME} PUBLIC -DROCAL_VIDEO) endif() - + # Filesystem + if(STD_FILESYSTEM_PRESENT) + message("-- ${White}rocAL built with std Filesystem${ColourReset}") + elseif(EXPERIMENTAL_FILESYSTEM_PRESENT) + message("-- ${White}rocAL built with std experimental Filesystem${ColourReset}") + else() + message(FATAL_ERROR "No filesystem library found.") + endif() # -Wall -- Enable most warning messages # -mavx2 -- Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 built-in functions and code generation # -mfma -- Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and FMA built-in functions and code generation diff --git a/rocAL/include/api/rocal_api_data_loaders.h b/rocAL/include/api/rocal_api_data_loaders.h index 626465e16..a1f477f72 100644 --- a/rocAL/include/api/rocal_api_data_loaders.h +++ b/rocAL/include/api/rocal_api_data_loaders.h @@ -846,5 +846,28 @@ extern "C" RocalTensor ROCAL_API_CALL rocalJpegCaffe2LMDBRecordSourcePartialSing bool loop = false, RocalImageSizeEvaluationPolicy decode_size_policy = ROCAL_USE_MOST_FREQUENT_SIZE, unsigned max_width = 0, unsigned max_height = 0); +/*! \brief Creates JPEG external source image reader. + * \ingroup group_rocal_data_loaders + * \param [in] rocal_context Rocal context + * \param [in] rocal_color_format The color format the images will be decoded to. + * \param [in] is_output Determines if the user wants the loaded images to be part of the output or not. + * \param [in] shuffle Determines if the user wants to shuffle the dataset or not. + * \param [in] loop Determines if the user wants to indefinitely loops through images or not. + * \param [in] decode_size_policy is the RocalImageSizeEvaluationPolicy for decoding + * \param [in] max_width The maximum width of the decoded images, larger or smaller will be resized to closest + * \param [in] max_height The maximum height of the decoded images, larger or smaller will be resized to closest + * \param [in] rocal_decoder_type Determines the decoder_type, tjpeg or hwdec + * \param [in] external_source_mode Determines the mode of the source passed from the user - file_names / uncompressed data / compressed data + * \return Reference to the output tensor + */ +extern "C" RocalTensor ROCAL_API_CALL rocalJpegExternalFileSource(RocalContext p_context, + RocalImageColor rocal_color_format, + bool is_output = false, + bool shuffle = false, + bool loop = false, + RocalImageSizeEvaluationPolicy decode_size_policy = ROCAL_USE_MOST_FREQUENT_SIZE, + unsigned max_width = 0, unsigned max_height = 0, + RocalDecoderType rocal_decoder_type = RocalDecoderType::ROCAL_DECODER_TJPEG, + RocalExternalSourceMode external_source_mode = RocalExternalSourceMode::ROCAL_EXTSOURCE_FNAME); #endif // MIVISIONX_ROCAL_API_DATA_LOADERS_H diff --git a/rocAL/include/api/rocal_api_data_transfer.h b/rocAL/include/api/rocal_api_data_transfer.h index 621c714aa..966ee6bdf 100644 --- a/rocAL/include/api/rocal_api_data_transfer.h +++ b/rocAL/include/api/rocal_api_data_transfer.h @@ -82,4 +82,26 @@ extern "C" void ROCAL_API_CALL rocalSetOutputs(RocalContext p_context, unsigned */ extern "C" RocalTensorList ROCAL_API_CALL rocalGetOutputTensors(RocalContext p_context); +/*! + * \brief Creates ExternalSourceFeedInput for data transfer + * \ingroup group_rocal_data_transfer + * \param rocal_context Rocal context + * \param input_images Strings pointing to the location on the disk + * \param labels Labels whose values is passed by the user using an external source + * \param input_buffer Compressed or uncompressed input buffer + * \param roi_width The roi width of the images + * \param roi_height The roi height of the images + * \param max_width The maximum width of the decoded images, larger or smaller will be resized to closest + * \param max_height The maximum height of the decoded images, larger or smaller will be resized to closest + * \param channels The number of channels for the image + * \param mode Determines the mode of the source passed from the user - file_names / uncompressed data / compressed data + * \param layout Determines the layout of the images - NCHW / NHWC + * \return Reference to the output tensor + */ +extern "C" RocalStatus ROCAL_API_CALL rocalExternalSourceFeedInput(RocalContext p_context, const std::vector& input_images_names, + bool is_labels, const std::vector& input_buffer, + const std::vector& roi_xywh, + unsigned int max_width, unsigned int max_height, unsigned int channels, + RocalExternalSourceMode mode, RocalTensorLayout layout, bool eos); + #endif // MIVISIONX_ROCAL_API_DATA_TRANSFER_H diff --git a/rocAL/include/api/rocal_api_tensor.h b/rocAL/include/api/rocal_api_tensor.h index a7075233b..5faf0e0ee 100644 --- a/rocAL/include/api/rocal_api_tensor.h +++ b/rocAL/include/api/rocal_api_tensor.h @@ -52,6 +52,8 @@ class rocalTensor { virtual size_t get_roi_dims_size() = 0; virtual void copy_roi(void* roi_buffer) = 0; virtual std::vector shape() = 0; + virtual void set_dims(std::vector dims) = 0; + virtual void set_mem_handle(void* buffer) = 0; }; /*! diff --git a/rocAL/include/api/rocal_api_types.h b/rocAL/include/api/rocal_api_types.h index 2a3553386..eed98519a 100644 --- a/rocAL/include/api/rocal_api_types.h +++ b/rocAL/include/api/rocal_api_types.h @@ -99,6 +99,13 @@ struct RocalJointsData { RotationBatch rotation_batch; }; +struct ROIxywh { + unsigned x; + unsigned y; + unsigned w; + unsigned h; +}; + /*! \brief rocAL Status enum * \ingroup group_rocal_types */ @@ -356,6 +363,21 @@ enum class RocalROICordsType { ROCAL_XYWH = 1 }; +/*! \brief RocalExternalSourceMode struct + * \ingroup group_rocal_types + */ +enum RocalExternalSourceMode { + /*! \brief list of filename passed as input + */ + ROCAL_EXTSOURCE_FNAME = 0, + /*! \brief compressed raw buffer passed as input + */ + ROCAL_EXTSOURCE_RAW_COMPRESSED = 1, + /*! \brief uncompressed raw buffer passed as input + */ + ROCAL_EXTSOURCE_RAW_UNCOMPRESSED = 2, +}; + /*! \brief Tensor padding types * \ingroup group_rocal_types */ diff --git a/rocAL/include/loaders/image/cifar10_data_loader.h b/rocAL/include/loaders/image/cifar10_data_loader.h index eb20035c3..9736b6dfc 100644 --- a/rocAL/include/loaders/image/cifar10_data_loader.h +++ b/rocAL/include/loaders/image/cifar10_data_loader.h @@ -47,6 +47,8 @@ class CIFAR10DataLoader : public LoaderModule { void shut_down() override; std::vector> &get_batch_random_bbox_crop_coords(); void set_batch_random_bbox_crop_coords(std::vector> batch_crop_coords); + void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) override {} private: void increment_loader_idx(); diff --git a/rocAL/include/loaders/image/image_loader.h b/rocAL/include/loaders/image/image_loader.h index 5fc41a02c..082bf2015 100644 --- a/rocAL/include/loaders/image/image_loader.h +++ b/rocAL/include/loaders/image/image_loader.h @@ -53,6 +53,8 @@ class ImageLoader : public LoaderModule { crop_image_info get_crop_image_info() override; void set_prefetch_queue_depth(size_t prefetch_queue_depth) override; void shut_down() override; + void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) override; private: bool is_out_of_data(); @@ -87,4 +89,6 @@ class ImageLoader : public LoaderModule { bool _decoder_keep_original = false; int _device_id; size_t _max_tensor_width, _max_tensor_height; + bool _external_source_reader = false; //!< Set to true if external source reader + bool _external_input_eos = false; //!< Set to true for last batch for the sequence }; diff --git a/rocAL/include/loaders/image/image_loader_sharded.h b/rocAL/include/loaders/image/image_loader_sharded.h index 1c2fe35d4..3b7bdf998 100644 --- a/rocAL/include/loaders/image/image_loader_sharded.h +++ b/rocAL/include/loaders/image/image_loader_sharded.h @@ -45,6 +45,8 @@ class ImageLoaderSharded : public LoaderModule { Timing timing() override; void set_prefetch_queue_depth(size_t prefetch_queue_depth) override; void shut_down() override; + void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) override; private: void increment_loader_idx(); diff --git a/rocAL/include/loaders/image/image_read_and_decode.h b/rocAL/include/loaders/image/image_read_and_decode.h index 740978e87..471164b54 100644 --- a/rocAL/include/loaders/image/image_read_and_decode.h +++ b/rocAL/include/loaders/image/image_read_and_decode.h @@ -53,7 +53,8 @@ class ImageReadAndDecode { void set_random_bbox_data_reader(std::shared_ptr randombboxcrop_meta_data_reader); std::vector> &get_batch_random_bbox_crop_coords(); void set_batch_random_bbox_crop_coords(std::vector> batch_crop_coords); - + void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos); //! Loads a decompressed batch of images into the buffer indicated by buff /// \param buff User's buffer provided to be filled with decoded image samples /// \param names User's buffer provided to be filled with name of the images decoded @@ -98,4 +99,5 @@ class ImageReadAndDecode { std::shared_ptr _randombboxcrop_meta_data_reader = nullptr; pCropCord _CropCord; RocalRandomCropDecParam *_random_crop_dec_param = nullptr; + bool _is_external_source = false; }; diff --git a/rocAL/include/loaders/image/node_image_loader.h b/rocAL/include/loaders/image/node_image_loader.h index ff18d205b..df4edb02b 100644 --- a/rocAL/include/loaders/image/node_image_loader.h +++ b/rocAL/include/loaders/image/node_image_loader.h @@ -40,7 +40,7 @@ class ImageLoaderNode : public Node { /// The loader will repeat images if necessary to be able to have images in multiples of the load_batch_count, /// for example if there are 10 images in the dataset and load_batch_count is 3, the loader repeats 2 images as if there are 12 images available. void init(unsigned internal_shard_count, unsigned cpu_num_threads, const std::string &source_path, const std::string &json_path, const std::map feature_key_map, StorageType storage_type, DecoderType decoder_type, bool shuffle, bool loop, - size_t load_batch_count, RocalMemType mem_type, std::shared_ptr meta_data_reader, bool decoder_keep_orig = false, const char *prefix = "", unsigned sequence_length = 0, unsigned step = 0, unsigned stride = 0); + size_t load_batch_count, RocalMemType mem_type, std::shared_ptr meta_data_reader, bool decoder_keep_orig = false, const char *prefix = "", unsigned sequence_length = 0, unsigned step = 0, unsigned stride = 0, ExternalSourceFileMode external_file_mode = ExternalSourceFileMode::NONE); std::shared_ptr get_loader_module(); diff --git a/rocAL/include/loaders/image/node_image_loader_single_shard.h b/rocAL/include/loaders/image/node_image_loader_single_shard.h index 8a3b717f8..133dbeb27 100644 --- a/rocAL/include/loaders/image/node_image_loader_single_shard.h +++ b/rocAL/include/loaders/image/node_image_loader_single_shard.h @@ -38,7 +38,7 @@ class ImageLoaderSingleShardNode : public Node { /// for example if there are 10 images in the dataset and load_batch_count is 3, the loader repeats 2 images as if there are 12 images available. void init(unsigned shard_id, unsigned shard_count, unsigned cpu_num_threads, const std::string &source_path, const std::string &json_path, StorageType storage_type, DecoderType decoder_type, bool shuffle, bool loop, size_t load_batch_count, RocalMemType mem_type, std::shared_ptr meta_data_reader, bool decoder_keep_orig = false, - const std::map feature_key_map = std::map(), unsigned sequence_length = 0, unsigned step = 0, unsigned stride = 0); + const std::map feature_key_map = std::map(), unsigned sequence_length = 0, unsigned step = 0, unsigned stride = 0, ExternalSourceFileMode external_file_mode = ExternalSourceFileMode::NONE); std::shared_ptr get_loader_module(); diff --git a/rocAL/include/loaders/loader_module.h b/rocAL/include/loaders/loader_module.h index e962d6012..4d4531a52 100644 --- a/rocAL/include/loaders/loader_module.h +++ b/rocAL/include/loaders/loader_module.h @@ -61,6 +61,10 @@ class LoaderModule { virtual void shut_down() = 0; virtual std::vector get_sequence_start_frame_number() { return {}; } virtual std::vector> get_sequence_frame_timestamps() { return {}; } + // External Source reader + virtual void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, + unsigned int channels, ExternalSourceFileMode mode, bool eos) = 0; }; using pLoaderModule = std::shared_ptr; \ No newline at end of file diff --git a/rocAL/include/loaders/video/video_loader.h b/rocAL/include/loaders/video/video_loader.h index 6e991e78d..4ff85f11c 100644 --- a/rocAL/include/loaders/video/video_loader.h +++ b/rocAL/include/loaders/video/video_loader.h @@ -56,6 +56,8 @@ class VideoLoader : public LoaderModule { std::vector get_sequence_start_frame_number() override; std::vector> get_sequence_frame_timestamps() override; void shut_down() override; + void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) override {} private: bool is_out_of_data(); diff --git a/rocAL/include/loaders/video/video_loader_sharded.h b/rocAL/include/loaders/video/video_loader_sharded.h index 1349cbcbe..41cd062a6 100644 --- a/rocAL/include/loaders/video/video_loader_sharded.h +++ b/rocAL/include/loaders/video/video_loader_sharded.h @@ -48,6 +48,8 @@ class VideoLoaderSharded : public LoaderModule { std::vector get_sequence_start_frame_number() override; std::vector> get_sequence_frame_timestamps() override; Timing timing() override; + void feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) override {} private: void increment_loader_idx(); diff --git a/rocAL/include/loaders/video/video_read_and_decode.h b/rocAL/include/loaders/video/video_read_and_decode.h index 2cc20a393..77748c4c1 100644 --- a/rocAL/include/loaders/video/video_read_and_decode.h +++ b/rocAL/include/loaders/video/video_read_and_decode.h @@ -28,7 +28,6 @@ THE SOFTWARE. #include #include #include -#include #include "commons.h" #include "ffmpeg_video_decoder.h" #include "video_reader_factory.h" @@ -36,6 +35,7 @@ THE SOFTWARE. #include "loader_module.h" #include "video_properties.h" #include "video_reader.h" +#include "filesystem.h" #ifdef ROCAL_VIDEO extern "C" { @@ -111,4 +111,4 @@ class VideoReadAndDecode { AVPixelFormat _out_pix_fmt; DecoderConfig _video_decoder_config; }; -#endif +#endif \ No newline at end of file diff --git a/rocAL/include/pipeline/commons.h b/rocAL/include/pipeline/commons.h index 933959a32..03bdd5f12 100644 --- a/rocAL/include/pipeline/commons.h +++ b/rocAL/include/pipeline/commons.h @@ -32,6 +32,7 @@ THE SOFTWARE. #include "exception.h" #include "log.h" +#include "filesystem.h" // Calculated from the largest resize shorter dimension in imagenet validation dataset #define MAX_ASPECT_RATIO 6.0f @@ -160,4 +161,7 @@ struct Timing { long long unsigned label_load_time = 0; long long unsigned bb_load_time = 0; long long unsigned mask_load_time = 0; + long long unsigned video_read_time= 0; + long long unsigned video_decode_time= 0; + long long unsigned video_process_time= 0; }; diff --git a/rocAL/include/pipeline/filesystem.h b/rocAL/include/pipeline/filesystem.h new file mode 100644 index 000000000..78be6f835 --- /dev/null +++ b/rocAL/include/pipeline/filesystem.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 2019 - 2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#pragma once +#if __cplusplus >= 201703L && __has_include() + #include + namespace filesys = std::filesystem; +#elif __has_include() + #include + namespace filesys = std::experimental::filesystem; +#else + #error "No filesystem support available" +#endif diff --git a/rocAL/include/pipeline/master_graph.h b/rocAL/include/pipeline/master_graph.h index 227a859f8..d0cf50ab1 100644 --- a/rocAL/include/pipeline/master_graph.h +++ b/rocAL/include/pipeline/master_graph.h @@ -136,6 +136,10 @@ class MasterGraph { void set_sequence_reader_output() { _is_sequence_reader_output = true; } void set_sequence_batch_size(size_t sequence_length) { _sequence_batch_size = _user_batch_size * sequence_length; } std::vector get_bbox_encoded_buffers(size_t num_encoded_boxes); + void feed_external_input(const std::vector& input_images_names, bool labels, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, + RocalTensorlayout layout, bool eos); + void set_external_source_reader_flag() { _external_source_reader = true; } size_t bounding_box_batch_count(pMetaDataBatch meta_data_batch); Tensor* roi_random_crop(Tensor *input, Tensor *roi_start, Tensor *roi_end, int *crop_shape); TensorList* random_object_bbox(Tensor *input, std::string output_format, int k_largest = -1, float foreground_prob=1.0); @@ -233,6 +237,8 @@ class MasterGraph { bool _offset; // Returns normalized offsets ((encoded_bboxes*scale - anchors*scale) - mean) / stds in EncodedBBoxes that use std and the mean and scale arguments if offset="True" std::vector _means, _stds; //_means: [x y w h] mean values for normalization _stds: [x y w h] standard deviations for offset normalization. bool _augmentation_metanode = false; + bool _external_source_eos = false; // If last batch, _external_source_eos will true + bool _external_source_reader = false; // Set to true if external source reader on // box IoU matcher variables bool _is_box_iou_matcher = false; // bool variable to set the box iou matcher BoxIouMatcherInfo _iou_matcher_info; diff --git a/rocAL/include/pipeline/tensor.h b/rocAL/include/pipeline/tensor.h index 26689e03f..a8cde5e3c 100644 --- a/rocAL/include/pipeline/tensor.h +++ b/rocAL/include/pipeline/tensor.h @@ -344,7 +344,13 @@ class Tensor : public rocalTensor { void* buffer() { return _mem_handle; } vx_tensor handle() { return _vx_handle; } vx_context context() { return _context; } - void set_mem_handle(void* buffer) { _mem_handle = buffer; } + void set_mem_handle(void* buffer) override { + if (buffer) + _mem_handle = buffer; + else { + THROW("Invalid buffer pointer passed") + } + } #if ENABLE_OPENCL unsigned copy_data(cl_command_queue queue, unsigned char* user_buffer, bool sync); unsigned copy_data(cl_command_queue queue, cl_mem user_buffer, bool sync); @@ -373,7 +379,7 @@ class Tensor : public rocalTensor { int create_from_ptr(vx_context context, void *ptr); int create_virtual(vx_context context, vx_graph graph); bool is_handle_set() { return (_vx_handle != 0); } - void set_dims(std::vector dims) { _info.set_dims(dims); } + void set_dims(std::vector dims) override { _info.set_dims(dims); } void set_layout(RocalTensorlayout layout) { _info.set_tensor_layout(layout); } unsigned num_of_dims() override { return _info.num_of_dims(); } unsigned batch_size() override { return _info.batch_size(); } diff --git a/rocAL/include/readers/image/external_source.h b/rocAL/include/readers/image/external_source.h new file mode 100644 index 000000000..cc542e927 --- /dev/null +++ b/rocAL/include/readers/image/external_source.h @@ -0,0 +1,28 @@ +#include + +// ExternalSourceImageInfo struct - used to pass the image info needed for external source input. +struct ExternalSourceImageInfo { + unsigned char* file_data; // Pointer to the file data + size_t file_read_size; // Total file size + unsigned int width; // Width of the image + unsigned int height; // Height of the image + unsigned int channels; // Number of image channels + unsigned roi_width; // ROI width of the image + unsigned roi_height; // ROI height of the image +}; + + +class ExternalSourceImageReader { + public: + enum class Status { + OK = 0 + }; + + //! Feeds file names as an external_source into the reader + virtual void feed_file_names(const std::vector &file_names, size_t num_images, bool eos = false) = 0; + + //! Used for feeding raw data into the reader (mode specified compressed jpegs or raw) + virtual void feed_data(const std::vector &images, const std::vector &image_size, ExternalSourceFileMode mode, bool eos = false, const std::vector roi_width = {}, const std::vector roi_height = {}, unsigned int width = 0, unsigned int height = 0, unsigned int channels = 0) = 0; + + virtual ~ExternalSourceImageReader() = default; +}; diff --git a/rocAL/include/readers/image/external_source_reader.h b/rocAL/include/readers/image/external_source_reader.h new file mode 100644 index 000000000..9864ed71b --- /dev/null +++ b/rocAL/include/readers/image/external_source_reader.h @@ -0,0 +1,119 @@ +/* +Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include +#include +#include +#include +#include + +#include "commons.h" +#include "image_reader.h" +#include "external_source.h" +#include "timing_debug.h" +#include "filesystem.h" + +class ExternalSourceReader : public Reader, public ExternalSourceImageReader { + public: + //! Looks up the folder which contains the files, amd loads the image names + /*! + \param desc User provided descriptor containing the files' path. + */ + Reader::Status initialize(ReaderConfig desc) override; + //! Reads the next resource item + /*! + \param buf User's provided buffer to receive the loaded images + \return Size of the loaded resource + */ + size_t read_data(unsigned char* buf, size_t max_size) override; + //! Opens the next file in the folder + /*! + \return The size of the next file, 0 if couldn't access it + */ + size_t open() override; + + //! Resets the object's state to read from the first file in the list + void reset() override; + + //! Returns the name of the latest file opened + std::string id() override { return _last_id; } + + //! Return batch_size() for count_items unless end_of_sequence has been signalled + unsigned count_items() override; + + ~ExternalSourceReader() override; + + int close() override; + + ExternalSourceReader(); + + //! receive next set of filenames from external source + void feed_file_names(const std::vector& file_names, size_t num_images, bool eos = false) override; + + //! receive next set of file data from external source + void feed_data(const std::vector& images, const std::vector& image_size, ExternalSourceFileMode mode, bool eos = false, const std::vector roi_width = {}, const std::vector roi_height = {}, unsigned int width = 0, unsigned int height = 0, unsigned int channels = 0) override; + + // mode(): returs the mode for the reader + ExternalSourceFileMode mode() { return _file_mode; } + + // get image_dims + void get_dims(int cur_idx, int& width, int& height, int& channels, unsigned& roi_width, unsigned& roi_height); + + private: + //! opens the folder containnig the images + std::string _folder_path; + std::queue _file_names_queue; + std::vector _file_data; + std::queue _images_data_queue; + std::mutex _lock; + std::condition_variable _wait_for_input; + + unsigned _curr_file_idx; + FILE* _current_fPtr; + unsigned _current_file_size; + std::string _last_id; + size_t _shard_id = 0; + size_t _shard_count = 1; // equivalent of batch size + //!< _batch_count Defines the quantum count of the images to be read. It's usually equal to the user's batch size. + /// The loader will repeat images if necessary to be able to have images available in multiples of the load_batch_count, + /// for instance if there are 10 images in the dataset and _batch_count is 3, the loader repeats 2 images as if there are 12 images available. + size_t _batch_count = 1; + size_t _file_id = 0; + bool _loop; + bool _shuffle; + int _read_counter = 0; + volatile bool _end_of_sequence; + ExternalSourceFileMode _file_mode; + //!< _file_count_all_shards total_number of files in to figure out the max_batch_size (usually needed for distributed training). + size_t _file_count_all_shards; + void push_file_name(const std::string& image_name); + bool pop_file_name(std::string& file_name); + void push_file_data(ExternalSourceImageInfo& image); + bool pop_file_data(ExternalSourceImageInfo& image); + void increment_read_ptr(); + int release(); + size_t get_file_shard_id(); + void increment_file_id() { _file_id++; } + void replicate_last_image_to_fill_last_shard(); + void replicate_last_batch_to_pad_partial_shard(); +}; diff --git a/rocAL/include/readers/image/image_reader.h b/rocAL/include/readers/image/image_reader.h index 75e44ff8a..1e2491a5c 100644 --- a/rocAL/include/readers/image/image_reader.h +++ b/rocAL/include/readers/image/image_reader.h @@ -45,10 +45,18 @@ enum class StorageType { CAFFE_LMDB_RECORD = 3, CAFFE2_LMDB_RECORD = 4, COCO_FILE_SYSTEM = 5, - MXNET_RECORDIO = 6, - VIDEO_FILE_SYSTEM = 7, - SEQUENCE_FILE_SYSTEM = 8, - NUMPY_DATA = 9 + SEQUENCE_FILE_SYSTEM = 6, + MXNET_RECORDIO = 7, + VIDEO_FILE_SYSTEM = 8, + EXTERNAL_FILE_SOURCE = 9, // to support reading from external source + NUMPY_DATA = 10 +}; + +enum class ExternalSourceFileMode { + FILENAME = 0, + RAWDATA_COMPRESSED = 1, + RAWDATA_UNCOMPRESSED = 2, + NONE = 3, }; struct ReaderConfig { @@ -73,6 +81,7 @@ struct ReaderConfig { void set_sequence_length(unsigned sequence_length) { _sequence_length = sequence_length; } void set_frame_step(unsigned step) { _sequence_frame_step = step; } void set_frame_stride(unsigned stride) { _sequence_frame_stride = stride; } + void set_external_filemode(ExternalSourceFileMode mode) { _file_mode = mode; } void set_files(const std::vector &files) { _files = files; } void set_seed(unsigned seed) { _seed = seed; } size_t get_shard_count() { return _shard_count; } @@ -94,6 +103,7 @@ struct ReaderConfig { void set_file_prefix(const std::string &prefix) { _file_prefix = prefix; } std::string file_prefix() { return _file_prefix; } std::shared_ptr meta_data_reader() { return _meta_data_reader; } + ExternalSourceFileMode mode() { return _file_mode; } private: StorageType _type = StorageType::FILE_SYSTEM; @@ -111,6 +121,7 @@ struct ReaderConfig { bool _loop = false; std::string _file_prefix = ""; //!< to read only files with prefix. supported only for cifar10_data_reader and tf_record_reader std::shared_ptr _meta_data_reader = nullptr; + ExternalSourceFileMode _file_mode = ExternalSourceFileMode::NONE; std::vector _files; unsigned _seed = 0; #ifdef ROCAL_VIDEO diff --git a/rocAL/include/readers/video/video_properties.h b/rocAL/include/readers/video/video_properties.h index ab5d22f60..e92790def 100644 --- a/rocAL/include/readers/video/video_properties.h +++ b/rocAL/include/readers/video/video_properties.h @@ -23,7 +23,6 @@ THE SOFTWARE. #pragma once #include -#include #include #include #include @@ -36,8 +35,6 @@ extern "C" { #endif #include "commons.h" -namespace filesys = boost::filesystem; - #ifdef ROCAL_VIDEO typedef struct VideoProperties { unsigned width, height, videos_count; diff --git a/rocAL/rocAL_hip/CMakeLists.txt b/rocAL/rocAL_hip/CMakeLists.txt index 863bf1d56..5f89c2f72 100644 --- a/rocAL/rocAL_hip/CMakeLists.txt +++ b/rocAL/rocAL_hip/CMakeLists.txt @@ -28,7 +28,7 @@ list(APPEND rocAL_HIP_SOURCES set_source_files_properties(${rocAL_HIP_SOURCES} PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1) -set(HIP_CXX_FLAGS -std=gnu++14) +set(HIP_CXX_FLAGS -std=gnu++17) set(COMPILER_FOR_HIP ${ROCM_PATH}/llvm/bin/clang++) set(CMAKE_CXX_COMPILER ${COMPILER_FOR_HIP}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${HIP_CXX_FLAGS}") diff --git a/rocAL/source/api/rocal_api_data_loaders.cpp b/rocAL/source/api/rocal_api_data_loaders.cpp index 6f11c2a92..5c5ca3b32 100644 --- a/rocAL/source/api/rocal_api_data_loaders.cpp +++ b/rocAL/source/api/rocal_api_data_loaders.cpp @@ -21,9 +21,6 @@ THE SOFTWARE. */ #include - -#include -#include #ifdef ROCAL_VIDEO #include "node_video_loader.h" #include "node_video_loader_single_shard.h" @@ -42,8 +39,6 @@ THE SOFTWARE. #include "node_resize.h" #include "rocal_api.h" -namespace filesys = boost::filesystem; - std::tuple evaluate_image_data_set(RocalImageSizeEvaluationPolicy decode_size_policy, StorageType storage_type, DecoderType decoder_type, const std::string& source_path, const std::string& json_path) { @@ -1443,7 +1438,7 @@ rocalRawTFRecordSource( output = context->master_graph->create_loader_output_tensor(info); auto cpu_num_threads = context->master_graph->calculate_cpu_num_threads(1); - context->master_graph->add_node({}, {output})->init(internal_shard_count, cpu_num_threads, source_path, "", feature_key_map, StorageType::TF_RECORD, DecoderType::SKIP_DECODE, shuffle, loop, context->user_batch_size(), context->master_graph->mem_type(), context->master_graph->meta_data_reader(), false, record_name_prefix); + context->master_graph->add_node({}, {output})->init(internal_shard_count, cpu_num_threads, source_path, "", feature_key_map, StorageType::TF_RECORD, DecoderType::SKIP_DECODE, shuffle, loop, context->user_batch_size(), context->master_graph->mem_type(), context->master_graph->meta_data_reader(), false, record_name_prefix, 0, 0, 0); context->master_graph->set_loop(loop); if (is_output) { @@ -2181,6 +2176,65 @@ rocalRawCIFAR10Source( return output; } +RocalTensor ROCAL_API_CALL +rocalJpegExternalFileSource( + RocalContext p_context, + RocalImageColor rocal_color_format, + bool is_output, + bool shuffle, + bool loop, + RocalImageSizeEvaluationPolicy decode_size_policy, + unsigned max_width, + unsigned max_height, + RocalDecoderType dec_type, + RocalExternalSourceMode external_source_mode) { + Tensor* output = nullptr; + auto context = static_cast(p_context); + try { + bool decoder_keep_original = (decode_size_policy == ROCAL_USE_USER_GIVEN_SIZE_RESTRICTED) || (decode_size_policy == ROCAL_USE_MAX_SIZE_RESTRICTED); + DecoderType decType = DecoderType::TURBO_JPEG; // default + if (dec_type == ROCAL_DECODER_OPENCV) decType = DecoderType::OPENCV_DEC; + if ((decode_size_policy == ROCAL_USE_MAX_SIZE) || (decode_size_policy == ROCAL_USE_MAX_SIZE_RESTRICTED)) + THROW("use_max_size is not supported in external source reader"); + + // user need to specify this + if (max_width == 0 || max_height == 0) { + THROW("Invalid input max width and height"); + } else { + LOG("User input size " + TOSTR(max_width) + " x " + TOSTR(max_height)) + } + + auto [width, height] = std::make_tuple(max_width, max_height); + auto [color_format, tensor_layout, dims, num_of_planes] = convert_color_format(rocal_color_format, context->user_batch_size(), height, width); + INFO("Internal buffer size width = " + TOSTR(width) + " height = " + TOSTR(height) + " depth = " + TOSTR(num_of_planes)) + + auto info = TensorInfo(std::move(dims), + context->master_graph->mem_type(), + RocalTensorDataType::UINT8, + tensor_layout, + color_format); + output = context->master_graph->create_loader_output_tensor(info); + context->master_graph->set_external_source_reader_flag(); + + unsigned shard_count = 1; // Hardcoding the shard count to 1 for now. + auto cpu_num_threads = context->master_graph->calculate_cpu_num_threads(shard_count); + context->master_graph->add_node({}, {output})->init(shard_count, cpu_num_threads, "", "", std::map(), StorageType::EXTERNAL_FILE_SOURCE, + decType, shuffle, loop, context->user_batch_size(), context->master_graph->mem_type(), context->master_graph->meta_data_reader(), + decoder_keep_original, "", 0, 0, 0, ExternalSourceFileMode(external_source_mode)); + context->master_graph->set_loop(loop); + + if (is_output) { + auto actual_output = context->master_graph->create_tensor(info, is_output); + context->master_graph->add_node({output}, {actual_output}); + } + + } catch (const std::exception& e) { + context->capture_error(e.what()); + std::cerr << e.what() << '\n'; + } + return output; +} + RocalStatus ROCAL_API_CALL rocalResetLoaders(RocalContext p_context) { auto context = static_cast(p_context); diff --git a/rocAL/source/api/rocal_api_data_transfer.cpp b/rocAL/source/api/rocal_api_data_transfer.cpp index 4202de1a3..54f745af4 100644 --- a/rocAL/source/api/rocal_api_data_transfer.cpp +++ b/rocAL/source/api/rocal_api_data_transfer.cpp @@ -79,6 +79,34 @@ void } } +RocalStatus ROCAL_API_CALL +rocalExternalSourceFeedInput( + RocalContext p_context, + const std::vector& input_images_names, + bool is_labels, + const std::vector& input_buffer, + const std::vector& roi_xywh, + unsigned int max_width, + unsigned int max_height, + unsigned int channels, + RocalExternalSourceMode mode, + RocalTensorLayout layout, + bool eos) { + auto context = static_cast(p_context); + try { + ExternalSourceFileMode external_file_mode = static_cast(mode); + RocalTensorlayout format = static_cast(layout); + context->master_graph->feed_external_input(input_images_names, is_labels, input_buffer, + roi_xywh, max_width, max_height, channels, + external_file_mode, format, eos); + } catch (const std::exception& e) { + context->capture_error(e.what()); + ERR(e.what()) + return ROCAL_RUNTIME_ERROR; + } + return ROCAL_OK; +} + RocalTensorList ROCAL_API_CALL rocalGetOutputTensors(RocalContext p_context) { auto context = static_cast(p_context); diff --git a/rocAL/source/loaders/image/image_loader.cpp b/rocAL/source/loaders/image/image_loader.cpp index c007f32c4..00abf74cc 100644 --- a/rocAL/source/loaders/image/image_loader.cpp +++ b/rocAL/source/loaders/image/image_loader.cpp @@ -64,6 +64,13 @@ void ImageLoader::set_gpu_device_id(int device_id) { size_t ImageLoader::remaining_count() { + if (_external_source_reader) { + if ((_image_loader->count() != 0) && !_external_input_eos) + return _batch_size; + else { + return 0; + } + } return _remaining_image_count; } @@ -307,3 +314,9 @@ decoded_image_info ImageLoader::get_decode_image_info() { crop_image_info ImageLoader::get_crop_image_info() { return _output_cropped_img_info; } + +void ImageLoader::feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) { + _external_source_reader = true; + _external_input_eos = eos; + _image_loader->feed_external_input(input_images_names, input_buffer, roi_xywh, max_width, max_height, channels, mode, eos); +} diff --git a/rocAL/source/loaders/image/image_loader_sharded.cpp b/rocAL/source/loaders/image/image_loader_sharded.cpp index c8eb68dcb..02d7f05f0 100644 --- a/rocAL/source/loaders/image/image_loader_sharded.cpp +++ b/rocAL/source/loaders/image/image_loader_sharded.cpp @@ -161,3 +161,8 @@ Timing ImageLoaderSharded::timing() { t.process_time = swap_handle_time; return t; } + +void ImageLoaderSharded::feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) { + for (auto& loader : _loaders) + loader->feed_external_input(input_images_names, input_buffer, roi_xywh, max_width, max_height, channels, mode, eos); +} diff --git a/rocAL/source/loaders/image/image_read_and_decode.cpp b/rocAL/source/loaders/image/image_read_and_decode.cpp index bef05042c..8e7c68d9c 100644 --- a/rocAL/source/loaders/image/image_read_and_decode.cpp +++ b/rocAL/source/loaders/image/image_read_and_decode.cpp @@ -26,6 +26,7 @@ THE SOFTWARE. #include #include "decoder_factory.h" +#include "external_source_reader.h" std::tuple interpret_color_format(RocalColorFormat color_format) { @@ -92,6 +93,34 @@ void ImageReadAndDecode::create(ReaderConfig reader_config, DecoderConfig decode } _num_threads = reader_config.get_cpu_num_threads(); _reader = create_reader(reader_config); + _is_external_source = (reader_config.type() == StorageType::EXTERNAL_FILE_SOURCE); +} + +void ImageReadAndDecode::feed_external_input(const std::vector& input_images_names, const std::vector& input_buffer, + const std::vector& roi_xywh, + unsigned int max_width, unsigned int max_height, unsigned int channels, ExternalSourceFileMode mode, bool eos) { + std::vector image_size; + std::vector image_roi_w, image_roi_h; + image_size.reserve(roi_xywh.size()); + image_roi_w.resize(roi_xywh.size()); + image_roi_h.resize(roi_xywh.size()); + size_t max_image_size = max_width * max_height * channels; + for (unsigned int i = 0; i < roi_xywh.size(); i++) { + if (mode == ExternalSourceFileMode::RAWDATA_UNCOMPRESSED) { + image_size[i] = max_image_size; + image_roi_w[i] = roi_xywh[i].w; + image_roi_h[i] = roi_xywh[i].h; + } + else if (mode == ExternalSourceFileMode::RAWDATA_COMPRESSED) + image_size[i] = roi_xywh[i].h; + } + auto ext_reader = std::static_pointer_cast(_reader); + if (mode == ExternalSourceFileMode::FILENAME) + ext_reader->feed_file_names(input_images_names, input_images_names.size(), eos); + else if (mode == ExternalSourceFileMode::RAWDATA_COMPRESSED) + ext_reader->feed_data(input_buffer, image_size, mode, eos, {}, {}, max_width, max_height, channels); + else if (mode == ExternalSourceFileMode::RAWDATA_UNCOMPRESSED) + ext_reader->feed_data(input_buffer, image_size, mode, eos, image_roi_w, image_roi_h, max_width, max_height, channels); } void ImageReadAndDecode::reset() { @@ -142,7 +171,7 @@ ImageReadAndDecode::load(unsigned char *buff, const unsigned output_planes = std::get<1>(ret); const bool keep_original = decoder_keep_original; const size_t image_size = max_decoded_width * max_decoded_height * output_planes * sizeof(unsigned char); - + bool skip_decode = false; // Decode with the height and size equal to a single image // File read is done serially since I/O parallelization does not work very well. _file_load_time.start(); // Debug timing @@ -170,6 +199,50 @@ ImageReadAndDecode::load(unsigned char *buff, file_counter++; } //_file_load_time.end();// Debug timing + } else if (_is_external_source) { + auto ext_reader = std::static_pointer_cast(_reader); + if (ext_reader->mode() == ExternalSourceFileMode::RAWDATA_UNCOMPRESSED) { + while ((file_counter != _batch_size) && _reader->count_items() > 0) { + int width, height, channels; + unsigned rwidth, rheight; + auto read_ptr = buff + image_size * file_counter; + size_t fsize = _reader->open(); + if (fsize == 0) { + WRN("Opened file " + _reader->id() + " of size 0"); + continue; + } + + _actual_read_size[file_counter] = _reader->read_data(read_ptr, fsize); + if (_actual_read_size[file_counter] < fsize) + LOG("Reader read less than requested bytes of size: " + _actual_read_size[file_counter]); + + _image_names[file_counter] = _reader->id(); + ext_reader->get_dims(file_counter, width, height, channels, rwidth, rheight); + names[file_counter] = _image_names[file_counter]; + roi_width[file_counter] = rwidth; + roi_height[file_counter] = rheight; + actual_width[file_counter] = width; + actual_height[file_counter] = height; + _reader->close(); + file_counter++; + } + skip_decode = true; + } else { + while ((file_counter != _batch_size) && _reader->count_items() > 0) { + _reader->count_items(); + size_t fsize = _reader->open(); + if (fsize == 0) { + WRN("Opened file " + _reader->id() + " of size 0"); + continue; + } + _compressed_buff[file_counter].reserve(fsize); + _actual_read_size[file_counter] = _reader->read_data(_compressed_buff[file_counter].data(), fsize); + _image_names[file_counter] = _reader->id(); + _reader->close(); + _compressed_image_size[file_counter] = fsize; + file_counter++; + } + } // return LoaderModuleStatus::OK; } else { while ((file_counter != _batch_size) && _reader->count_items() > 0) { @@ -197,7 +270,7 @@ ImageReadAndDecode::load(unsigned char *buff, _file_load_time.end(); // Debug timing _decode_time.start(); // Debug timing - if (_decoder_config._type != DecoderType::SKIP_DECODE) { + if (!skip_decode) { for (size_t i = 0; i < _batch_size; i++) _decompressed_buff_ptrs[i] = buff + image_size * i; diff --git a/rocAL/source/loaders/image/node_image_loader.cpp b/rocAL/source/loaders/image/node_image_loader.cpp index ec138d3b5..4380e4c52 100644 --- a/rocAL/source/loaders/image/node_image_loader.cpp +++ b/rocAL/source/loaders/image/node_image_loader.cpp @@ -29,7 +29,7 @@ ImageLoaderNode::ImageLoaderNode(Tensor *output, void *device_resources) : Node( } void ImageLoaderNode::init(unsigned internal_shard_count, unsigned cpu_num_threads, const std::string &source_path, const std::string &json_path, const std::map feature_key_map, StorageType storage_type, DecoderType decoder_type, bool shuffle, bool loop, - size_t load_batch_count, RocalMemType mem_type, std::shared_ptr meta_data_reader, bool decoder_keep_orig, const char *file_prefix, unsigned sequence_length, unsigned step, unsigned stride) { + size_t load_batch_count, RocalMemType mem_type, std::shared_ptr meta_data_reader, bool decoder_keep_orig, const char *file_prefix, unsigned sequence_length, unsigned step, unsigned stride, ExternalSourceFileMode external_file_mode) { if (!_loader_module) THROW("ERROR: loader module is not set for ImageLoaderNode, cannot initialize") if (internal_shard_count < 1) @@ -46,6 +46,7 @@ void ImageLoaderNode::init(unsigned internal_shard_count, unsigned cpu_num_threa reader_cfg.set_sequence_length(sequence_length); reader_cfg.set_frame_step(step); reader_cfg.set_frame_stride(stride); + reader_cfg.set_external_filemode(external_file_mode); _loader_module->initialize(reader_cfg, DecoderConfig(decoder_type), mem_type, _batch_size, decoder_keep_orig); diff --git a/rocAL/source/loaders/image/node_image_loader_single_shard.cpp b/rocAL/source/loaders/image/node_image_loader_single_shard.cpp index eece62af2..d4bcab537 100644 --- a/rocAL/source/loaders/image/node_image_loader_single_shard.cpp +++ b/rocAL/source/loaders/image/node_image_loader_single_shard.cpp @@ -30,7 +30,7 @@ ImageLoaderSingleShardNode::ImageLoaderSingleShardNode(Tensor *output, void *dev void ImageLoaderSingleShardNode::init(unsigned shard_id, unsigned shard_count, unsigned cpu_num_threads, const std::string &source_path, const std::string &json_path, StorageType storage_type, DecoderType decoder_type, bool shuffle, bool loop, size_t load_batch_count, RocalMemType mem_type, std::shared_ptr meta_data_reader, - bool decoder_keep_original, const std::map feature_key_map, unsigned sequence_length, unsigned step, unsigned stride) { + bool decoder_keep_original, const std::map feature_key_map, unsigned sequence_length, unsigned step, unsigned stride, ExternalSourceFileMode external_file_mode) { if (!_loader_module) THROW("ERROR: loader module is not set for ImageLoaderNode, cannot initialize") if (shard_count < 1) @@ -49,6 +49,7 @@ void ImageLoaderSingleShardNode::init(unsigned shard_id, unsigned shard_count, u reader_cfg.set_sequence_length(sequence_length); reader_cfg.set_frame_step(step); reader_cfg.set_frame_stride(stride); + reader_cfg.set_external_filemode(external_file_mode); _loader_module->initialize(reader_cfg, DecoderConfig(decoder_type), mem_type, _batch_size, decoder_keep_original); diff --git a/rocAL/source/loaders/video/video_read_and_decode.cpp b/rocAL/source/loaders/video/video_read_and_decode.cpp index 2f173b46f..459a4f509 100644 --- a/rocAL/source/loaders/video/video_read_and_decode.cpp +++ b/rocAL/source/loaders/video/video_read_and_decode.cpp @@ -21,11 +21,8 @@ THE SOFTWARE. */ #include "video_read_and_decode.h" - #include "video_decoder_factory.h" -namespace filesys = boost::filesystem; - #ifdef ROCAL_VIDEO std::tuple video_interpret_color_format(RocalColorFormat color_format) { diff --git a/rocAL/source/meta_data/caffe_meta_data_reader.cpp b/rocAL/source/meta_data/caffe_meta_data_reader.cpp index f9e10b61e..0ecdd37cb 100644 --- a/rocAL/source/meta_data/caffe_meta_data_reader.cpp +++ b/rocAL/source/meta_data/caffe_meta_data_reader.cpp @@ -25,11 +25,6 @@ THE SOFTWARE. #include #include -#include -#include -#include -#include - #include "commons.h" #include "exception.h" @@ -37,8 +32,6 @@ using caffe_protos::Datum; using std::string; using namespace std; -namespace filesys = boost::filesystem; - CaffeMetaDataReader::CaffeMetaDataReader() { } diff --git a/rocAL/source/meta_data/cifar10_meta_data_reader.cpp b/rocAL/source/meta_data/cifar10_meta_data_reader.cpp index 9ddcd984d..916223d4e 100644 --- a/rocAL/source/meta_data/cifar10_meta_data_reader.cpp +++ b/rocAL/source/meta_data/cifar10_meta_data_reader.cpp @@ -25,18 +25,15 @@ THE SOFTWARE. #include #include -#include -#include -#include - #include "commons.h" #include "exception.h" +#include "filesystem.h" +#include "cifar10_meta_data_reader.h" using namespace std; -namespace filesys = boost::filesystem; - -Cifar10MetaDataReader::Cifar10MetaDataReader() { +Cifar10MetaDataReader::Cifar10MetaDataReader() +{ _src_dir = nullptr; _entity = nullptr; _sub_dir = nullptr; diff --git a/rocAL/source/meta_data/label_reader_folders.cpp b/rocAL/source/meta_data/label_reader_folders.cpp index da983bf24..172128a24 100644 --- a/rocAL/source/meta_data/label_reader_folders.cpp +++ b/rocAL/source/meta_data/label_reader_folders.cpp @@ -25,17 +25,13 @@ THE SOFTWARE. #include #include -#include -#include -#include - #include "commons.h" #include "exception.h" +#include "label_reader_folders.h" +#include "filesystem.h" using namespace std; -namespace filesys = boost::filesystem; - LabelReaderFolders::LabelReaderFolders() { _src_dir = nullptr; _entity = nullptr; diff --git a/rocAL/source/meta_data/mxnet_meta_data_reader.cpp b/rocAL/source/meta_data/mxnet_meta_data_reader.cpp index 5a7e3753e..0f135fbd3 100644 --- a/rocAL/source/meta_data/mxnet_meta_data_reader.cpp +++ b/rocAL/source/meta_data/mxnet_meta_data_reader.cpp @@ -24,13 +24,8 @@ THE SOFTWARE. #include #include +#include "filesystem.h" -#include -#include -#include -#include - -namespace filesys = boost::filesystem; using namespace std; void MXNetMetaDataReader::init(const MetaDataConfig &cfg, pMetaDataBatch meta_data_batch) { diff --git a/rocAL/source/meta_data/video_label_reader.cpp b/rocAL/source/meta_data/video_label_reader.cpp index 7444b2767..0084cf9b6 100644 --- a/rocAL/source/meta_data/video_label_reader.cpp +++ b/rocAL/source/meta_data/video_label_reader.cpp @@ -25,17 +25,12 @@ THE SOFTWARE. #include #include -#include -#include -#include - #include "commons.h" #include "exception.h" +#include "filesystem.h" using namespace std; -namespace filesys = boost::filesystem; - #ifdef ROCAL_VIDEO VideoLabelReader::VideoLabelReader() { _src_dir = nullptr; diff --git a/rocAL/source/pipeline/master_graph.cpp b/rocAL/source/pipeline/master_graph.cpp index 83fbcdb4b..26cf94a8e 100644 --- a/rocAL/source/pipeline/master_graph.cpp +++ b/rocAL/source/pipeline/master_graph.cpp @@ -494,6 +494,8 @@ MasterGraph::reset() { size_t MasterGraph::remaining_count() { + if (!_external_source_eos && _external_source_reader) + return _user_batch_size; return (_remaining_count >= 0) ? _remaining_count : 0; } @@ -1582,6 +1584,8 @@ size_t MasterGraph::bounding_box_batch_count(pMetaDataBatch meta_data_batch) { } TensorList *MasterGraph::labels_meta_data() { + if (_external_source_reader) + return &_labels_tensor_list; if (_ring_buffer.level() == 0) THROW("No meta data has been loaded") auto meta_data_buffers = (unsigned char *)_ring_buffer.get_meta_read_buffers()[0]; // Get labels buffer from ring buffer @@ -2403,3 +2407,24 @@ MasterGraph::get_bbox_encoded_buffers(size_t num_encoded_boxes) { } return bbox_encoded_output; } + +void MasterGraph::feed_external_input(const std::vector& input_images_names, bool is_labels, const std::vector& input_buffer, + const std::vector& roi_xywh, unsigned int max_width, unsigned int max_height, unsigned int channels, + ExternalSourceFileMode mode, RocalTensorlayout layout, bool eos) { + _external_source_eos = eos; + _loader_module->feed_external_input(input_images_names, input_buffer, roi_xywh, max_width, max_height, channels, mode, eos); + + if (is_labels) { + if (_labels_tensor_list.size() == 0) { // Labels tensor list is initialized only once for the pipeline + std::vector dims = {1}; + auto default_labels_info = TensorInfo(std::move(dims), _mem_type, RocalTensorDataType::INT32); + default_labels_info.set_metadata(); + + for (unsigned i = 0; i < _user_batch_size; i++) { + auto info = default_labels_info; + _labels_tensor_list.push_back(new Tensor(info)); + } + _metadata_output_tensor_list.emplace_back(&_labels_tensor_list); + } + } +} diff --git a/rocAL/source/readers/image/caffe2_lmdb_record_reader.cpp b/rocAL/source/readers/image/caffe2_lmdb_record_reader.cpp index 6959ef789..3c4c8fc22 100644 --- a/rocAL/source/readers/image/caffe2_lmdb_record_reader.cpp +++ b/rocAL/source/readers/image/caffe2_lmdb_record_reader.cpp @@ -21,20 +21,11 @@ THE SOFTWARE. */ #include "caffe2_lmdb_record_reader.h" - -#include -#include - -#include -#include -#include -#include #include #include #include #include using namespace std; -namespace filesys = boost::filesystem; Caffe2LMDBRecordReader::Caffe2LMDBRecordReader() { _src_dir = nullptr; diff --git a/rocAL/source/readers/image/caffe_lmdb_record_reader.cpp b/rocAL/source/readers/image/caffe_lmdb_record_reader.cpp index ad3749b17..2262b88d1 100644 --- a/rocAL/source/readers/image/caffe_lmdb_record_reader.cpp +++ b/rocAL/source/readers/image/caffe_lmdb_record_reader.cpp @@ -23,12 +23,6 @@ THE SOFTWARE. #include "caffe_lmdb_record_reader.h" #include -#include - -#include -#include -#include -#include #include #include #include @@ -37,9 +31,8 @@ THE SOFTWARE. using namespace std; using caffe_protos::Datum; -namespace filesys = boost::filesystem; - -CaffeLMDBRecordReader::CaffeLMDBRecordReader() { +CaffeLMDBRecordReader::CaffeLMDBRecordReader() +{ _sub_dir = nullptr; _curr_file_idx = 0; _current_file_size = 0; diff --git a/rocAL/source/readers/image/cifar10_data_reader.cpp b/rocAL/source/readers/image/cifar10_data_reader.cpp index ac9cb3799..f98ab9ce0 100644 --- a/rocAL/source/readers/image/cifar10_data_reader.cpp +++ b/rocAL/source/readers/image/cifar10_data_reader.cpp @@ -20,15 +20,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "cifar10_data_reader.h" - +#include #include +#include +#include +#include "cifar10_data_reader.h" #include - -#include -#include - -namespace filesys = boost::filesystem; +#include "filesystem.h" CIFAR10DataReader::CIFAR10DataReader() { _src_dir = nullptr; diff --git a/rocAL/source/readers/image/coco_file_source_reader.cpp b/rocAL/source/readers/image/coco_file_source_reader.cpp index f1e656f6a..d8378d3a7 100644 --- a/rocAL/source/readers/image/coco_file_source_reader.cpp +++ b/rocAL/source/readers/image/coco_file_source_reader.cpp @@ -21,18 +21,10 @@ THE SOFTWARE. */ #include "coco_file_source_reader.h" - -#include - -#include -#include -#include - -#include "coco_meta_data_reader.h" -#include "meta_data_graph_factory.h" #include "meta_data_reader_factory.h" +#include "meta_data_graph_factory.h" +#include "filesystem.h" -namespace filesys = boost::filesystem; #define USE_STDIO_FILE 0 COCOFileSourceReader::COCOFileSourceReader() { diff --git a/rocAL/source/readers/image/external_source_reader.cpp b/rocAL/source/readers/image/external_source_reader.cpp new file mode 100644 index 000000000..c07fc04c5 --- /dev/null +++ b/rocAL/source/readers/image/external_source_reader.cpp @@ -0,0 +1,233 @@ +/* +Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "external_source_reader.h" + +#include +#include + +ExternalSourceReader::ExternalSourceReader() { + _curr_file_idx = 0; + _current_file_size = 0; + _current_fPtr = nullptr; + _file_id = 0; + _shuffle = false; + _file_count_all_shards = 0; + _loop = false; // loop not supported for external source + _end_of_sequence = false; +} + +// return batch_size() for count_items unless end_of_sequence has been signalled. +unsigned ExternalSourceReader::count_items() { + if (_file_mode == ExternalSourceFileMode::FILENAME) { + if (_end_of_sequence && _file_names_queue.empty()) { + return 0; + } + } else { + if (_end_of_sequence && _images_data_queue.empty()) { + return 0; + } + } + return _batch_count; +} + +Reader::Status ExternalSourceReader::initialize(ReaderConfig desc) { + auto ret = Reader::Status::OK; + _folder_path = desc.path(); + _file_id = 0; + _shard_id = desc.get_shard_id(); + _shard_count = desc.get_shard_count(); + _batch_count = desc.get_batch_size(); + _shuffle = desc.shuffle(); + _loop = desc.loop(); + _file_mode = desc.mode(); + _end_of_sequence = false; + _file_data.reserve(_batch_count); + return ret; +} + +void ExternalSourceReader::increment_read_ptr() { + _read_counter++; + _curr_file_idx = (_curr_file_idx + 1) % _batch_count; +} + +size_t ExternalSourceReader::open() { + if (_file_mode == ExternalSourceFileMode::FILENAME) { + std::string next_file_name; + bool ret = pop_file_name(next_file_name); // Get next file name: blocking call, will wait till next file is received from external source + if (_end_of_sequence && !ret) + return 0; + _last_id = next_file_name; + filesys::path pathObj(next_file_name); + if (filesys::exists(pathObj) && filesys::is_regular_file(pathObj)) { + _current_fPtr = fopen(next_file_name.c_str(), "rb"); // Open the file, + if (!_current_fPtr) // Check if it is ready for reading + return 0; + fseek(_current_fPtr, 0, SEEK_END); // Take the file read pointer to the end + _current_file_size = ftell(_current_fPtr); // Check how many bytes are there between and the current read pointer position (end of the file) + if (_current_file_size == 0) { // If file is empty continue + fclose(_current_fPtr); + _current_fPtr = nullptr; + return 0; + } + fseek(_current_fPtr, 0, SEEK_SET); // Take the file pointer back to the start + ExternalSourceImageInfo image_info; + image_info.file_data = (unsigned char*)next_file_name.data(); + image_info.file_read_size = _current_file_size; + _file_data[_curr_file_idx] = image_info; + increment_read_ptr(); + } + } else { + ExternalSourceImageInfo image_info; + bool ret = pop_file_data(image_info); + if (_end_of_sequence && !ret) { + WRN(" EOS || POP FAILED ") + return 0; + } + _file_data[_curr_file_idx] = image_info; + _current_file_size = image_info.file_read_size; + } + return _current_file_size; +} + +size_t ExternalSourceReader::read_data(unsigned char* buf, size_t read_size) { + if (_file_mode == ExternalSourceFileMode::FILENAME) { + if (!_current_fPtr) + return 0; + + // Requested read size bigger than the file size? just read as many bytes as the file size + read_size = std::min(static_cast(read_size), _current_file_size); + size_t actual_read_size = fread(buf, sizeof(unsigned char), read_size, _current_fPtr); + return actual_read_size; + } else { + unsigned char* file_data_ptr = _file_data[_curr_file_idx].file_data; + size_t size = _current_file_size; + if (size > read_size) + THROW("Requested size doesn't match the actual size for file read") + memcpy(static_cast(buf), static_cast(file_data_ptr), size); + increment_read_ptr(); + return size; + } +} + +void ExternalSourceReader::get_dims(int cur_idx, int& width, int& height, int& channels, unsigned& roi_width, unsigned& roi_height) { + if (cur_idx >= 0) { + width = _file_data[cur_idx].width; + height = _file_data[cur_idx].height; + channels = _file_data[cur_idx].channels; + roi_width = _file_data[cur_idx].roi_width; + roi_height = _file_data[cur_idx].roi_height; + } +} + +int ExternalSourceReader::close() { + return release(); +} + +ExternalSourceReader::~ExternalSourceReader() { + release(); +} + +int ExternalSourceReader::release() { + if (_file_mode != ExternalSourceFileMode::FILENAME) { + if (!_current_fPtr) + return 0; + fclose(_current_fPtr); + _current_fPtr = nullptr; + _end_of_sequence = false; // reset for looping + } + return 0; +} + +void ExternalSourceReader::reset() { + _read_counter = 0; + _curr_file_idx = 0; + _end_of_sequence = false; // reset for looping +} + +size_t ExternalSourceReader::get_file_shard_id() { + if (_batch_count == 0 || _shard_count == 0) + THROW("Shard (Batch) size cannot be set to 0") + return _file_id % _shard_count; +} + +void ExternalSourceReader::push_file_name(const std::string& file_name) { + std::unique_lock lock(_lock); + _file_names_queue.push(file_name); + lock.unlock(); + // notify waiting thread of new data + _wait_for_input.notify_all(); +} + +bool ExternalSourceReader::pop_file_name(std::string& file_name) { + std::unique_lock lock(_lock); + if (_file_names_queue.empty() && !_end_of_sequence) + _wait_for_input.wait(lock); + if (!_file_names_queue.empty()) { + file_name = _file_names_queue.front(); + _file_names_queue.pop(); + return true; + } else + return false; +} + +void ExternalSourceReader::push_file_data(ExternalSourceImageInfo& image_info) { + std::unique_lock lock(_lock); + _images_data_queue.push(image_info); + lock.unlock(); + // notify waiting thread of new data + _wait_for_input.notify_all(); +} + +bool ExternalSourceReader::pop_file_data(ExternalSourceImageInfo& image_info) { + std::unique_lock lock(_lock); + if (_images_data_queue.empty() && !_end_of_sequence) + _wait_for_input.wait(lock); + if (!_images_data_queue.empty()) { + image_info = _images_data_queue.front(); + _images_data_queue.pop(); + return true; + } else + return false; +} + +void ExternalSourceReader::feed_file_names(const std::vector& file_names, size_t num_images, bool eos) { + for (unsigned n = 0; n < num_images; n++) { + push_file_name(file_names[n]); + } + _end_of_sequence = eos; +} + +void ExternalSourceReader::feed_data(const std::vector& images, const std::vector& image_size, ExternalSourceFileMode mode, bool eos, const std::vector roi_width, const std::vector roi_height, unsigned int width, unsigned int height, unsigned int channels) { + if (mode == ExternalSourceFileMode::RAWDATA_COMPRESSED) { + for (unsigned n = 0; n < images.size(); n++) { + ExternalSourceImageInfo image_info = {images[n], image_size[n], width, height, channels, 0, 0}; + push_file_data(image_info); + } + } else { + for (unsigned n = 0; n < images.size(); n++) { + ExternalSourceImageInfo image_info = {images[n], image_size[n], width, height, channels, roi_width[n], roi_height[n]}; + push_file_data(image_info); + } + } + _end_of_sequence = eos; +} diff --git a/rocAL/source/readers/image/file_source_reader.cpp b/rocAL/source/readers/image/file_source_reader.cpp index af0fbfde9..2623dd411 100644 --- a/rocAL/source/readers/image/file_source_reader.cpp +++ b/rocAL/source/readers/image/file_source_reader.cpp @@ -20,15 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "file_source_reader.h" - -#include - -#include -#include #include - -namespace filesys = boost::filesystem; +#include +#include +#include +#include "file_source_reader.h" +#include "filesystem.h" FileSourceReader::FileSourceReader() { _src_dir = nullptr; diff --git a/rocAL/source/readers/image/mxnet_recordio_reader.cpp b/rocAL/source/readers/image/mxnet_recordio_reader.cpp index bf8e306f6..da1b313f1 100644 --- a/rocAL/source/readers/image/mxnet_recordio_reader.cpp +++ b/rocAL/source/readers/image/mxnet_recordio_reader.cpp @@ -25,16 +25,8 @@ THE SOFTWARE. #include #include #include - -#include -#include -#include -#include -#include -#include -#include - -namespace filesys = boost::filesystem; +#include "mxnet_recordio_reader.h" +#include "filesystem.h" using namespace std; diff --git a/rocAL/source/readers/image/reader_factory.cpp b/rocAL/source/readers/image/reader_factory.cpp index 887620bbd..74b395bab 100644 --- a/rocAL/source/readers/image/reader_factory.cpp +++ b/rocAL/source/readers/image/reader_factory.cpp @@ -29,6 +29,7 @@ THE SOFTWARE. #include "caffe_lmdb_record_reader.h" #include "cifar10_data_reader.h" #include "coco_file_source_reader.h" +#include "external_source_reader.h" #include "file_source_reader.h" #include "mxnet_recordio_reader.h" #include "numpy_data_reader.h" @@ -85,6 +86,12 @@ std::shared_ptr create_reader(ReaderConfig config) { throw std::runtime_error("MXNetRecordIOReader cannot access the storage"); return ret; } break; + case StorageType::EXTERNAL_FILE_SOURCE: { + auto ret = std::make_shared(); + if (ret->initialize(config) != Reader::Status::OK) + throw std::runtime_error("ExternalSourceReader cannot access the storage"); + return ret; + } break; case StorageType::NUMPY_DATA: { auto ret = std::make_shared(); if (ret->initialize(config) != Reader::Status::OK) diff --git a/rocAL/source/readers/image/tf_record_reader.cpp b/rocAL/source/readers/image/tf_record_reader.cpp index 427c19a0d..43213549e 100644 --- a/rocAL/source/readers/image/tf_record_reader.cpp +++ b/rocAL/source/readers/image/tf_record_reader.cpp @@ -21,21 +21,11 @@ THE SOFTWARE. */ #include "tf_record_reader.h" - -#include -#include - -#include -#include -#include -#include #include #include #include #include -namespace filesys = boost::filesystem; - TFRecordReader::TFRecordReader() { _src_dir = nullptr; _sub_dir = nullptr; diff --git a/rocAL/source/readers/video/sequence_file_source_reader.cpp b/rocAL/source/readers/video/sequence_file_source_reader.cpp index b6204aa72..a121c40e7 100644 --- a/rocAL/source/readers/video/sequence_file_source_reader.cpp +++ b/rocAL/source/readers/video/sequence_file_source_reader.cpp @@ -20,15 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "sequence_file_source_reader.h" - -#include - -#include -#include #include - -namespace filesys = boost::filesystem; +#include +#include +#include +#include "sequence_file_source_reader.h" +#include "filesystem.h" SequenceFileSourceReader::SequenceFileSourceReader() { _src_dir = nullptr; diff --git a/rocAL/source/readers/video/video_file_source_reader.cpp b/rocAL/source/readers/video/video_file_source_reader.cpp index b27627e29..2d2066c9e 100644 --- a/rocAL/source/readers/video/video_file_source_reader.cpp +++ b/rocAL/source/readers/video/video_file_source_reader.cpp @@ -22,13 +22,6 @@ THE SOFTWARE. #include "video_file_source_reader.h" -#include - -#include -#include -#include -namespace filesys = boost::filesystem; - #ifdef ROCAL_VIDEO VideoFileSourceReader::VideoFileSourceReader() { _curr_sequence_idx = 0; diff --git a/rocAL/source/readers/video/video_properties.cpp b/rocAL/source/readers/video/video_properties.cpp index d436e6c8a..e0e997342 100644 --- a/rocAL/source/readers/video/video_properties.cpp +++ b/rocAL/source/readers/video/video_properties.cpp @@ -23,6 +23,9 @@ THE SOFTWARE. #include "video_properties.h" #include +#include +#include +#include "filesystem.h" #ifdef ROCAL_VIDEO void substring_extraction(std::string const &str, const char delim, std::vector &out) { diff --git a/rocAL_pybind/CMakeLists.txt b/rocAL_pybind/CMakeLists.txt index 7a6bc47e1..ba7dc21ff 100644 --- a/rocAL_pybind/CMakeLists.txt +++ b/rocAL_pybind/CMakeLists.txt @@ -44,6 +44,7 @@ find_package(TurboJpeg QUIET) set(Python3_FIND_VIRTUALENV FIRST) find_package(Python3 QUIET COMPONENTS Interpreter Development) find_package(pybind11 QUIET CONFIG) +find_package(HALF QUIET) # Backend if(BUILD_PYPACKAGE) @@ -184,6 +185,11 @@ if(NOT pybind11_FOUND) set(BUILD_ROCAL_PYBIND false) message("-- ${Yellow}NOTE: rocAL requires pybind11, Not Found${ColourReset}") endif() +# PyBind11 +if(NOT HALF_FOUND) + set(BUILD_ROCAL_PYBIND false) + message("-- ${Yellow}NOTE: rocAL requires Half, Not Found${ColourReset}") +endif() if(${BUILD_ROCAL_PYBIND}) # avoid setting the default installation path to /usr/local @@ -210,6 +216,8 @@ if(${BUILD_ROCAL_PYBIND}) message("-- ${Green}NOTE: rocAL pybind requires Python3, Found -- ${Python3_EXECUTABLE} ${ColourReset}") # PyBind11 include_directories(${pybind11_INCLUDE_DIRS}) + # half + include_directories(${HALF_INCLUDE_DIRS}) file(GLOB_RECURSE pyfiles amd/*.py) file(GLOB_RECURSE sources *.cpp) diff --git a/rocAL_pybind/amd/rocal/fn.py b/rocAL_pybind/amd/rocal/fn.py index a2ae5733d..1ec5289c2 100644 --- a/rocAL_pybind/amd/rocal/fn.py +++ b/rocAL_pybind/amd/rocal/fn.py @@ -1088,6 +1088,20 @@ def box_iou_matcher(*inputs, anchors, high_threshold=0.5, Pipeline._current_pipeline._box_iou_matcher = True return (box_iou_matcher, []) + +def external_source(*inputs, source, device=None, color_format=types.RGB, random_shuffle=False, mode=types.EXTSOURCE_FNAME, max_width=2000, max_height=2000): + # pybind call arguments + Pipeline._current_pipeline._is_external_source_operator = True + Pipeline._current_pipeline._external_source = iter(source) + Pipeline._current_pipeline._external_source_mode = mode + Pipeline._current_pipeline._external_source_user_given_width = max_width + Pipeline._current_pipeline._external_source_user_given_height = max_height + kwargs_pybind = {"rocal_color_format": color_format, "is_output": False, "shuffle": random_shuffle, "loop": False, "decode_size_policy": types.USER_GIVEN_SIZE, + "max_width": max_width, "max_height": max_height, "dec_type": types.DECODER_TJPEG, "external_source_mode": mode} + external_source_operator = b.externalFileSource( + Pipeline._current_pipeline._handle, *(kwargs_pybind.values())) + return (external_source_operator, []) # Labels is Empty + def set_layout(*inputs, output_layout=types.NHWC): """!Adjusts brightness of the image. diff --git a/rocAL_pybind/amd/rocal/pipeline.py b/rocAL_pybind/amd/rocal/pipeline.py index a127b8f7b..a95c283a4 100644 --- a/rocAL_pybind/amd/rocal/pipeline.py +++ b/rocAL_pybind/amd/rocal/pipeline.py @@ -120,6 +120,9 @@ def __init__(self, batch_size=-1, num_threads=0, device_id=-1, seed=1, self._reader = None self._define_graph_set = False self.set_seed(self._seed) + self._is_external_source_operator = False + self._external_source = None + self._external_source_mode = None def build(self): """!Build the pipeline using rocalVerify call diff --git a/rocAL_pybind/amd/rocal/plugin/generic.py b/rocAL_pybind/amd/rocal/plugin/generic.py index e3c3d0006..d307069aa 100644 --- a/rocAL_pybind/amd/rocal/plugin/generic.py +++ b/rocAL_pybind/amd/rocal/plugin/generic.py @@ -27,7 +27,7 @@ import numpy as np import rocal_pybind as b import amd.rocal.types as types - +import ctypes class ROCALGenericIterator(object): """!Iterator for processing data @@ -62,11 +62,58 @@ def __init__(self, pipeline, tensor_layout=types.NCHW, reverse_channels=False, m self.labels_tensor = None self.iterator_length = b.getRemainingImages( self.loader._handle) // self.batch_size # iteration length + if self.loader._is_external_source_operator: + self.eos = False + self.index = 0 + self.num_batches = self.loader._external_source.n // self.batch_size if self.loader._external_source.n % self.batch_size == 0 else ( + self.loader._external_source.n // self.batch_size + 1) + else: + self.num_batches = None def next(self): return self.__next__() def __next__(self): + if (self.loader._is_external_source_operator): + if (self.index + 1) == self.num_batches: + self.eos = True + if (self.index + 1) <= self.num_batches: + data_loader_source = next(self.loader._external_source) + # Extract all data from the source + images_list = data_loader_source[0] if (self.loader._external_source_mode == types.EXTSOURCE_FNAME) else [] + input_buffer = data_loader_source[0] if (self.loader._external_source_mode != types.EXTSOURCE_FNAME) else [] + labels_data = data_loader_source[1] if (len(data_loader_source) > 1) else None + roi_height = data_loader_source[2] if (len(data_loader_source) > 2) else [] + roi_width = data_loader_source[3] if (len(data_loader_source) > 3) else [] + ROIxywh_list = [] + for i in range(self.batch_size): + ROIxywh = b.ROIxywh() + ROIxywh.x = 0 + ROIxywh.y = 0 + ROIxywh.w = roi_width[i] if len(roi_width) > 0 else 0 + ROIxywh.h = roi_height[i] if len(roi_height) > 0 else 0 + ROIxywh_list.append(ROIxywh) + if (len(data_loader_source) == 6 and self.loader._external_source_mode == types.EXTSOURCE_RAW_UNCOMPRESSED): + decoded_height = data_loader_source[4] + decoded_width = data_loader_source[5] + else: + decoded_height = self.loader._external_source_user_given_height + decoded_width = self.loader._external_source_user_given_width + + kwargs_pybind = { + "handle": self.loader._handle, + "source_input_images": images_list, + "labels": labels_data, + "input_batch_buffer": input_buffer, + "roi_xywh": ROIxywh_list, + "decoded_width": decoded_width, + "decoded_height": decoded_height, + "channels": 3, + "external_source_mode": self.loader._external_source_mode, + "rocal_tensor_layout": types.NCHW, + "eos": self.eos} + b.externalSourceFeedInput(*(kwargs_pybind.values())) + self.index = self.index + 1 if self.loader.rocal_run() != 0: raise StopIteration self.output_tensor_list = self.loader.get_output_tensors() @@ -99,6 +146,14 @@ def __next__(self): else: self.output_tensor_list[i].copy_data( self.output_list[i].data.ptr) + if (self.loader._is_external_source_operator): + self.labels = self.loader.get_image_labels() + if self.device == "cpu": + self.labels_tensor = self.labels.astype(dtype=np.int_) + else: + with cp.cuda.Device(device=self.device_id): + self.labels_tensor = self.labels.astype(dtype=cp.int_) + return self.output_list, self.labels_tensor if self.loader._name == "labelReader": if self.loader._one_hot_encoding == True: diff --git a/rocAL_pybind/amd/rocal/plugin/pytorch.py b/rocAL_pybind/amd/rocal/plugin/pytorch.py index 2b5d3cdb8..ca2ad6724 100644 --- a/rocAL_pybind/amd/rocal/plugin/pytorch.py +++ b/rocAL_pybind/amd/rocal/plugin/pytorch.py @@ -137,6 +137,14 @@ def __init__(self, pipeline, tensor_layout=types.NCHW, reverse_channels=False, m self.output_memory_type = self.loader._output_memory_type self.iterator_length = b.getRemainingImages(self.loader._handle) self.display = display + self.batch_size = pipeline._batch_size + if self.loader._is_external_source_operator: + self.eos = False + self.index = 0 + self.num_batches = self.loader._external_source.n // self.batch_size if self.loader._external_source.n % self.batch_size == 0 else ( + self.loader._external_source.n // self.batch_size + 1) + else: + self.num_batches = None if self.loader._name is None: self.loader._name = self.loader._reader @@ -144,6 +152,39 @@ def next(self): return self.__next__() def __next__(self): + if (self.loader._is_external_source_operator): + if (self.index + 1) == self.num_batches: + self.eos = True + if (self.index + 1) <= self.num_batches: + data_loader_source = next(self.loader._external_source) + # Extract all data from the source + images_list = data_loader_source[0] if (self.loader._external_source_mode == types.EXTSOURCE_FNAME) else [] + input_buffer = data_loader_source[0] if (self.loader._external_source_mode != types.EXTSOURCE_FNAME) else [] + labels_data = data_loader_source[1] if (len(data_loader_source) > 1) else None + roi_height = data_loader_source[2] if (len(data_loader_source) > 2) else [] + roi_width = data_loader_source[3] if (len(data_loader_source) > 3) else [] + if (len(data_loader_source) == 6 and self.loader._external_source_mode == types.EXTSOURCE_RAW_UNCOMPRESSED): + decoded_height = data_loader_source[4] + decoded_width = data_loader_source[5] + else: + decoded_height = self.loader._external_source_user_given_height + decoded_width = self.loader._external_source_user_given_width + + kwargs_pybind = { + "handle": self.loader._handle, + "source_input_images": images_list, + "labels": labels_data, + "input_batch_buffer": input_buffer, + "roi_width": roi_width, + "roi_height": roi_height, + "decoded_width": decoded_width, + "decoded_height": decoded_height, + "channels": 3, + "external_source_mode": self.loader._external_source_mode, + "rocal_tensor_layout": types.NCHW, + "eos": self.eos} + b.externalSourceFeedInput(*(kwargs_pybind.values())) + self.index = self.index + 1 if self.loader.rocal_run() != 0: raise StopIteration else: @@ -222,6 +263,11 @@ def __next__(self): return self.output_list, self.bb_padded, self.labels_padded + elif self.loader._is_external_source_operator: + self.labels = self.loader.get_image_labels() + self.labels_tensor = self.labels_tensor.copy_( + torch.from_numpy(self.labels)).long() + return self.output_list, self.labels_tensor else: if self.loader._one_hot_encoding: self.loader.get_one_hot_encoded_labels( diff --git a/rocAL_pybind/amd/rocal/types.py b/rocAL_pybind/amd/rocal/types.py index 11818ec50..27a0f8f56 100644 --- a/rocAL_pybind/amd/rocal/types.py +++ b/rocAL_pybind/amd/rocal/types.py @@ -91,6 +91,11 @@ from rocal_pybind.types import GAUSSIAN_INTERPOLATION from rocal_pybind.types import TRIANGULAR_INTERPOLATION +# Rocal External Source Mode +from rocal_pybind.types import EXTSOURCE_FNAME +from rocal_pybind.types import EXTSOURCE_RAW_COMPRESSED +from rocal_pybind.types import EXTSOURCE_RAW_UNCOMPRESSED + from rocal_pybind.types import TRIMTOSHAPE from rocal_pybind.types import PAD @@ -151,12 +156,15 @@ SCALING_MODE_NOT_LARGER: ("SCALING_MODE_NOT_LARGER", SCALING_MODE_NOT_LARGER), SCALING_MODE_MIN_MAX: ("SCALING_MODE_MIN_MAX", SCALING_MODE_MIN_MAX), + EXTSOURCE_FNAME: ("EXTSOURCE_FNAME", EXTSOURCE_FNAME), + EXTSOURCE_RAW_COMPRESSED: ("EXTSOURCE_RAW_COMPRESSED", EXTSOURCE_RAW_COMPRESSED), + EXTSOURCE_RAW_UNCOMPRESSED: ("EXTSOURCE_RAW_UNCOMPRESSED", EXTSOURCE_RAW_UNCOMPRESSED), + TRIMTOSHAPE: ("TRIMTOSHAPE", TRIMTOSHAPE), PAD: ("PAD", PAD), } - def data_type_function(dtype): """!Converts a given data type identifier to its corresponding known type. diff --git a/rocAL_pybind/examples/PYTHON_UNITTEST_TEST_FILE.sh b/rocAL_pybind/examples/PYTHON_UNITTEST_TEST_FILE.sh index a19f1eef3..3b5239798 100755 --- a/rocAL_pybind/examples/PYTHON_UNITTEST_TEST_FILE.sh +++ b/rocAL_pybind/examples/PYTHON_UNITTEST_TEST_FILE.sh @@ -84,7 +84,7 @@ do python"$ver" rocAL_api_python_unittest.py --image-dataset-path "$coco_detection_path" --reader-type coco --json-path "$coco_json_path" --augmentation-name contrast --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Contrast_${rgb_name[$rgb]}_${device_name}" python"$ver" rocAL_api_python_unittest.py --image-dataset-path "$coco_detection_path" --reader-type coco --json-path "$coco_json_path" --augmentation-name vignette --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Vignette_${rgb_name[$rgb]}_${device_name}" - # tf classification + # # tf classification python"$ver" rocAL_api_python_unittest.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name blend --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Blend_${rgb_name[$rgb]}_${device_name}" python"$ver" rocAL_api_python_unittest.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name warp_affine --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}WarpAffine_${rgb_name[$rgb]}_${device_name}" python"$ver" rocAL_api_python_unittest.py --image-dataset-path "$tf_classification_path" --reader-type "tf_classification" --augmentation-name blur --batch-size $batch_size --max-width $width --max-height $height --color-format $rgb --$backend_arg -f "${output_path}Blur_${rgb_name[$rgb]}_${device_name}" diff --git a/rocAL_pybind/examples/rocAL_api_external_source_reader_example.py b/rocAL_pybind/examples/rocAL_api_external_source_reader_example.py new file mode 100644 index 000000000..a871d78e5 --- /dev/null +++ b/rocAL_pybind/examples/rocAL_api_external_source_reader_example.py @@ -0,0 +1,279 @@ +from random import shuffle +from amd.rocal.pipeline import Pipeline +from amd.rocal.plugin.generic import ROCALClassificationIterator +import amd.rocal.fn as fn +import amd.rocal.types as types +import os +import numpy as np +import cupy as cp +import cv2 +from PIL import Image + + +def main(): + batch_size = 3 + data_dir = os.environ["ROCAL_DATA_PATH"] + \ + "/coco/coco_10_img/train_10images_2017/" + device = "cpu" + try: + path_mode0 = "OUTPUT_IMAGES_PYTHON/EXTERNAL_SOURCE_READER/MODE0/" + isExist = os.path.exists(path_mode0) + if not isExist: + os.makedirs(path_mode0) + except OSError as error: + print(error) + try: + path_mode1 = "OUTPUT_IMAGES_PYTHON/EXTERNAL_SOURCE_READER/MODE1/" + isExist = os.path.exists(path_mode1) + if not isExist: + os.makedirs(path_mode1) + except OSError as error: + print(error) + try: + path_mode2 = "OUTPUT_IMAGES_PYTHON/EXTERNAL_SOURCE_READER/MODE2/" + isExist = os.path.exists(path_mode2) + if not isExist: + os.makedirs(path_mode2) + except OSError as error: + print(error) + + def image_dump(img, idx, device="cpu", mode=0): + if device == "gpu": + img = cp.asnumpy(img) + img = img.transpose([1, 2, 0]) # NCHW + img = (img).astype('uint8') + if mode!=2: + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + cv2.imwrite("OUTPUT_IMAGES_PYTHON/EXTERNAL_SOURCE_READER/MODE" + str(mode) + "/"+ + str(idx)+"_"+"train"+".png", img) + + ##################### MODE 0 ######################### + # Define the Data Source for all image samples - User needs to define their own source + class ExternalInputIteratorMode0(object): + def __init__(self, batch_size): + self.images_dir = data_dir + self.batch_size = batch_size + self.files = [] + import glob + for filename in glob.glob(os.path.join(self.images_dir, '*.jpg')): + self.files.append(filename) + shuffle(self.files) + + def __iter__(self): + self.i = 0 + self.n = len(self.files) + return self + + def __next__(self): + batch = [] + labels = [] + label = 1 + for _ in range(self.batch_size): + jpeg_filename = self.files[self.i] + batch.append(jpeg_filename) + labels.append(label) + label = label + 1 + self.i = (self.i + 1) % self.n + labels = np.array(labels).astype('int32') + return batch, labels + + # Mode 0 + external_input_source = ExternalInputIteratorMode0(batch_size) + + # Create the pipeline + external_source_pipeline_mode0 = Pipeline(batch_size=batch_size, num_threads=1, device_id=0, prefetch_queue_depth=4, + seed=1, rocal_cpu=True if device == "cpu" else False, tensor_layout=types.NCHW) + + with external_source_pipeline_mode0: + jpegs, _ = fn.external_source( + source=external_input_source, mode=types.EXTSOURCE_FNAME) + output = fn.resize(jpegs, resize_width=300, resize_height=300, + output_layout=types.NCHW, output_dtype=types.UINT8) + external_source_pipeline_mode0.set_outputs(output) + + # build the external_source_pipeline_mode0 + external_source_pipeline_mode0.build() + # Index starting from 0 + cnt = 0 + # Dataloader + data_loader = ROCALClassificationIterator( + external_source_pipeline_mode0, device=device) + for i, output_list in enumerate(data_loader, 0): + print("**************MODE 0*******************") + print("**************", i, "*******************") + print("**************starts*******************") + print("\nImages:\n", output_list) + print("**************ends*******************") + print("**************", i, "*******************") + for img in output_list[0][0]: + cnt = cnt + 1 + image_dump(img, cnt, device=device, mode=0) + + ##################### MODE 0 ######################### + + ##################### MODE 1 ######################### + # Define the Data Source for all image samples + class ExternalInputIteratorMode1(object): + def __init__(self, batch_size): + self.images_dir = data_dir + self.batch_size = batch_size + self.files = [] + import os + import glob + for filename in glob.glob(os.path.join(self.images_dir, '*.jpg')): + self.files.append(filename) + + def __iter__(self): + self.i = 0 + self.n = len(self.files) + self.maxWidth = None + self.maxHeight = None + return self + + def __next__(self): + batch = [] + labels = [] + srcsize_height = [] + label = 1 + for x in range(self.batch_size): + jpeg_filename = self.files[self.i] + f = open(jpeg_filename, 'rb') + numpy_buffer = np.frombuffer(f.read(), dtype=np.uint8) + batch.append(numpy_buffer) + srcsize_height.append(len(numpy_buffer)) + labels.append(label) + label = label + 1 + self.i = (self.i + 1) % self.n + labels = np.array(labels).astype('int32') + return (batch, labels, srcsize_height) + +# Mode 1 + eii_1 = ExternalInputIteratorMode1(batch_size) + + # Create the pipeline + external_source_pipeline_mode1 = Pipeline(batch_size=batch_size, num_threads=1, device_id=0, prefetch_queue_depth=4, + seed=1, rocal_cpu=True if device == "cpu" else False, tensor_layout=types.NCHW) + + with external_source_pipeline_mode1: + jpegs, _ = fn.external_source( + source=eii_1, mode=types.EXTSOURCE_RAW_COMPRESSED, max_width=2000, max_height=2000) + output = fn.resize(jpegs, resize_width=2000, resize_height=2000, + output_layout=types.NCHW, output_dtype=types.UINT8) + external_source_pipeline_mode1.set_outputs(output) + + # build the external_source_pipeline_mode1 + external_source_pipeline_mode1.build() + # Index starting from 0 + cnt = 0 + # Dataloader + data_loader = ROCALClassificationIterator( + external_source_pipeline_mode1, device=device) + for i, output_list in enumerate(data_loader, 0): + print("**************MODE 1*******************") + print("**************", i, "*******************") + print("**************starts*******************") + print("\nImages:\n", output_list) + print("**************ends*******************") + print("**************", i, "*******************") + for img in output_list[0][0]: + cnt = cnt + 1 + image_dump(img, cnt, device=device, mode=1) + ##################### MODE 1 ######################### + + ##################### MODE 2 ######################### + # Define the Data Source for all image samples + + class ExternalInputIteratorMode2(object): + def __init__(self, batch_size): + self.images_dir = data_dir + self.batch_size = batch_size + self.files = [] + self.maxHeight = self.maxWidth = 0 + import os + import glob + for filename in glob.glob(os.path.join(self.images_dir, '*.jpg')): + self.files.append(filename) + shuffle(self.files) + self.i = 0 + self.n = len(self.files) + + for x in range(self.n): + jpeg_filename = self.files[x] + label = 1 + image = cv2.imread(jpeg_filename, cv2.IMREAD_COLOR) + # Check if the image was loaded successfully + if image is None: + print("Error: Failed to load the image.") + else: + # Get the height and width of the image + height, width = image.shape[:2] + self.maxHeight = height if height > self.maxHeight else self.maxHeight + self.maxWidth = width if width > self.maxWidth else self.maxWidth + + def __iter__(self): + return self + + def __next__(self): + batch = [] + batch_of_numpy = [] + labels = [] + label = 1 + roi_height = [] + roi_width = [] + self.out_image = np.zeros( + (self.batch_size, self.maxHeight, self.maxWidth, 3), dtype="uint8") + for x in range(self.batch_size): + jpeg_filename = self.files[self.i] + image = cv2.imread(jpeg_filename, cv2.IMREAD_COLOR) + # Check if the image was loaded successfully + if image is None: + print("Error: Failed to load the image.") + else: + # Get the height and width of the image + height, width = image.shape[:2] + batch.append(np.asarray(image)) + roi_height.append(height) + roi_width.append(width) + self.out_image[x][:roi_height[x], :roi_width[x], :] = batch[x] + batch_of_numpy.append(self.out_image[x]) + labels.append(label) + label = label + 1 + self.i = (self.i + 1) % self.n + labels = np.array(labels).astype('int32') + return (batch_of_numpy, labels, roi_height, roi_width, self.maxHeight, self.maxWidth) + + +# Mode 2 + eii_2 = ExternalInputIteratorMode2(batch_size) + + # Create the pipeline + external_source_pipeline_mode2 = Pipeline(batch_size=batch_size, num_threads=1, device_id=0, prefetch_queue_depth=4, + seed=1, rocal_cpu=True if device == "cpu" else False, tensor_layout=types.NCHW) + + with external_source_pipeline_mode2: + jpegs, _ = fn.external_source(source=eii_2, mode=types.EXTSOURCE_RAW_UNCOMPRESSED, + max_width=eii_2.maxWidth, max_height=eii_2.maxHeight) + output = fn.resize(jpegs, resize_width=300, resize_height=300, + output_layout=types.NCHW, output_dtype=types.UINT8) + external_source_pipeline_mode2.set_outputs(output) + + # build the external_source_pipeline_mode2 + external_source_pipeline_mode2.build() + # Index starting from 0 + cnt = 0 + # Dataloader + data_loader = ROCALClassificationIterator( + external_source_pipeline_mode2, device=device) + for i, output_list in enumerate(data_loader, 0): + print("**************MODE 2*******************") + print("**************", i, "*******************") + print("**************starts*******************") + print("\nImages:\n", output_list) + print("**************ends*******************") + print("**************", i, "*******************") + for img in output_list[0][0]: + cnt = cnt+1 + image_dump(img, cnt, device=device, mode=2) + ##################### MODE 2 ######################### +if __name__ == '__main__': + main() diff --git a/rocAL_pybind/rocal_pybind.cpp b/rocAL_pybind/rocal_pybind.cpp index bbd8bcfb6..1562575dd 100644 --- a/rocAL_pybind/rocal_pybind.cpp +++ b/rocAL_pybind/rocal_pybind.cpp @@ -96,6 +96,39 @@ py::object wrapper_copy_to_tensor(RocalContext context, py::object p, return py::cast(Py_None); } +py::object wrapperRocalExternalSourceFeedInput( + RocalContext context, std::vector input_images_names, + py::array &labels, py::list arrays, + std::vector roi_xywh, + unsigned int max_width, unsigned int max_height, unsigned int channels, + RocalExternalSourceMode mode, RocalTensorLayout layout, bool eos) { + std::vector uchar_arrays; + if (input_images_names.size() == 0) { // Used for mode 1 and mode 2 for passing decoded buffers + size_t numArrays = py::len(arrays); + for (size_t i = 0; i < numArrays; i++) { + py::array_t arr(arrays[i]); + py::buffer_info buf = arr.request(); + uchar_arrays.push_back(static_cast(buf.ptr)); + } + } + bool enable_labels = true; + if (labels.is_none()) { + enable_labels = false; + } + int status = rocalExternalSourceFeedInput(context, input_images_names, enable_labels, uchar_arrays, roi_xywh, max_width, max_height, channels, mode, layout, eos); + + // Update labels in the tensorList + if (enable_labels) { + auto labels_tensor_list = rocalGetImageLabels(context); + int *labels_ptr = static_cast(labels.request().ptr); + for (size_t i = 0; i < labels.size(); i++) { + labels_tensor_list->at(i)->set_mem_handle(labels_ptr); + labels_ptr++; + } + } + return py::cast(Py_None); +} + std::unordered_map rocalToPybindLayout = { {0, "NHWC"}, {1, "NCHW"}, @@ -114,6 +147,7 @@ std::unordered_map rocalToPybindOutputDtype = { PYBIND11_MODULE(rocal_pybind, m) { m.doc() = "Python bindings for the C++ portions of ROCAL"; + // Bind the C++ structure // rocal_api.h m.def("rocalCreate", &rocalCreate, "Creates context with the arguments sent and returns it", py::return_value_policy::reference, @@ -361,6 +395,17 @@ PYBIND11_MODULE(rocal_pybind, m) { .value("DECODER_VIDEO_FFMPEG_SW", ROCAL_DECODER_VIDEO_FFMPEG_SW) .value("DECODER_VIDEO_FFMPEG_HW", ROCAL_DECODER_VIDEO_FFMPEG_HW) .export_values(); + py::enum_(types_m, "RocalExternalSourceMode", "Rocal Extrernal Source Mode") + .value("EXTSOURCE_FNAME", ROCAL_EXTSOURCE_FNAME) + .value("EXTSOURCE_RAW_COMPRESSED", ROCAL_EXTSOURCE_RAW_COMPRESSED) + .value("EXTSOURCE_RAW_UNCOMPRESSED", ROCAL_EXTSOURCE_RAW_UNCOMPRESSED) + .export_values(); + py::class_(m, "ROIxywh") + .def(py::init<>()) + .def_readwrite("x", &ROIxywh::x) + .def_readwrite("y", &ROIxywh::y) + .def_readwrite("w", &ROIxywh::w) + .def_readwrite("h", &ROIxywh::h); py::enum_(types_m, "RocalOutOfBoundsPolicy", "Rocal Out of Bounds Policy Type") .value("TRIMTOSHAPE", TRIMTOSHAPE) .value("PAD", PAD) @@ -591,6 +636,10 @@ PYBIND11_MODULE(rocal_pybind, m) { py::return_value_policy::reference); m.def("mxnetDecoder", &rocalMXNetRecordSourceSingleShard, "Reads file from the source given and decodes it according to the policy only for mxnet records", py::return_value_policy::reference); + m.def("externalFileSource", &rocalJpegExternalFileSource, + py::return_value_policy::reference); + m.def("externalSourceFeedInput", &wrapperRocalExternalSourceFeedInput, + py::return_value_policy::reference); m.def("numpyReaderSource", &rocalNumpyFileSource, "Reads file from the source given and decodes it according to the policy", py::return_value_policy::reference); m.def("numpyReaderSourceShard", &rocalNumpyFileSourceSingleShard, "Reads file from the source given and decodes it according to the shard id and number of shards", diff --git a/tests/cpp_api_tests/rocAL_external_source/CMakeLists.txt b/tests/cpp_api_tests/rocAL_external_source/CMakeLists.txt new file mode 100644 index 000000000..935d7de34 --- /dev/null +++ b/tests/cpp_api_tests/rocAL_external_source/CMakeLists.txt @@ -0,0 +1,73 @@ +################################################################################ +# +# MIT License +# +# Copyright (c) 2023 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################ +cmake_minimum_required(VERSION 3.5) + +project (rocal_external_source) +set(CMAKE_CXX_STANDARD 14) + +# ROCm Path +set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path") + +# avoid setting the default installation path to /usr/local +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX ${ROCM_PATH} CACHE PATH "rocAL default installation path" FORCE) +endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# Add Default libdir +set(CMAKE_INSTALL_LIBDIR "lib" CACHE STRING "Library install directory") +include(GNUInstallDirs) + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../cmake) + +find_package(OpenCV QUIET) +find_package(AMDRPP QUIET) +include_directories(${ROCM_PATH}/${CMAKE_INSTALL_INCLUDEDIR}/rocal) +link_directories(${ROCM_PATH}/lib) +file(GLOB My_Source_Files ./*.cpp) +add_executable(${PROJECT_NAME} ${My_Source_Files}) + +if(OpenCV_FOUND) + if(${OpenCV_VERSION_MAJOR} EQUAL 3 OR ${OpenCV_VERSION_MAJOR} EQUAL 4) + message("-- OpenCV Found -- Version-${OpenCV_VERSION_MAJOR}.${OpenCV_VERSION_MINOR}.X Supported") + include_directories(${OpenCV_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES}) + if(${OpenCV_VERSION_MAJOR} EQUAL 4) + target_compile_definitions(${PROJECT_NAME} PUBLIC USE_OPENCV_4=1) + else() + target_compile_definitions(${PROJECT_NAME} PUBLIC USE_OPENCV_4=0) + endif() + else() + message(FATAL_ERROR "OpenCV Found -- Version-${OpenCV_VERSION_MAJOR}.${OpenCV_VERSION_MINOR}.X Not Supported") + endif() +else() + message(FATAL_ERROR "OpenCV Not Found -- No Display Support") +endif() + +target_link_libraries(${PROJECT_NAME} rocal) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -mf16c -Wall ") + +install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/tests/cpp_api_tests/rocAL_external_source/README.md b/tests/cpp_api_tests/rocAL_external_source/README.md new file mode 100644 index 000000000..acaf18f52 --- /dev/null +++ b/tests/cpp_api_tests/rocAL_external_source/README.md @@ -0,0 +1,28 @@ +# rocal_external_source application + +This application demonstrates a basic usage of rocAL's C++ API to load images from external source and add augmentations and displays the output images. + +## Build Instructions + +### Pre-requisites + +* Ubuntu Linux, [version `18.04` or later](https://www.microsoft.com/software-download/windows10) +* rocAL library +* [OpenCV 3.1](https://github.com/opencv/opencv/releases) or higher +* ROCm Performance Primitives (RPP) + +### build + + ````bash + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/rocm/rpp/lib + mkdir build + cd build + cmake ../ + make + ```` + +### running the application + + ````bash + rocal_external_source decode_width decode_height batch_size gray_scale/rgb/rgbplanar display_on_off external_source_mode + ```` diff --git a/tests/cpp_api_tests/rocAL_external_source/rocal_external_source.cpp b/tests/cpp_api_tests/rocAL_external_source/rocal_external_source.cpp new file mode 100644 index 000000000..3c3f24cc3 --- /dev/null +++ b/tests/cpp_api_tests/rocAL_external_source/rocal_external_source.cpp @@ -0,0 +1,426 @@ +/* +MIT License + +Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include + +#include +#include +#include +#include +#include + +#include "rocal_api.h" + +using namespace cv; +#if USE_OPENCV_4 +#define CV_LOAD_IMAGE_COLOR IMREAD_COLOR +#define CV_BGR2GRAY COLOR_BGR2GRAY +#define CV_GRAY2RGB COLOR_GRAY2RGB +#define CV_RGB2BGR COLOR_RGB2BGR +#define CV_FONT_HERSHEY_SIMPLEX FONT_HERSHEY_SIMPLEX +#define CV_FILLED FILLED +#define CV_WINDOW_AUTOSIZE WINDOW_AUTOSIZE +#endif + +#define DISPLAY +using namespace std::chrono; + +template +void convert_float_to_uchar_buffer(T *input_float_buffer, unsigned char *output_uchar_buffer, size_t data_size) { + for (size_t i = 0; i < data_size; i++) { + output_uchar_buffer[i] = (unsigned char)(*(input_float_buffer + i) * 255); + } +} + +const std::array, 3> color_mappings = { + {std::make_pair(ROCAL_COLOR_U8, 1), + std::make_pair(ROCAL_COLOR_RGB24, 3), + std::make_pair(ROCAL_COLOR_RGB_PLANAR, 3)} + }; + +int main(int argc, const char **argv) { + const int MIN_ARG_COUNT = 2; + if (argc < MIN_ARG_COUNT) { + printf( + "Usage: rocal_external_source " + " decode_width decode_height batch_size " + "gray_scale/rgb/rgbplanar display_on_off external_source_mode\n"); + return -1; + } + int argIdx = 0; + const char *folder_path = argv[++argIdx]; + bool display = 1; // Display the images + int rgb = 1; // process color images + int decode_width = 224; // Decoding width + int decode_height = 224; // Decoding height + int input_batch_size = 2; // Batch size + bool processing_device = 0; // CPU Processing + int mode = 0; // File mode + + if (argc >= argIdx + MIN_ARG_COUNT) processing_device = atoi(argv[++argIdx]); + + if (argc >= argIdx + MIN_ARG_COUNT) decode_width = atoi(argv[++argIdx]); + + if (argc >= argIdx + MIN_ARG_COUNT) decode_height = atoi(argv[++argIdx]); + + if (argc >= argIdx + MIN_ARG_COUNT) input_batch_size = atoi(argv[++argIdx]); + + if (argc >= argIdx + MIN_ARG_COUNT) rgb = atoi(argv[++argIdx]); + + if (argc >= argIdx + MIN_ARG_COUNT) display = atoi(argv[++argIdx]); + + if (argc >= argIdx + MIN_ARG_COUNT) mode = atoi(argv[++argIdx]); + + std::cerr << "\n Mode:: " << mode << std::endl; + std::cerr << ">>> Running on " << (processing_device ? "GPU" : "CPU") << std::endl; + RocalImageColor color_format = RocalImageColor::ROCAL_COLOR_RGB_PLANAR; + color_format = color_mappings[rgb].first; + int channels = color_mappings[rgb].second; + + auto handle = rocalCreate(input_batch_size, processing_device ? RocalProcessMode::ROCAL_PROCESS_GPU : RocalProcessMode::ROCAL_PROCESS_CPU, 0, 1); + + if (rocalGetStatus(handle) != ROCAL_OK) { + std::cerr << "Could not create the Rocal contex\n"; + return -1; + } + + /*>>>>>>>>>>>>>>>> Creating Rocal parameters <<<<<<<<<<<<<<<<*/ + + rocalSetSeed(0); + + /*>>>>>>>>>>>>>>>>>>> Graph description <<<<<<<<<<<<<<<<<<<*/ + RocalTensor input1; + RocalTensorOutputType tensor_output_type = RocalTensorOutputType::ROCAL_UINT8; + std::vector srcsize_height, srcsize_width; + uint32_t max_height = 0, max_width = 0; + DIR *_src_dir; + struct dirent *_entity; + std::vector file_names; + std::vector input_buffer; + if ((_src_dir = opendir(folder_path)) == nullptr) { + std::cerr << "\n ERROR: Failed opening the directory at " << folder_path; + exit(0); + } + + while ((_entity = readdir(_src_dir)) != nullptr) { + if (_entity->d_type != DT_REG) continue; + + std::string file_path = folder_path; + file_path.append(_entity->d_name); + file_names.push_back(file_path); + } + if (mode != 0) { + if (mode == 1) { + // Mode 1 is Raw compressed + // srcsize_height and srcsize_width resized based on total file count + srcsize_height.resize(file_names.size()); + srcsize_width.resize(file_names.size()); + for (uint32_t i = 0; i < file_names.size(); i++) { + FILE *_current_fPtr; + _current_fPtr = fopen(file_names[i].c_str(), "rb"); // Open the file, + if (!_current_fPtr) // Check if it is ready for reading + return 0; + fseek(_current_fPtr, 0, + SEEK_END); // Take the file read pointer to the end + size_t _current_file_size = ftell( + _current_fPtr); // Check how many bytes are there between and the + // current read pointer position (end of the file) + unsigned char *input_data = static_cast( + malloc(sizeof(unsigned char) * _current_file_size)); + if (_current_file_size == 0) { // If file is empty continue + fclose(_current_fPtr); + _current_fPtr = nullptr; + return 0; + } + + fseek(_current_fPtr, 0, + SEEK_SET); // Take the file pointer back to the start + size_t actual_read_size = fread(input_data, sizeof(unsigned char), + _current_file_size, _current_fPtr); + input_buffer.push_back(input_data); + srcsize_height[i] = actual_read_size; // It stored the actual file size + } + } else if (mode == 2) { // Raw un compressed + srcsize_height.resize(file_names.size()); + srcsize_width.resize(file_names.size()); + for (uint32_t i = 0; i < file_names.size(); i++) { + Mat image; + image = imread(file_names[i], 1); + if (image.empty()) { + std::cout << "Could not read the image: " << file_names[i] << std::endl; + return 1; + } + srcsize_height[i] = image.rows; + srcsize_width[i] = image.cols; + max_height = std::max(max_height, srcsize_height[i]); + max_width = std::max(max_width, srcsize_width[i]); + } + unsigned long long image_dim_max = (unsigned long long)max_height * (unsigned long long)max_width * 3; + unsigned char *complete_image_buffer = (unsigned char *)malloc(sizeof(unsigned char) * file_names.size() * image_dim_max); + uint32_t elements_in_row_max = max_width * 3; + unsigned char *temp_buffer, *temp_image; + for (uint32_t i = 0; i < file_names.size(); i++) { + temp_image = temp_buffer = complete_image_buffer + (i * image_dim_max); + Mat image = imread(file_names[i], 1); + if (image.empty()) { + std::cout << "Could not read the image: " << file_names[i] << std::endl; + return 1; + } + cvtColor(image, image, cv::COLOR_BGR2RGB); + unsigned char *ip_image = image.data; + uint32_t elements_in_row = srcsize_width[i] * 3; + for (uint32_t j = 0; j < srcsize_height[i]; j++) { + memcpy(temp_buffer, ip_image, elements_in_row * sizeof(unsigned char)); + ip_image += elements_in_row; + temp_buffer += elements_in_row_max; + } + input_buffer.push_back(temp_image); + } + } + } + if (max_height != 0 && max_width != 0) { + input1 = rocalJpegExternalFileSource( + handle, color_format, false, false, false, + ROCAL_USE_USER_GIVEN_SIZE, max_width, max_height, + RocalDecoderType::ROCAL_DECODER_TJPEG, RocalExternalSourceMode(mode)); + } else { + input1 = rocalJpegExternalFileSource( + handle, color_format, false, false, false, + ROCAL_USE_USER_GIVEN_SIZE, decode_width, decode_height, + RocalDecoderType::ROCAL_DECODER_TJPEG, RocalExternalSourceMode(mode)); + } + if (rocalGetStatus(handle) != ROCAL_OK) { + std::cerr << "JPEG source could not initialize : " + << rocalGetErrorMessage(handle) << std::endl; + return -1; + } + + // uncomment the following to add augmentation if needed + int resize_w = decode_width, resize_h = decode_height; + // just do one augmentation to test + rocalResize(handle, input1, resize_w, resize_h, true); // Remove this later + if (rocalGetStatus(handle) != ROCAL_OK) { + std::cerr << "Error while adding the augmentation nodes " << std::endl; + auto err_msg = rocalGetErrorMessage(handle); + std::cerr << err_msg << std::endl; + } + // Calling the API to verify and build the augmentation graph + if (rocalVerify(handle) != ROCAL_OK) { + std::cerr << "Could not verify the augmentation graph" << std::endl; + return -1; + } + + /*>>>>>>>>>>>>>>>>>>> Diplay using OpenCV <<<<<<<<<<<<<<<<<*/ + cv::Mat mat_color; + const unsigned number_of_cols = 1; // no augmented case + int col_counter = 0; + printf("Going to process images\n"); + printf("Remaining images %lu \n", rocalGetRemainingImages(handle)); + high_resolution_clock::time_point t1 = high_resolution_clock::now(); + int index = 0; + bool eos = false; + int total_images = file_names.size(); + int counter = 0; + std::vector names; + std::vector labels; + bool set_labels = true; + names.resize(input_batch_size); + labels.resize(total_images); + RocalTensorList output_tensor_list; + auto cv_color_format = ((color_format == RocalImageColor::ROCAL_COLOR_RGB24) ? ((tensor_output_type == RocalTensorOutputType::ROCAL_FP32) ? CV_32FC3 : CV_8UC3) : CV_8UC1); + std::vector ROI_xywh; + ROI_xywh.resize(input_batch_size); + while (static_cast(rocalGetRemainingImages(handle)) >= input_batch_size) { + std::vector input_images; + std::vector input_batch_buffer; + std::vector label_buffer; + for (int i = 0; i < input_batch_size; i++) { + if (mode == 0) { + input_images.push_back(file_names.back()); + file_names.pop_back(); + if ((file_names.size()) == 0) { + eos = true; + } + label_buffer.push_back(labels.back()); + labels.pop_back(); + } else { + if (mode == 1) { + input_batch_buffer.push_back(input_buffer.back()); + input_buffer.pop_back(); + ROI_xywh[i].h = srcsize_height.back(); + srcsize_height.pop_back(); + label_buffer.push_back(labels.back()); + labels.pop_back(); + } else { + input_batch_buffer.push_back(input_buffer.back()); + input_buffer.pop_back(); + ROI_xywh[i].w = srcsize_width.back(); + srcsize_width.pop_back(); + ROI_xywh[i].h = srcsize_height.back(); + srcsize_height.pop_back(); + label_buffer.push_back(labels.back()); + labels.pop_back(); + } + if ((file_names.size()) == 0 || input_buffer.size() == 0) { + eos = true; + } + } + } + if (index + 1 <= (total_images / input_batch_size)) { + std::cerr << "\n************************** Gonna process Batch *************************" << index; + std::cerr << "\n Mode ********************* " << mode; + if (mode == 0) { + rocalExternalSourceFeedInput(handle, input_images, set_labels, {}, ROI_xywh, + decode_width, decode_height, channels, + RocalExternalSourceMode(0), + RocalTensorLayout(0), eos); + } else if (mode == 1) { + rocalExternalSourceFeedInput(handle, {}, set_labels, input_batch_buffer, + ROI_xywh, decode_width, decode_height, + channels, RocalExternalSourceMode(mode), + RocalTensorLayout(0), eos); + } else if (mode == 2) { + rocalExternalSourceFeedInput(handle, {}, set_labels, input_batch_buffer, + ROI_xywh, max_width, max_height, + channels, RocalExternalSourceMode(mode), + RocalTensorLayout(0), eos); + } + } + if (rocalRun(handle) != 0) { + std::cerr << "rocalRun(handle) != 0 --- breaking"; + break; + } + + if (!display) continue; + // Dump the output image + output_tensor_list = rocalGetOutputTensors(handle); + std::vector compression_params; + compression_params.push_back(IMWRITE_PNG_COMPRESSION); + compression_params.push_back(9); + + cv::Mat mat_input; + cv::Mat mat_output; + int h = 0, w = 0 ; + for (uint64_t idx = 0; idx < output_tensor_list->size(); idx++) { + if (output_tensor_list->at(idx)->layout() == RocalTensorLayout::ROCAL_NHWC) { + h = output_tensor_list->at(idx)->dims().at(1) * output_tensor_list->at(idx)->dims().at(0); + w = output_tensor_list->at(idx)->dims().at(2); + } + + mat_input = cv::Mat(h, w, cv_color_format); + mat_output = cv::Mat(h, w, cv_color_format); + unsigned char *out_buffer = nullptr; + if (output_tensor_list->at(idx)->data_type() == RocalTensorOutputType::ROCAL_FP32) { + float *out_f_buffer = nullptr; + if (output_tensor_list->at(idx)->backend() == RocalTensorBackend::ROCAL_GPU) { + out_f_buffer = (float *)malloc(output_tensor_list->at(idx)->data_size()); + output_tensor_list->at(idx)->copy_data(out_f_buffer); + } else if (output_tensor_list->at(idx)->backend() == RocalTensorBackend::ROCAL_CPU) + out_f_buffer = (float *)output_tensor_list->at(idx)->buffer(); + + out_buffer = (unsigned char *)malloc(output_tensor_list->at(idx)->data_size() / 4); + convert_float_to_uchar_buffer(out_f_buffer, out_buffer, output_tensor_list->at(idx)->data_size() / 4); + // if(out_f_buffer != nullptr) free(out_f_buffer); + } + if (output_tensor_list->at(idx)->data_type() == RocalTensorOutputType::ROCAL_FP16) { + half *out_f16_buffer = nullptr; + if (output_tensor_list->at(idx)->backend() == RocalTensorBackend::ROCAL_GPU) { + out_f16_buffer = (half *)malloc(output_tensor_list->at(idx)->data_size()); + output_tensor_list->at(idx)->copy_data(out_f16_buffer); + } else if (output_tensor_list->at(idx)->backend() == RocalTensorBackend::ROCAL_CPU) + out_f16_buffer = (half *)output_tensor_list->at(idx)->buffer(); + + out_buffer = (unsigned char *)malloc(output_tensor_list->at(idx)->data_size() / 2); + convert_float_to_uchar_buffer(out_f16_buffer, out_buffer, output_tensor_list->at(idx)->data_size() / 2); + // if(out_f16_buffer != nullptr) free(out_f16_buffer); + } else { + if (output_tensor_list->at(idx)->backend() == RocalTensorBackend::ROCAL_GPU) { + out_buffer = (unsigned char *)malloc(output_tensor_list->at(idx)->data_size()); + output_tensor_list->at(idx)->copy_data(out_buffer); + } else if (output_tensor_list->at(idx)->backend() == RocalTensorBackend::ROCAL_CPU) + out_buffer = (unsigned char *)(output_tensor_list->at(idx)->buffer()); + } + + mat_input.data = (unsigned char *)out_buffer; + + mat_input.copyTo(mat_output(cv::Rect(0, 0, w, h))); + std::string outName = "external_source_output"; + std::string out_filename = outName + ".png"; // in case the user specifies non png filename + if (display) + out_filename = outName + std::to_string(index) + std::to_string(idx) + ".png"; // in case the user specifies non png filename + + if (color_format == RocalImageColor::ROCAL_COLOR_RGB24) { + cv::cvtColor(mat_output, mat_color, CV_RGB2BGR); + cv::imwrite(out_filename, mat_color, compression_params); + } else { + cv::imwrite(out_filename, mat_output, compression_params); + } + // if(out_buffer != nullptr) free(out_buffer); + } + mat_input.release(); + mat_output.release(); + + cv::waitKey(1); + + uint pipeline_type = 1; // External Source Reader Support given for the classification pipeline only + switch (pipeline_type) { + case 1: // classification pipeline + { + if(set_labels) + { + auto labels_tensor_list = rocalGetImageLabels(handle); + int *labels_ptr = static_cast(label_buffer.data()); + for (size_t i = 0; i < label_buffer.size(); i++) { + labels_tensor_list->at(i)->set_mem_handle(labels_ptr); + std::cerr << ">>>>> LABELS : " << labels_ptr[0] << "\t"; + labels_ptr++; + } + } + else + std::cerr<<"\n labels are not set"; + } break; + default: { + std::cerr << "Not a valid pipeline type ! Exiting!\n"; + return -1; + } + } + col_counter = (col_counter + 1) % number_of_cols; + index++; + counter += input_batch_size; + } + + high_resolution_clock::time_point t2 = high_resolution_clock::now(); + auto dur = duration_cast(t2 - t1).count(); + auto rocal_timing = rocalGetTimingInfo(handle); + std::cerr << std::endl; + std::cerr << "Load time " << rocal_timing.load_time << std::endl; + std::cerr << "Decode time " << rocal_timing.decode_time << std::endl; + std::cerr << "Process time " << rocal_timing.process_time << std::endl; + std::cerr << "Transfer time " << rocal_timing.transfer_time << std::endl; + std::cerr << ">>>>> " << counter + << " images/frames Processed. Total Elapsed Time " << dur / 1000000 + << " sec " << dur % 1000000 << " us " << std::endl; + rocalRelease(handle); + return 0; +}