From 2b5f0f2574551f59970bb9d710bafad2bc4bbd4a Mon Sep 17 00:00:00 2001 From: Michalis Spyrou Date: Wed, 10 Jan 2018 14:08:50 +0000 Subject: COMPMID-782 Port examples to the new format Change-Id: Ib178a97c080ff650094d02ee49e2a0aa22376dd0 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/115717 Reviewed-by: Anthony Barbier Tested-by: Jenkins --- examples/cl_events.cpp | 132 +++++----- examples/cl_sgemm.cpp | 272 ++++++++++---------- examples/gc_absdiff.cpp | 122 +++++---- examples/gc_dc.cpp | 141 +++++----- examples/graph_alexnet.cpp | 226 ++++++++-------- examples/graph_googlenet.cpp | 292 +++++++++++---------- examples/graph_lenet.cpp | 151 +++++------ examples/graph_mobilenet.cpp | 244 +++++++++--------- examples/graph_squeezenet.cpp | 294 +++++++++++---------- examples/graph_vgg16.cpp | 340 ++++++++++++------------ examples/graph_vgg19.cpp | 358 +++++++++++++------------- examples/neon_cartoon_effect.cpp | 109 ++++---- examples/neon_cnn.cpp | 415 +++++++++++++++--------------- examples/neon_convolution.cpp | 102 ++++---- examples/neon_copy_objects.cpp | 208 ++++++++------- examples/neon_scale.cpp | 91 ++++--- examples/neoncl_scale_median_gaussian.cpp | 145 ++++++----- utils/Utils.cpp | 35 --- utils/Utils.h | 17 -- 19 files changed, 1886 insertions(+), 1808 deletions(-) diff --git a/examples/cl_events.cpp b/examples/cl_events.cpp index c9c3e5d039..ec02fc30f9 100644 --- a/examples/cl_events.cpp +++ b/examples/cl_events.cpp @@ -33,78 +33,88 @@ using namespace arm_compute; using namespace utils; -void main_cl_events(int argc, char **argv) +class CLEventsExample : public Example { - /** [OpenCL events] **/ - PPMLoader ppm; - CLImage src, tmp_scale_median, tmp_median_gauss, dst; - constexpr int scale_factor = 2; - - CLScheduler::get().default_init(); - - if(argc < 2) - { - // Print help - std::cout << "Usage: ./build/cl_events [input_image.ppm]\n\n"; - std::cout << "No input_image provided, creating a dummy 640x480 image\n"; - // Create an empty grayscale 640x480 image - src.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else +public: + void do_setup(int argc, char **argv) override { - ppm.open(argv[1]); - ppm.init_image(src, Format::U8); - } + /** [OpenCL events] **/ + PPMLoader ppm; + constexpr int scale_factor = 2; - // Declare and configure the functions to create the following pipeline: scale -> median -> gauss - CLScale scale; - CLMedian3x3 median; - CLGaussian5x5 gauss; + CLScheduler::get().default_init(); - TensorInfo dst_info(src.info()->dimension(0) / scale_factor, src.info()->dimension(1) / scale_factor, Format::U8); + if(argc < 2) + { + // Print help + std::cout << "Usage: ./build/cl_events [input_image.ppm]\n\n"; + std::cout << "No input_image provided, creating a dummy 640x480 image\n"; + // Create an empty grayscale 640x480 image + src.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm.open(argv[1]); + ppm.init_image(src, Format::U8); + } - // Configure the temporary and destination images - dst.allocator()->init(dst_info); - tmp_scale_median.allocator()->init(dst_info); - tmp_median_gauss.allocator()->init(dst_info); + TensorInfo dst_info(src.info()->dimension(0) / scale_factor, src.info()->dimension(1) / scale_factor, Format::U8); - //Configure the functions: - scale.configure(&src, &tmp_scale_median, InterpolationPolicy::NEAREST_NEIGHBOR, BorderMode::REPLICATE); - median.configure(&tmp_scale_median, &tmp_median_gauss, BorderMode::REPLICATE); - gauss.configure(&tmp_median_gauss, &dst, BorderMode::REPLICATE); + // Configure the temporary and destination images + dst.allocator()->init(dst_info); + tmp_scale_median.allocator()->init(dst_info); + tmp_median_gauss.allocator()->init(dst_info); - // Allocate all the images - src.allocator()->allocate(); - dst.allocator()->allocate(); - tmp_scale_median.allocator()->allocate(); - tmp_median_gauss.allocator()->allocate(); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm.is_open()) - { - ppm.fill_image(src); - } + //Configure the functions: + scale.configure(&src, &tmp_scale_median, InterpolationPolicy::NEAREST_NEIGHBOR, BorderMode::REPLICATE); + median.configure(&tmp_scale_median, &tmp_median_gauss, BorderMode::REPLICATE); + gauss.configure(&tmp_median_gauss, &dst, BorderMode::REPLICATE); - // Enqueue and flush the scale OpenCL kernel: - scale.run(); - // Create a synchronisation event between scale and median: - cl::Event scale_event = CLScheduler::get().enqueue_sync_event(); - // Enqueue and flush the median OpenCL kernel: - median.run(); - // Enqueue and flush the Gaussian OpenCL kernel: - gauss.run(); + // Allocate all the images + src.allocator()->allocate(); + dst.allocator()->allocate(); + tmp_scale_median.allocator()->allocate(); + tmp_median_gauss.allocator()->allocate(); - //Make sure all the OpenCL jobs are done executing: - scale_event.wait(); // Block until Scale is done executing (Median3x3 and Gaussian5x5 might still be running) - CLScheduler::get().sync(); // Block until Gaussian5x5 is done executing + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm.is_open()) + { + ppm.fill_image(src); + output_filename = std::string(argv[1]) + "_out.ppm"; + } + /** [OpenCL events] **/ + } + void do_run() override + { + // Enqueue and flush the scale OpenCL kernel: + scale.run(); + // Create a synchronisation event between scale and median: + cl::Event scale_event = CLScheduler::get().enqueue_sync_event(); + // Enqueue and flush the median OpenCL kernel: + median.run(); + // Enqueue and flush the Gaussian OpenCL kernel: + gauss.run(); - // Save the result to file: - if(ppm.is_open()) + //Make sure all the OpenCL jobs are done executing: + scale_event.wait(); // Block until Scale is done executing (Median3x3 and Gaussian5x5 might still be running) + CLScheduler::get().sync(); // Block until Gaussian5x5 is done executing + } + void do_teardown() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + // Save the result to file: + if(!output_filename.empty()) + { + save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + } } - /** [OpenCL events] **/ -} + +private: + CLImage src{}, tmp_scale_median{}, tmp_median_gauss{}, dst{}; + CLScale scale{}; + CLMedian3x3 median{}; + CLGaussian5x5 gauss{}; + std::string output_filename{}; +}; /** Main program for convolution test * @@ -113,5 +123,5 @@ void main_cl_events(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_cl_events); + return utils::run_example(argc, argv); } diff --git a/examples/cl_sgemm.cpp b/examples/cl_sgemm.cpp index 939870fabf..f2c63985f6 100644 --- a/examples/cl_sgemm.cpp +++ b/examples/cl_sgemm.cpp @@ -36,174 +36,184 @@ using namespace arm_compute; using namespace utils; -void main_cl_sgemm(int argc, char **argv) +class CLSGEMMExample : public Example { - NPYLoader npy0, npy1, npy2; - CLTensor src0, src1, src2, dst; - float alpha = 1.0f, beta = 0.0f; - - CLTuner tuner; - CLScheduler::get().default_init(&tuner); - - std::ifstream stream; - if(argc > 1) +public: + void do_setup(int argc, char **argv) override { - stream.open(argv[1], std::fstream::in); - } + NPYLoader npy0, npy1, npy2; + alpha = 1.0f; + beta = 0.0f; - if(argc < 3 || (argc < 4 && stream.bad())) - { - // Print help - std::cout << "Usage: 1) ./build/cl_sgemm input_matrix_1.npy input_matrix_2.npy [input_matrix_3.npy] [alpha = 1] [beta = 0]\n"; - std::cout << " 2) ./build/cl_sgemm M N K [alpha = 1.0f] [beta = 0.0f]\n\n"; - std::cout << "Too few or no input_matrices provided. Using M=7, N=3, K=5, alpha=1.0f and beta=0.0f\n\n"; - - src0.allocator()->init(TensorInfo(TensorShape(5U, 7U), 1, DataType::F32)); - src1.allocator()->init(TensorInfo(TensorShape(3U, 5U), 1, DataType::F32)); - src2.allocator()->init(TensorInfo(TensorShape(3U, 7U), 1, DataType::F32)); - } - else - { - if(stream.good()) /* case file1.npy file2.npy [file3.npy] [alpha = 1.0f] [beta = 0.0f] */ + CLScheduler::get().default_init(&tuner); + + std::ifstream stream; + if(argc > 1) { - npy0.open(argv[1]); - npy0.init_tensor(src0, DataType::F32); - npy1.open(argv[2]); - npy1.init_tensor(src1, DataType::F32); + stream.open(argv[1], std::fstream::in); + } - if(argc > 3) + if(argc < 3 || (argc < 4 && stream.bad())) + { + // Print help + std::cout << "Usage: 1) ./build/cl_sgemm input_matrix_1.npy input_matrix_2.npy [input_matrix_3.npy] [alpha = 1] [beta = 0]\n"; + std::cout << " 2) ./build/cl_sgemm M N K [alpha = 1.0f] [beta = 0.0f]\n\n"; + std::cout << "Too few or no input_matrices provided. Using M=7, N=3, K=5, alpha=1.0f and beta=0.0f\n\n"; + + src0.allocator()->init(TensorInfo(TensorShape(5U, 7U), 1, DataType::F32)); + src1.allocator()->init(TensorInfo(TensorShape(3U, 5U), 1, DataType::F32)); + src2.allocator()->init(TensorInfo(TensorShape(3U, 7U), 1, DataType::F32)); + } + else + { + if(stream.good()) /* case file1.npy file2.npy [file3.npy] [alpha = 1.0f] [beta = 0.0f] */ { - stream.close(); - stream.clear(); - stream.open(argv[3], std::fstream::in); - if(stream.good()) /* case with third file */ - { - npy2.open(argv[3]); - npy2.init_tensor(src2, DataType::F32); + npy0.open(argv[1]); + npy0.init_tensor(src0, DataType::F32); + npy1.open(argv[2]); + npy1.init_tensor(src1, DataType::F32); - if(argc > 4) + if(argc > 3) + { + stream.close(); + stream.clear(); + stream.open(argv[3], std::fstream::in); + if(stream.good()) /* case with third file */ { - // Convert string to float - alpha = strtof(argv[4], nullptr); + npy2.open(argv[3]); + npy2.init_tensor(src2, DataType::F32); - if(argc > 5) + if(argc > 4) { // Convert string to float - beta = strtof(argv[5], nullptr); + alpha = strtof(argv[4], nullptr); + + if(argc > 5) + { + // Convert string to float + beta = strtof(argv[5], nullptr); + } } } - } - else /* case without third file */ - { - alpha = strtof(argv[3], nullptr); - - if(argc > 4) + else /* case without third file */ { - beta = strtof(argv[4], nullptr); + alpha = strtof(argv[3], nullptr); + + if(argc > 4) + { + beta = strtof(argv[4], nullptr); + } } } } - } - else /* case M N K [alpha = 1.0f] [beta = 0.0f] */ - { - size_t M = strtol(argv[1], nullptr, 10); - size_t N = strtol(argv[2], nullptr, 10); - size_t K = strtol(argv[3], nullptr, 10); - - src0.allocator()->init(TensorInfo(TensorShape(K, M), 1, DataType::F32)); - src1.allocator()->init(TensorInfo(TensorShape(N, K), 1, DataType::F32)); - src2.allocator()->init(TensorInfo(TensorShape(N, M), 1, DataType::F32)); - - if(argc > 4) + else /* case M N K [alpha = 1.0f] [beta = 0.0f] */ { - alpha = strtof(argv[4], nullptr); + size_t M = strtol(argv[1], nullptr, 10); + size_t N = strtol(argv[2], nullptr, 10); + size_t K = strtol(argv[3], nullptr, 10); + + src0.allocator()->init(TensorInfo(TensorShape(K, M), 1, DataType::F32)); + src1.allocator()->init(TensorInfo(TensorShape(N, K), 1, DataType::F32)); + src2.allocator()->init(TensorInfo(TensorShape(N, M), 1, DataType::F32)); - if(argc > 5) + if(argc > 4) { - beta = strtof(argv[5], nullptr); + alpha = strtof(argv[4], nullptr); + + if(argc > 5) + { + beta = strtof(argv[5], nullptr); + } } } } - } - init_sgemm_output(dst, src0, src1, DataType::F32); + init_sgemm_output(dst, src0, src1, DataType::F32); - // Configure function - CLGEMM sgemm; - sgemm.configure(&src0, &src1, (src2.info()->total_size() > 0) ? &src2 : nullptr, &dst, alpha, beta); + // Configure function + sgemm.configure(&src0, &src1, (src2.info()->total_size() > 0) ? &src2 : nullptr, &dst, alpha, beta); - // Allocate all the images - src0.allocator()->allocate(); - src1.allocator()->allocate(); - dst.allocator()->allocate(); + // Allocate all the images + src0.allocator()->allocate(); + src1.allocator()->allocate(); + dst.allocator()->allocate(); - // Fill the input images with either the data provided or random data - if(npy0.is_open()) - { - npy0.fill_tensor(src0); - npy1.fill_tensor(src1); + // Fill the input images with either the data provided or random data + if(npy0.is_open()) + { + npy0.fill_tensor(src0); + npy1.fill_tensor(src1); + + output_filename = "sgemm_out.npy"; + is_fortran = npy0.is_fortran(); - if(npy2.is_open()) + if(npy2.is_open()) + { + src2.allocator()->allocate(); + npy2.fill_tensor(src2); + } + } + else { src2.allocator()->allocate(); - npy2.fill_tensor(src2); + + fill_random_tensor(src0, -1.f, 1.f); + fill_random_tensor(src1, -1.f, 1.f); + fill_random_tensor(src2, -1.f, 1.f); } - } - else - { - src2.allocator()->allocate(); - fill_random_tensor(src0, -1.f, 1.f); - fill_random_tensor(src1, -1.f, 1.f); - fill_random_tensor(src2, -1.f, 1.f); + // Dummy run for CLTuner + sgemm.run(); } - - // Dummy run for CLTuner - sgemm.run(); - - auto start = std::chrono::high_resolution_clock::now(); - - // Execute the function - sgemm.run(); - - // Make sure all the OpenCL jobs are done executing: - CLScheduler::get().sync(); - - auto stop = std::chrono::high_resolution_clock::now(); - - if(!npy0.is_open()) /* If the inputs were not files, print the results */ + void do_run() override { - std::cout << "\nMatrix 1:" << std::endl; - src0.map(true); - src0.print(std::cout, IOFormatInfo()); - src0.unmap(); - - std::cout << "Matrix 2:" << std::endl; - src1.map(true); - src1.print(std::cout, IOFormatInfo()); - src1.unmap(); - - std::cout << "Matrix 3:" << std::endl; - src2.map(true); - src2.print(std::cout, IOFormatInfo()); - src2.unmap(); - - std::cout << "Alpha:" << alpha << "\n\n"; - std::cout << "Beta:" << beta << "\n\n"; - - std::cout << "Output Matrix:" << std::endl; - dst.map(true); - dst.print(std::cout, IOFormatInfo()); - dst.unmap(); + // Execute the function + sgemm.run(); + + // Make sure all the OpenCL jobs are done executing: + CLScheduler::get().sync(); } - else /* Save to .npy file */ + void do_teardown() override { - save_to_npy(dst, "sgemm_out.npy", npy0.is_fortran()); + if(output_filename.empty()) /* If the inputs were not files, print the results */ + { + std::cout << "\nMatrix 1:" << std::endl; + src0.map(true); + src0.print(std::cout, IOFormatInfo()); + src0.unmap(); + + std::cout << "Matrix 2:" << std::endl; + src1.map(true); + src1.print(std::cout, IOFormatInfo()); + src1.unmap(); + + std::cout << "Matrix 3:" << std::endl; + src2.map(true); + src2.print(std::cout, IOFormatInfo()); + src2.unmap(); + + std::cout << "Alpha:" << alpha << "\n\n"; + std::cout << "Beta:" << beta << "\n\n"; + + std::cout << "Output Matrix:" << std::endl; + dst.map(true); + dst.print(std::cout, IOFormatInfo()); + dst.unmap(); + } + else /* Save to .npy file */ + { + save_to_npy(dst, output_filename, is_fortran); + } } - auto delta = std::chrono::duration_cast(stop - start); - std::cout << "Time elapsed: " << delta.count() << "us." << std::endl; -} +private: + CLTensor src0{}, src1{}, src2{}, dst{}; + CLGEMM sgemm{}; + CLTuner tuner{}; + float alpha{}, beta{}; + bool is_fortran{}; + std::string output_filename{}; +}; /** Main program for sgemm test * @@ -212,5 +222,5 @@ void main_cl_sgemm(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_cl_sgemm); + return utils::run_example(argc, argv); } diff --git a/examples/gc_absdiff.cpp b/examples/gc_absdiff.cpp index 997feed8e8..32f946d421 100644 --- a/examples/gc_absdiff.cpp +++ b/examples/gc_absdiff.cpp @@ -34,71 +34,83 @@ using namespace arm_compute; using namespace utils; -void main_gc_absdiff(int argc, char **argv) +class GCAbsDiffExample : public Example { - PPMLoader ppm1, ppm2; - GCImage src1, src2, dst; - GCScheduler::get().default_init(); - if(argc < 2) +public: + void do_setup(int argc, char **argv) override { - // Print help - std::cout << "Usage: " << argv[0] << " [input0_image.ppm] [input1_image.ppm] \n\n"; - std::cout << "No input_image provided, creating two dummy 640x480 images\n"; - // Create two empty grayscale 640x480 images - src1.allocator()->init(TensorInfo(640, 480, Format::U8)); - src2.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else if(argc < 3) - { - // Print help - std::cout << "Usage: " << argv[0] << " [input0_image.ppm] [input1_image.ppm] \n\n"; - std::cout << "Only one input_image provided, creating a dummy 640x480 image\n"; - ppm1.open(argv[1]); - ppm1.init_image(src1, Format::U8); - // Create an empty grayscale 640x480 image - src2.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else - { - ppm1.open(argv[1]); - ppm1.init_image(src1, Format::U8); - ppm2.open(argv[2]); - ppm2.init_image(src2, Format::U8); - } + PPMLoader ppm1, ppm2; - // Configure the temporary and destination images - dst.allocator()->init(*src1.info()); + GCScheduler::get().default_init(); + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [input0_image.ppm] [input1_image.ppm] \n\n"; + std::cout << "No input_image provided, creating two dummy 640x480 images\n"; + // Create two empty grayscale 640x480 images + src1.allocator()->init(TensorInfo(640, 480, Format::U8)); + src2.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else if(argc < 3) + { + // Print help + std::cout << "Usage: " << argv[0] << " [input0_image.ppm] [input1_image.ppm] \n\n"; + std::cout << "Only one input_image provided, creating a dummy 640x480 image\n"; + ppm1.open(argv[1]); + ppm1.init_image(src1, Format::U8); + // Create an empty grayscale 640x480 image + src2.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm1.open(argv[1]); + ppm1.init_image(src1, Format::U8); + ppm2.open(argv[2]); + ppm2.init_image(src2, Format::U8); + } - GCAbsoluteDifference absdiff; - absdiff.configure(&src1, &src2, &dst); + // Configure the temporary and destination images + dst.allocator()->init(*src1.info()); - // Allocate all the images - src1.allocator()->allocate(); - src2.allocator()->allocate(); - dst.allocator()->allocate(); + absdiff.configure(&src1, &src2, &dst); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm1.is_open()) - { - ppm1.fill_image(src1); + // Allocate all the images + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm1.is_open()) + { + ppm1.fill_image(src1); + output_filename = std::string(argv[1]) + "_out.ppm"; + } + if(ppm2.is_open()) + { + ppm2.fill_image(src2); + } } - if(ppm2.is_open()) + void do_run() override { - ppm2.fill_image(src2); + // Execute the functions: + absdiff.run(); } - - // Execute the functions: - absdiff.run(); - - // Save the result to file: - if(ppm1.is_open()) + void do_teardown() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - // save_to_ppm maps and unmaps the image to store as PPM - // The GCTensor::map call inside the save_to_ppm will block until all pending operations on that image have completed - save_to_ppm(dst, output_filename); + // Save the result to file: + if(!output_filename.empty()) + { + // save_to_ppm maps and unmaps the image to store as PPM + // The GCTensor::map call inside the save_to_ppm will block until all pending operations on that image have completed + save_to_ppm(dst, output_filename); + } } -} + +private: + GCImage src1{}, src2{}, dst{}; + GCAbsoluteDifference absdiff{}; + std::string output_filename{}; +}; /** Main program for absdiff test * @@ -107,5 +119,5 @@ void main_gc_absdiff(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_gc_absdiff); + return utils::run_example(argc, argv); } diff --git a/examples/gc_dc.cpp b/examples/gc_dc.cpp index 174c88458d..8b6f4414e0 100644 --- a/examples/gc_dc.cpp +++ b/examples/gc_dc.cpp @@ -33,84 +33,91 @@ using namespace arm_compute; using namespace utils; -namespace +class GCDCExample : public Example { -TensorShape get_output_shape(TensorShape in_shape, TensorShape kernel_shape, const PadStrideInfo &info) -{ - TensorShape out_shape(in_shape); - const std::pair scaled_dims = scaled_dimensions(in_shape.x(), - in_shape.y(), - kernel_shape.x(), - kernel_shape.y(), - info); - out_shape.set(0, scaled_dims.first); - out_shape.set(1, scaled_dims.second); - out_shape.set(2, kernel_shape[3]); - return out_shape; -} -} // namespace - -void main_gc_dc(int argc, char **argv) -{ - ARM_COMPUTE_UNUSED(argc); - ARM_COMPUTE_UNUSED(argv); +public: + void do_setup(int argc, char **argv) override + { + ARM_COMPUTE_UNUSED(argc); + ARM_COMPUTE_UNUSED(argv); - // init instance - GCScheduler::get().default_init(); + // init instance + GCScheduler::get().default_init(); - const TensorShape src_shape = TensorShape{ 11U /* W */, 13U /* H */, 4U /* C */, 3U /* N */ }; - const unsigned int kernel_size = 3; - const int stride_x = 1; - const int stride_y = 1; - const int pad_x = 0; - const int pad_y = 0; - const unsigned int num_kernels = 256; - const DataType data_type = DataType::F16; + const TensorShape src_shape = TensorShape{ 11U /* W */, 13U /* H */, 4U /* C */, 3U /* N */ }; + const unsigned int kernel_size = 3; + const int stride_x = 1; + const int stride_y = 1; + const int pad_x = 0; + const int pad_y = 0; + const unsigned int num_kernels = 256; + const DataType data_type = DataType::F16; - // generate shape - const TensorShape weights_shape(kernel_size, kernel_size, src_shape.z(), num_kernels); - const TensorShape bias_shape(num_kernels); - const PadStrideInfo pad_info(stride_x, stride_y, pad_x, pad_y, DimensionRoundingType::FLOOR); + // generate shape + const TensorShape weights_shape(kernel_size, kernel_size, src_shape.z(), num_kernels); + const TensorShape bias_shape(num_kernels); + const PadStrideInfo pad_info(stride_x, stride_y, pad_x, pad_y, DimensionRoundingType::FLOOR); - // output shape should be 9*11*256*3 (W*H*C*N) - const TensorShape dst_shape = get_output_shape(src_shape, weights_shape, pad_info); + // output shape should be 9*11*256*3 (W*H*C*N) + const TensorShape dst_shape = get_output_shape(src_shape, weights_shape, pad_info); - // create tensors - GCTensor src, weights, bias, dst; - src.allocator()->init(TensorInfo(src_shape, 1, data_type)); - weights.allocator()->init(TensorInfo(weights_shape, 1, data_type)); - bias.allocator()->init(TensorInfo(bias_shape, 1, data_type)); - dst.allocator()->init(TensorInfo(dst_shape, 1, data_type)); + // create tensors + src.allocator()->init(TensorInfo(src_shape, 1, data_type)); + weights.allocator()->init(TensorInfo(weights_shape, 1, data_type)); + bias.allocator()->init(TensorInfo(bias_shape, 1, data_type)); + dst.allocator()->init(TensorInfo(dst_shape, 1, data_type)); - // configure layer - GCDirectConvolutionLayer conv; - conv.configure(&src, &weights, &bias, &dst, pad_info); + // configure layer + conv.configure(&src, &weights, &bias, &dst, pad_info); - // allocate tensors - src.allocator()->allocate(); - weights.allocator()->allocate(); - bias.allocator()->allocate(); - dst.allocator()->allocate(); + // allocate tensors + src.allocator()->allocate(); + weights.allocator()->allocate(); + bias.allocator()->allocate(); + dst.allocator()->allocate(); - // To demonstrate how to fill tensor with some values... - src.map(); - Window window; - window.use_tensor_dimensions(src_shape); - Iterator it(&src, window); - execute_window_loop(window, [&](const Coordinates & id) + // To demonstrate how to fill tensor with some values... + src.map(); + Window window; + window.use_tensor_dimensions(src_shape); + Iterator it(&src, window); + execute_window_loop(window, [&](const Coordinates & id) + { + *reinterpret_cast(it.ptr()) = half_float::half(1.f); + }); + src.unmap(); + } + void do_run() override + { + // run the layer + conv.run(); + } + void do_teardown() override { - *reinterpret_cast(it.ptr()) = half_float::half(1.f); - }); - src.unmap(); + // check result + dst.map(); + // do something + dst.unmap(); + } - // run the layer - conv.run(); +private: + GCTensor src{}, weights{}, bias{}, dst{}; + GCDirectConvolutionLayer conv{}; - // check result - dst.map(); - // do something - dst.unmap(); -} + TensorShape get_output_shape(TensorShape in_shape, TensorShape kernel_shape, const PadStrideInfo &info) + { + TensorShape out_shape(in_shape); + const std::pair scaled_dims = scaled_dimensions(in_shape.x(), + in_shape.y(), + kernel_shape.x(), + kernel_shape.y(), + info); + out_shape.set(0, scaled_dims.first); + out_shape.set(1, scaled_dims.second); + out_shape.set(2, kernel_shape[3]); + return out_shape; + } +}; /** Main program for directconvolution test * @@ -119,5 +126,5 @@ void main_gc_dc(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_gc_dc); + return utils::run_example(argc, argv); } diff --git a/examples/graph_alexnet.cpp b/examples/graph_alexnet.cpp index 6423fe48d3..8705c8ed1e 100644 --- a/examples/graph_alexnet.cpp +++ b/examples/graph_alexnet.cpp @@ -31,6 +31,7 @@ #include #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; @@ -39,122 +40,129 @@ using namespace arm_compute::graph_utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_alexnet(int argc, char **argv) +class GraphAlexnetExample : public Example { - std::string data_path; /* Path to the trainable data */ - std::string image; /* Image data */ - std::string label; /* Label data */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /* Path to the trainable data */ + std::string image; /* Image data */ + std::string label; /* Label data */ - constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ - constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ - constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ + constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ + constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ + constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; - std::cout << "No image provided: using random values\n\n"; - } - else if(argc == 4) - { - data_path = argv[2]; - image = argv[3]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; - std::cout << "No text file with labels provided: skipping output accessor\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; + std::cout << "No image provided: using random values\n\n"; + } + else if(argc == 4) + { + data_path = argv[2]; + image = argv[3]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; + std::cout << "No text file with labels provided: skipping output accessor\n\n"; + } + else + { + data_path = argv[2]; + image = argv[3]; + label = argv[4]; + } + + graph << target_hint + << Tensor(TensorInfo(TensorShape(227U, 227U, 3U, 1U), 1, DataType::F32), + get_input_accessor(image, mean_r, mean_g, mean_b)) + // Layer 1 + << ConvolutionLayer( + 11U, 11U, 96U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv1_b.npy"), + PadStrideInfo(4, 4, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))) + // Layer 2 + << convolution_hint + << ConvolutionLayer( + 5U, 5U, 256U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv2_b.npy"), + PadStrideInfo(1, 1, 2, 2), 2) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))) + // Layer 3 + << ConvolutionLayer( + 3U, 3U, 384U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 4 + << ConvolutionLayer( + 3U, 3U, 384U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv4_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv4_b.npy"), + PadStrideInfo(1, 1, 1, 1), 2) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 5 + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv5_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv5_b.npy"), + PadStrideInfo(1, 1, 1, 1), 2) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))) + // Layer 6 + << FullyConnectedLayer( + 4096U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc6_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc6_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 7 + << FullyConnectedLayer( + 4096U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc7_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc7_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 8 + << FullyConnectedLayer( + 1000U, + get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc8_w.npy"), + get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc8_b.npy")) + // Softmax + << SoftmaxLayer() + << Tensor(get_output_accessor(label, 5)); } - else + void do_run() override { - data_path = argv[2]; - image = argv[3]; - label = argv[4]; + // Run graph + graph.run(); } - Graph graph; - - graph << target_hint - << Tensor(TensorInfo(TensorShape(227U, 227U, 3U, 1U), 1, DataType::F32), - get_input_accessor(image, mean_r, mean_g, mean_b)) - // Layer 1 - << ConvolutionLayer( - 11U, 11U, 96U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv1_b.npy"), - PadStrideInfo(4, 4, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))) - // Layer 2 - << convolution_hint - << ConvolutionLayer( - 5U, 5U, 256U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv2_b.npy"), - PadStrideInfo(1, 1, 2, 2), 2) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))) - // Layer 3 - << ConvolutionLayer( - 3U, 3U, 384U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 4 - << ConvolutionLayer( - 3U, 3U, 384U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv4_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv4_b.npy"), - PadStrideInfo(1, 1, 1, 1), 2) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 5 - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv5_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/conv5_b.npy"), - PadStrideInfo(1, 1, 1, 1), 2) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))) - // Layer 6 - << FullyConnectedLayer( - 4096U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc6_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc6_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 7 - << FullyConnectedLayer( - 4096U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc7_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc7_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 8 - << FullyConnectedLayer( - 1000U, - get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc8_w.npy"), - get_weights_accessor(data_path, "/cnn_data/alexnet_model/fc8_b.npy")) - // Softmax - << SoftmaxLayer() - << Tensor(get_output_accessor(label, 5)); - - // Run graph - graph.run(); -} +private: + Graph graph{}; +}; /** Main program for AlexNet * @@ -163,5 +171,5 @@ void main_graph_alexnet(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_alexnet); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/graph_googlenet.cpp b/examples/graph_googlenet.cpp index 746d558389..1e9601b492 100644 --- a/examples/graph_googlenet.cpp +++ b/examples/graph_googlenet.cpp @@ -31,167 +31,173 @@ #include #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; -namespace -{ -BranchLayer get_inception_node(const std::string &data_path, std::string &¶m_path, - unsigned int a_filt, - std::tuple b_filters, - std::tuple c_filters, - unsigned int d_filt) -{ - std::string total_path = "/cnn_data/googlenet_model/" + param_path + "/" + param_path + "_"; - SubGraph i_a; - i_a << ConvolutionLayer( - 1U, 1U, a_filt, - get_weights_accessor(data_path, total_path + "1x1_w.npy"), - get_weights_accessor(data_path, total_path + "1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - - SubGraph i_b; - i_b << ConvolutionLayer( - 1U, 1U, std::get<0>(b_filters), - get_weights_accessor(data_path, total_path + "3x3_reduce_w.npy"), - get_weights_accessor(data_path, total_path + "3x3_reduce_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, std::get<1>(b_filters), - get_weights_accessor(data_path, total_path + "3x3_w.npy"), - get_weights_accessor(data_path, total_path + "3x3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - - SubGraph i_c; - i_c << ConvolutionLayer( - 1U, 1U, std::get<0>(c_filters), - get_weights_accessor(data_path, total_path + "5x5_reduce_w.npy"), - get_weights_accessor(data_path, total_path + "5x5_reduce_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 5U, 5U, std::get<1>(c_filters), - get_weights_accessor(data_path, total_path + "5x5_w.npy"), - get_weights_accessor(data_path, total_path + "5x5_b.npy"), - PadStrideInfo(1, 1, 2, 2)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - - SubGraph i_d; - i_d << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL))) - << ConvolutionLayer( - 1U, 1U, d_filt, - get_weights_accessor(data_path, total_path + "pool_proj_w.npy"), - get_weights_accessor(data_path, total_path + "pool_proj_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - - return BranchLayer(BranchMergeMethod::DEPTH_CONCATENATE, std::move(i_a), std::move(i_b), std::move(i_c), std::move(i_d)); -} -} // namespace - /** Example demonstrating how to implement Googlenet's network using the Compute Library's graph API * * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_googlenet(int argc, char **argv) +class GraphGooglenetExample : public Example { - std::string data_path; /* Path to the trainable data */ - std::string image; /* Image data */ - std::string label; /* Label data */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /* Path to the trainable data */ + std::string image; /* Image data */ + std::string label; /* Label data */ - constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ - constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ - constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ + constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ + constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ + constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; - std::cout << "No image provided: using random values\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; + std::cout << "No image provided: using random values\n\n"; + } + else if(argc == 4) + { + data_path = argv[2]; + image = argv[3]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; + std::cout << "No text file with labels provided: skipping output accessor\n\n"; + } + else + { + data_path = argv[2]; + image = argv[3]; + label = argv[4]; + } + + graph << target_hint + << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), + get_input_accessor(image, mean_r, mean_g, mean_b)) + << ConvolutionLayer( + 7U, 7U, 64U, + get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv1/conv1_7x7_s2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv1/conv1_7x7_s2_b.npy"), + PadStrideInfo(2, 2, 3, 3)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) + << convolution_hint + << ConvolutionLayer( + 1U, 1U, 64U, + get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_reduce_w.npy"), + get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_reduce_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 192U, + get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << get_inception_node(data_path, "inception_3a", 64, std::make_tuple(96U, 128U), std::make_tuple(16U, 32U), 32U) + << get_inception_node(data_path, "inception_3b", 128, std::make_tuple(128U, 192U), std::make_tuple(32U, 96U), 64U) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << get_inception_node(data_path, "inception_4a", 192, std::make_tuple(96U, 208U), std::make_tuple(16U, 48U), 64U) + << get_inception_node(data_path, "inception_4b", 160, std::make_tuple(112U, 224U), std::make_tuple(24U, 64U), 64U) + << get_inception_node(data_path, "inception_4c", 128, std::make_tuple(128U, 256U), std::make_tuple(24U, 64U), 64U) + << get_inception_node(data_path, "inception_4d", 112, std::make_tuple(144U, 288U), std::make_tuple(32U, 64U), 64U) + << get_inception_node(data_path, "inception_4e", 256, std::make_tuple(160U, 320U), std::make_tuple(32U, 128U), 128U) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << get_inception_node(data_path, "inception_5a", 256, std::make_tuple(160U, 320U), std::make_tuple(32U, 128U), 128U) + << get_inception_node(data_path, "inception_5b", 384, std::make_tuple(192U, 384U), std::make_tuple(48U, 128U), 128U) + << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 7, PadStrideInfo(1, 1, 0, 0, DimensionRoundingType::CEIL))) + << FullyConnectedLayer( + 1000U, + get_weights_accessor(data_path, "/cnn_data/googlenet_model/loss3/loss3_classifier_w.npy"), + get_weights_accessor(data_path, "/cnn_data/googlenet_model/loss3/loss3_classifier_b.npy")) + << SoftmaxLayer() + << Tensor(get_output_accessor(label, 5)); } - else if(argc == 4) + void do_run() override { - data_path = argv[2]; - image = argv[3]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; - std::cout << "No text file with labels provided: skipping output accessor\n\n"; + // Run graph + graph.run(); } - else + +private: + Graph graph{}; + + BranchLayer get_inception_node(const std::string &data_path, std::string &¶m_path, + unsigned int a_filt, + std::tuple b_filters, + std::tuple c_filters, + unsigned int d_filt) { - data_path = argv[2]; - image = argv[3]; - label = argv[4]; - } + std::string total_path = "/cnn_data/googlenet_model/" + param_path + "/" + param_path + "_"; + SubGraph i_a; + i_a << ConvolutionLayer( + 1U, 1U, a_filt, + get_weights_accessor(data_path, total_path + "1x1_w.npy"), + get_weights_accessor(data_path, total_path + "1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - Graph graph; + SubGraph i_b; + i_b << ConvolutionLayer( + 1U, 1U, std::get<0>(b_filters), + get_weights_accessor(data_path, total_path + "3x3_reduce_w.npy"), + get_weights_accessor(data_path, total_path + "3x3_reduce_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, std::get<1>(b_filters), + get_weights_accessor(data_path, total_path + "3x3_w.npy"), + get_weights_accessor(data_path, total_path + "3x3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - graph << target_hint - << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), - get_input_accessor(image, mean_r, mean_g, mean_b)) - << ConvolutionLayer( - 7U, 7U, 64U, - get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv1/conv1_7x7_s2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv1/conv1_7x7_s2_b.npy"), - PadStrideInfo(2, 2, 3, 3)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) - << convolution_hint - << ConvolutionLayer( - 1U, 1U, 64U, - get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_reduce_w.npy"), - get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_reduce_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 192U, - get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/googlenet_model/conv2/conv2_3x3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << NormalizationLayer(NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << get_inception_node(data_path, "inception_3a", 64, std::make_tuple(96U, 128U), std::make_tuple(16U, 32U), 32U) - << get_inception_node(data_path, "inception_3b", 128, std::make_tuple(128U, 192U), std::make_tuple(32U, 96U), 64U) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << get_inception_node(data_path, "inception_4a", 192, std::make_tuple(96U, 208U), std::make_tuple(16U, 48U), 64U) - << get_inception_node(data_path, "inception_4b", 160, std::make_tuple(112U, 224U), std::make_tuple(24U, 64U), 64U) - << get_inception_node(data_path, "inception_4c", 128, std::make_tuple(128U, 256U), std::make_tuple(24U, 64U), 64U) - << get_inception_node(data_path, "inception_4d", 112, std::make_tuple(144U, 288U), std::make_tuple(32U, 64U), 64U) - << get_inception_node(data_path, "inception_4e", 256, std::make_tuple(160U, 320U), std::make_tuple(32U, 128U), 128U) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << get_inception_node(data_path, "inception_5a", 256, std::make_tuple(160U, 320U), std::make_tuple(32U, 128U), 128U) - << get_inception_node(data_path, "inception_5b", 384, std::make_tuple(192U, 384U), std::make_tuple(48U, 128U), 128U) - << PoolingLayer(PoolingLayerInfo(PoolingType::AVG, 7, PadStrideInfo(1, 1, 0, 0, DimensionRoundingType::CEIL))) - << FullyConnectedLayer( - 1000U, - get_weights_accessor(data_path, "/cnn_data/googlenet_model/loss3/loss3_classifier_w.npy"), - get_weights_accessor(data_path, "/cnn_data/googlenet_model/loss3/loss3_classifier_b.npy")) - << SoftmaxLayer() - << Tensor(get_output_accessor(label, 5)); + SubGraph i_c; + i_c << ConvolutionLayer( + 1U, 1U, std::get<0>(c_filters), + get_weights_accessor(data_path, total_path + "5x5_reduce_w.npy"), + get_weights_accessor(data_path, total_path + "5x5_reduce_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 5U, 5U, std::get<1>(c_filters), + get_weights_accessor(data_path, total_path + "5x5_w.npy"), + get_weights_accessor(data_path, total_path + "5x5_b.npy"), + PadStrideInfo(1, 1, 2, 2)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - graph.run(); -} + SubGraph i_d; + i_d << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL))) + << ConvolutionLayer( + 1U, 1U, d_filt, + get_weights_accessor(data_path, total_path + "pool_proj_w.npy"), + get_weights_accessor(data_path, total_path + "pool_proj_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + + return BranchLayer(BranchMergeMethod::DEPTH_CONCATENATE, std::move(i_a), std::move(i_b), std::move(i_c), std::move(i_d)); + } +}; /** Main program for Googlenet * @@ -200,5 +206,5 @@ void main_graph_googlenet(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_googlenet); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/graph_lenet.cpp b/examples/graph_lenet.cpp index 3e4727f189..2442cffe08 100644 --- a/examples/graph_lenet.cpp +++ b/examples/graph_lenet.cpp @@ -29,103 +29,88 @@ #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; -namespace -{ -/** Generates appropriate accessor according to the specified path - * - * @note If path is empty will generate a DummyAccessor else will generate a NumPyBinLoader - * - * @param path Path to the data files - * @param data_file Relative path to the data files from path - * - * @return An appropriate tensor accessor - */ -std::unique_ptr get_accessor(const std::string &path, const std::string &data_file) -{ - if(path.empty()) - { - return arm_compute::support::cpp14::make_unique(); - } - else - { - return arm_compute::support::cpp14::make_unique(path + data_file); - } -} -} // namespace - /** Example demonstrating how to implement LeNet's network using the Compute Library's graph API * * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] batches ) */ -void main_graph_lenet(int argc, char **argv) +class GraphLenetExample : public Example { - std::string data_path; /** Path to the trainable data */ - unsigned int batches = 4; /** Number of batches */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /** Path to the trainable data */ + unsigned int batches = 4; /** Number of batches */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [batches]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [batches]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - //Do something with argv[1] - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " [path_to_data] [batches]\n\n"; - std::cout << "No number of batches where specified, thus will use the default : " << batches << "\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [batches]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [batches]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + //Do something with argv[1] + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " [path_to_data] [batches]\n\n"; + std::cout << "No number of batches where specified, thus will use the default : " << batches << "\n\n"; + } + else + { + //Do something with argv[1] and argv[2] + data_path = argv[2]; + batches = std::strtol(argv[3], nullptr, 0); + } + + //conv1 << pool1 << conv2 << pool2 << fc1 << act1 << fc2 << smx + graph << target_hint + << Tensor(TensorInfo(TensorShape(28U, 28U, 1U, batches), 1, DataType::F32), DummyAccessor()) + << ConvolutionLayer( + 5U, 5U, 20U, + get_weights_accessor(data_path, "/cnn_data/lenet_model/conv1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/lenet_model/conv1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + << ConvolutionLayer( + 5U, 5U, 50U, + get_weights_accessor(data_path, "/cnn_data/lenet_model/conv2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/lenet_model/conv2_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + << FullyConnectedLayer( + 500U, + get_weights_accessor(data_path, "/cnn_data/lenet_model/ip1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/lenet_model/ip1_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << FullyConnectedLayer( + 10U, + get_weights_accessor(data_path, "/cnn_data/lenet_model/ip2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/lenet_model/ip2_b.npy")) + << SoftmaxLayer() + << Tensor(DummyAccessor()); } - else + void do_run() override { - //Do something with argv[1] and argv[2] - data_path = argv[2]; - batches = std::strtol(argv[3], nullptr, 0); + // Run graph + graph.run(); } - Graph graph; - - //conv1 << pool1 << conv2 << pool2 << fc1 << act1 << fc2 << smx - graph << target_hint - << Tensor(TensorInfo(TensorShape(28U, 28U, 1U, batches), 1, DataType::F32), DummyAccessor()) - << ConvolutionLayer( - 5U, 5U, 20U, - get_accessor(data_path, "/cnn_data/lenet_model/conv1_w.npy"), - get_accessor(data_path, "/cnn_data/lenet_model/conv1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - << ConvolutionLayer( - 5U, 5U, 50U, - get_accessor(data_path, "/cnn_data/lenet_model/conv2_w.npy"), - get_accessor(data_path, "/cnn_data/lenet_model/conv2_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - << FullyConnectedLayer( - 500U, - get_accessor(data_path, "/cnn_data/lenet_model/ip1_w.npy"), - get_accessor(data_path, "/cnn_data/lenet_model/ip1_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << FullyConnectedLayer( - 10U, - get_accessor(data_path, "/cnn_data/lenet_model/ip2_w.npy"), - get_accessor(data_path, "/cnn_data/lenet_model/ip2_b.npy")) - << SoftmaxLayer() - << Tensor(DummyAccessor()); - - graph.run(); -} +private: + Graph graph{}; +}; /** Main program for LeNet * @@ -134,5 +119,5 @@ void main_graph_lenet(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_lenet); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/graph_mobilenet.cpp b/examples/graph_mobilenet.cpp index c468093e56..193e5c336e 100644 --- a/examples/graph_mobilenet.cpp +++ b/examples/graph_mobilenet.cpp @@ -29,142 +29,148 @@ #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; -namespace -{ -BranchLayer get_dwsc_node(const std::string &data_path, std::string &¶m_path, - unsigned int conv_filt, - PadStrideInfo dwc_pad_stride_info, PadStrideInfo conv_pad_stride_info) -{ - std::string total_path = "/cnn_data/mobilenet_v1_model/" + param_path + "_"; - SubGraph sg; - sg << DepthwiseConvolutionLayer( - 3U, 3U, - get_weights_accessor(data_path, total_path + "depthwise_depthwise_weights.npy"), - std::unique_ptr(nullptr), - dwc_pad_stride_info, - true) - << BatchNormalizationLayer( - get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_moving_mean.npy"), - get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_moving_variance.npy"), - get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_beta.npy"), - get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_gamma.npy"), - 0.001f) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)) - << ConvolutionLayer( - 1U, 1U, conv_filt, - get_weights_accessor(data_path, total_path + "pointwise_weights.npy"), - std::unique_ptr(nullptr), - conv_pad_stride_info) - << BatchNormalizationLayer( - get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_moving_mean.npy"), - get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_moving_variance.npy"), - get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_beta.npy"), - get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_gamma.npy"), - 0.001f) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)); - - return BranchLayer(std::move(sg)); -} -} // namespace - /** Example demonstrating how to implement MobileNet's network using the Compute Library's graph API * * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_mobilenet(int argc, char **argv) +class GraphMobilenetExample : public Example { - std::string data_path; /* Path to the trainable data */ - std::string image; /* Image data */ - std::string label; /* Label data */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /* Path to the trainable data */ + std::string image; /* Image data */ + std::string label; /* Label data */ - constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ - constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ - constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ + constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ + constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ + constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; - std::cout << "No image provided: using random values\n\n"; - } - else if(argc == 4) - { - data_path = argv[2]; - image = argv[3]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; - std::cout << "No text file with labels provided: skipping output accessor\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; + std::cout << "No image provided: using random values\n\n"; + } + else if(argc == 4) + { + data_path = argv[2]; + image = argv[3]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; + std::cout << "No text file with labels provided: skipping output accessor\n\n"; + } + else + { + data_path = argv[2]; + image = argv[3]; + label = argv[4]; + } + + graph << target_hint + << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), + get_input_accessor(image, mean_r, mean_g, mean_b)) + << convolution_hint + << ConvolutionLayer( + 3U, 3U, 32U, + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_weights.npy"), + std::unique_ptr(nullptr), + PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR)) + << BatchNormalizationLayer( + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_moving_mean.npy"), + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_moving_variance.npy"), + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_beta.npy"), + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_gamma.npy"), + 0.001f) + + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)) + << get_dwsc_node(data_path, "Conv2d_1", 64, PadStrideInfo(1, 1, 1, 1), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_2", 128, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_3", 128, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_4", 256, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_5", 256, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_6", 512, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_7", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_8", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_9", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_10", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_11", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_12", 1024, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << get_dwsc_node(data_path, "Conv2d_13", 1024, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) + << PoolingLayer(PoolingLayerInfo(PoolingType::AVG)) + << ConvolutionLayer( + 1U, 1U, 1001U, + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Logits_Conv2d_1c_1x1_weights.npy"), + get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Logits_Conv2d_1c_1x1_biases.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ReshapeLayer(TensorShape(1001U)) + << SoftmaxLayer() + << Tensor(get_output_accessor(label, 5)); } - else + void do_run() override { - data_path = argv[2]; - image = argv[3]; - label = argv[4]; + // Run graph + graph.run(); } - Graph graph; +private: + Graph graph{}; - graph << target_hint - << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), - get_input_accessor(image, mean_r, mean_g, mean_b)) - << convolution_hint - << ConvolutionLayer( - 3U, 3U, 32U, - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_weights.npy"), - std::unique_ptr(nullptr), - PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR)) - << BatchNormalizationLayer( - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_moving_mean.npy"), - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_moving_variance.npy"), - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_beta.npy"), - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Conv2d_0_BatchNorm_gamma.npy"), - 0.001f) - - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)) - << get_dwsc_node(data_path, "Conv2d_1", 64, PadStrideInfo(1, 1, 1, 1), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_2", 128, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_3", 128, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_4", 256, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_5", 256, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_6", 512, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_7", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_8", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_9", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_10", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_11", 512, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_12", 1024, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << get_dwsc_node(data_path, "Conv2d_13", 1024, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0)) - << PoolingLayer(PoolingLayerInfo(PoolingType::AVG)) - << ConvolutionLayer( - 1U, 1U, 1001U, - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Logits_Conv2d_1c_1x1_weights.npy"), - get_weights_accessor(data_path, "/cnn_data/mobilenet_v1_model/Logits_Conv2d_1c_1x1_biases.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ReshapeLayer(TensorShape(1001U)) - << SoftmaxLayer() - << Tensor(get_output_accessor(label, 5)); + BranchLayer get_dwsc_node(const std::string &data_path, std::string &¶m_path, + unsigned int conv_filt, + PadStrideInfo dwc_pad_stride_info, PadStrideInfo conv_pad_stride_info) + { + std::string total_path = "/cnn_data/mobilenet_v1_model/" + param_path + "_"; + SubGraph sg; + sg << DepthwiseConvolutionLayer( + 3U, 3U, + get_weights_accessor(data_path, total_path + "depthwise_depthwise_weights.npy"), + std::unique_ptr(nullptr), + dwc_pad_stride_info, + true) + << BatchNormalizationLayer( + get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_moving_mean.npy"), + get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_moving_variance.npy"), + get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_beta.npy"), + get_weights_accessor(data_path, total_path + "depthwise_BatchNorm_gamma.npy"), + 0.001f) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)) + << ConvolutionLayer( + 1U, 1U, conv_filt, + get_weights_accessor(data_path, total_path + "pointwise_weights.npy"), + std::unique_ptr(nullptr), + conv_pad_stride_info) + << BatchNormalizationLayer( + get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_moving_mean.npy"), + get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_moving_variance.npy"), + get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_beta.npy"), + get_weights_accessor(data_path, total_path + "pointwise_BatchNorm_gamma.npy"), + 0.001f) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f)); - graph.run(); -} + return BranchLayer(std::move(sg)); + } +}; /** Main program for MobileNetV1 * @@ -173,5 +179,5 @@ void main_graph_mobilenet(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_mobilenet); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/graph_squeezenet.cpp b/examples/graph_squeezenet.cpp index 11a80a7bd8..b21f2fe5c4 100644 --- a/examples/graph_squeezenet.cpp +++ b/examples/graph_squeezenet.cpp @@ -31,33 +31,13 @@ #include #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; using namespace arm_compute::logging; namespace { -BranchLayer get_expand_fire_node(const std::string &data_path, std::string &¶m_path, unsigned int expand1_filt, unsigned int expand3_filt) -{ - std::string total_path = "/cnn_data/squeezenet_v1.0_model/" + param_path + "_"; - SubGraph i_a; - i_a << ConvolutionLayer( - 1U, 1U, expand1_filt, - get_weights_accessor(data_path, total_path + "expand1x1_w.npy"), - get_weights_accessor(data_path, total_path + "expand1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - - SubGraph i_b; - i_b << ConvolutionLayer( - 3U, 3U, expand3_filt, - get_weights_accessor(data_path, total_path + "expand3x3_w.npy"), - get_weights_accessor(data_path, total_path + "expand3x3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - - return BranchLayer(BranchMergeMethod::DEPTH_CONCATENATE, std::move(i_a), std::move(i_b)); -} } // namespace /** Example demonstrating how to implement Squeezenet's network using the Compute Library's graph API @@ -65,136 +45,166 @@ BranchLayer get_expand_fire_node(const std::string &data_path, std::string &&par * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_squeezenet(int argc, char **argv) +class GraphSqueezenetExample : public Example { - std::string data_path; /* Path to the trainable data */ - std::string image; /* Image data */ - std::string label; /* Label data */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /* Path to the trainable data */ + std::string image; /* Image data */ + std::string label; /* Label data */ - constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ - constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ - constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ + constexpr float mean_r = 122.68f; /* Mean value to subtract from red channel */ + constexpr float mean_g = 116.67f; /* Mean value to subtract from green channel */ + constexpr float mean_b = 104.01f; /* Mean value to subtract from blue channel */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + ConvolutionMethodHint convolution_hint = target_hint == TargetHint::NEON ? ConvolutionMethodHint::GEMM : ConvolutionMethodHint::DIRECT; - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; - std::cout << "No image provided: using random values\n\n"; - } - else if(argc == 4) - { - data_path = argv[2]; - image = argv[3]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; - std::cout << "No text file with labels provided: skipping output accessor\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; + std::cout << "No image provided: using random values\n\n"; + } + else if(argc == 4) + { + data_path = argv[2]; + image = argv[3]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; + std::cout << "No text file with labels provided: skipping output accessor\n\n"; + } + else + { + data_path = argv[2]; + image = argv[3]; + label = argv[4]; + } + + graph << target_hint + << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), + get_input_accessor(image, mean_r, mean_g, mean_b)) + << ConvolutionLayer( + 7U, 7U, 96U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv1_b.npy"), + PadStrideInfo(2, 2, 0, 0)) + << convolution_hint + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << ConvolutionLayer( + 1U, 1U, 16U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire2_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire2_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire2", 64U, 64U) + << ConvolutionLayer( + 1U, 1U, 16U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire3_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire3_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire3", 64U, 64U) + << ConvolutionLayer( + 1U, 1U, 32U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire4_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire4_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire4", 128U, 128U) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << ConvolutionLayer( + 1U, 1U, 32U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire5_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire5_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire5", 128U, 128U) + << ConvolutionLayer( + 1U, 1U, 48U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire6_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire6_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire6", 192U, 192U) + << ConvolutionLayer( + 1U, 1U, 48U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire7_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire7_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire7", 192U, 192U) + << ConvolutionLayer( + 1U, 1U, 64U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire8_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire8_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire8", 256U, 256U) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) + << ConvolutionLayer( + 1U, 1U, 64U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire9_squeeze1x1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire9_squeeze1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << get_expand_fire_node(data_path, "fire9", 256U, 256U) + << ConvolutionLayer( + 1U, 1U, 1000U, + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv10_w.npy"), + get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv10_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::AVG)) + << FlattenLayer() + << SoftmaxLayer() + << Tensor(get_output_accessor(label, 5)); } - else + void do_run() override { - data_path = argv[2]; - image = argv[3]; - label = argv[4]; + // Run graph + graph.run(); } - Graph graph; +private: + Graph graph{}; - graph << target_hint - << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), - get_input_accessor(image, mean_r, mean_g, mean_b)) - << ConvolutionLayer( - 7U, 7U, 96U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv1_b.npy"), - PadStrideInfo(2, 2, 0, 0)) - << convolution_hint - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << ConvolutionLayer( - 1U, 1U, 16U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire2_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire2_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire2", 64U, 64U) - << ConvolutionLayer( - 1U, 1U, 16U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire3_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire3_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire3", 64U, 64U) - << ConvolutionLayer( - 1U, 1U, 32U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire4_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire4_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire4", 128U, 128U) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << ConvolutionLayer( - 1U, 1U, 32U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire5_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire5_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire5", 128U, 128U) - << ConvolutionLayer( - 1U, 1U, 48U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire6_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire6_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire6", 192U, 192U) - << ConvolutionLayer( - 1U, 1U, 48U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire7_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire7_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire7", 192U, 192U) - << ConvolutionLayer( - 1U, 1U, 64U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire8_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire8_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire8", 256U, 256U) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL))) - << ConvolutionLayer( - 1U, 1U, 64U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire9_squeeze1x1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/fire9_squeeze1x1_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << get_expand_fire_node(data_path, "fire9", 256U, 256U) - << ConvolutionLayer( - 1U, 1U, 1000U, - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv10_w.npy"), - get_weights_accessor(data_path, "/cnn_data/squeezenet_v1.0_model/conv10_b.npy"), - PadStrideInfo(1, 1, 0, 0)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::AVG)) - << FlattenLayer() - << SoftmaxLayer() - << Tensor(get_output_accessor(label, 5)); + BranchLayer get_expand_fire_node(const std::string &data_path, std::string &¶m_path, unsigned int expand1_filt, unsigned int expand3_filt) + { + std::string total_path = "/cnn_data/squeezenet_v1.0_model/" + param_path + "_"; + SubGraph i_a; + i_a << ConvolutionLayer( + 1U, 1U, expand1_filt, + get_weights_accessor(data_path, total_path + "expand1x1_w.npy"), + get_weights_accessor(data_path, total_path + "expand1x1_b.npy"), + PadStrideInfo(1, 1, 0, 0)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - graph.run(); -} + SubGraph i_b; + i_b << ConvolutionLayer( + 3U, 3U, expand3_filt, + get_weights_accessor(data_path, total_path + "expand3x3_w.npy"), + get_weights_accessor(data_path, total_path + "expand3x3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + + return BranchLayer(BranchMergeMethod::DEPTH_CONCATENATE, std::move(i_a), std::move(i_b)); + } +}; /** Main program for Squeezenet v1.0 * @@ -203,5 +213,5 @@ void main_graph_squeezenet(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_squeezenet); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/graph_vgg16.cpp b/examples/graph_vgg16.cpp index fcaa6182cb..1a804a4882 100644 --- a/examples/graph_vgg16.cpp +++ b/examples/graph_vgg16.cpp @@ -29,6 +29,7 @@ #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; @@ -37,179 +38,186 @@ using namespace arm_compute::graph_utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_vgg16(int argc, char **argv) +class GraphVGG16Example : public Example { - std::string data_path; /* Path to the trainable data */ - std::string image; /* Image data */ - std::string label; /* Label data */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /* Path to the trainable data */ + std::string image; /* Image data */ + std::string label; /* Label data */ - constexpr float mean_r = 123.68f; /* Mean value to subtract from red channel */ - constexpr float mean_g = 116.779f; /* Mean value to subtract from green channel */ - constexpr float mean_b = 103.939f; /* Mean value to subtract from blue channel */ + constexpr float mean_r = 123.68f; /* Mean value to subtract from red channel */ + constexpr float mean_g = 116.779f; /* Mean value to subtract from green channel */ + constexpr float mean_b = 103.939f; /* Mean value to subtract from blue channel */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - ConvolutionMethodHint convolution_hint = ConvolutionMethodHint::DIRECT; + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + ConvolutionMethodHint convolution_hint = ConvolutionMethodHint::DIRECT; - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; - std::cout << "No image provided: using random values\n\n"; - } - else if(argc == 4) - { - data_path = argv[2]; - image = argv[3]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; - std::cout << "No text file with labels provided: skipping output accessor\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; + std::cout << "No image provided: using random values\n\n"; + } + else if(argc == 4) + { + data_path = argv[2]; + image = argv[3]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; + std::cout << "No text file with labels provided: skipping output accessor\n\n"; + } + else + { + data_path = argv[2]; + image = argv[3]; + label = argv[4]; + } + + graph << target_hint + << convolution_hint + << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), + get_input_accessor(image, mean_r, mean_g, mean_b)) + << ConvolutionMethodHint::DIRECT + // Layer 1 + << ConvolutionLayer( + 3U, 3U, 64U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 2 + << ConvolutionLayer( + 3U, 3U, 64U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 3 + << ConvolutionLayer( + 3U, 3U, 128U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 4 + << ConvolutionLayer( + 3U, 3U, 128U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 5 + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 6 + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 7 + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 8 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 9 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 10 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 11 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 12 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 13 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 14 + << FullyConnectedLayer( + 4096U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc6_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc6_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 15 + << FullyConnectedLayer( + 4096U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc7_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc7_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 16 + << FullyConnectedLayer( + 1000U, + get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc8_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc8_b.npy")) + // Softmax + << SoftmaxLayer() + << Tensor(get_output_accessor(label, 5)); } - else + void do_run() override { - data_path = argv[2]; - image = argv[3]; - label = argv[4]; + // Run graph + graph.run(); } - Graph graph; - - graph << target_hint - << convolution_hint - << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), - get_input_accessor(image, mean_r, mean_g, mean_b)) - << ConvolutionMethodHint::DIRECT - // Layer 1 - << ConvolutionLayer( - 3U, 3U, 64U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 2 - << ConvolutionLayer( - 3U, 3U, 64U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv1_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 3 - << ConvolutionLayer( - 3U, 3U, 128U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 4 - << ConvolutionLayer( - 3U, 3U, 128U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv2_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 5 - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 6 - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 7 - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv3_3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 8 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 9 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 10 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv4_3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 11 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 12 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 13 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/conv5_3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 14 - << FullyConnectedLayer( - 4096U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc6_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc6_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 15 - << FullyConnectedLayer( - 4096U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc7_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc7_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 16 - << FullyConnectedLayer( - 1000U, - get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc8_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg16_model/fc8_b.npy")) - // Softmax - << SoftmaxLayer() - << Tensor(get_output_accessor(label, 5)); - - // Run graph - graph.run(); -} +private: + Graph graph{}; +}; /** Main program for VGG16 * @@ -218,5 +226,5 @@ void main_graph_vgg16(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_vgg16); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/graph_vgg19.cpp b/examples/graph_vgg19.cpp index 1f6cba4441..5214438d7f 100644 --- a/examples/graph_vgg19.cpp +++ b/examples/graph_vgg19.cpp @@ -29,6 +29,7 @@ #include +using namespace arm_compute::utils; using namespace arm_compute::graph; using namespace arm_compute::graph_utils; @@ -37,188 +38,195 @@ using namespace arm_compute::graph_utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Target (0 = NEON, 1 = OpenCL), [optional] Path to the weights folder, [optional] image, [optional] labels ) */ -void main_graph_vgg19(int argc, char **argv) +class GraphVGG19Example : public Example { - std::string data_path; /* Path to the trainable data */ - std::string image; /* Image data */ - std::string label; /* Label data */ +public: + void do_setup(int argc, char **argv) override + { + std::string data_path; /* Path to the trainable data */ + std::string image; /* Image data */ + std::string label; /* Label data */ - constexpr float mean_r = 123.68f; /* Mean value to subtract from red channel */ - constexpr float mean_g = 116.779f; /* Mean value to subtract from green channel */ - constexpr float mean_b = 103.939f; /* Mean value to subtract from blue channel */ + constexpr float mean_r = 123.68f; /* Mean value to subtract from red channel */ + constexpr float mean_g = 116.779f; /* Mean value to subtract from green channel */ + constexpr float mean_b = 103.939f; /* Mean value to subtract from blue channel */ - // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON - TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); - ConvolutionMethodHint convolution_hint = ConvolutionMethodHint::DIRECT; + // Set target. 0 (NEON), 1 (OpenCL). By default it is NEON + TargetHint target_hint = set_target_hint(argc > 1 ? std::strtol(argv[1], nullptr, 10) : 0); + ConvolutionMethodHint convolution_hint = ConvolutionMethodHint::DIRECT; - // Parse arguments - if(argc < 2) - { - // Print help - std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 2) - { - std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; - std::cout << "No data folder provided: using random values\n\n"; - } - else if(argc == 3) - { - data_path = argv[2]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; - std::cout << "No image provided: using random values\n\n"; - } - else if(argc == 4) - { - data_path = argv[2]; - image = argv[3]; - std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; - std::cout << "No text file with labels provided: skipping output accessor\n\n"; + // Parse arguments + if(argc < 2) + { + // Print help + std::cout << "Usage: " << argv[0] << " [target] [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 2) + { + std::cout << "Usage: " << argv[0] << " " << argv[1] << " [path_to_data] [image] [labels]\n\n"; + std::cout << "No data folder provided: using random values\n\n"; + } + else if(argc == 3) + { + data_path = argv[2]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " [image] [labels]\n\n"; + std::cout << "No image provided: using random values\n\n"; + } + else if(argc == 4) + { + data_path = argv[2]; + image = argv[3]; + std::cout << "Usage: " << argv[0] << " " << argv[1] << " " << argv[2] << " " << argv[3] << " [labels]\n\n"; + std::cout << "No text file with labels provided: skipping output accessor\n\n"; + } + else + { + data_path = argv[2]; + image = argv[3]; + label = argv[4]; + } + + graph << target_hint + << convolution_hint + << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), + get_input_accessor(image, mean_r, mean_g, mean_b)) + // Layer 1 + << ConvolutionLayer( + 3U, 3U, 64U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 64U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 2 + << ConvolutionLayer( + 3U, 3U, 128U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 128U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 3 + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 256U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_4_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_4_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 4 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_4_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_4_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 5 + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_1_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_1_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_2_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_2_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_3_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_3_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << ConvolutionLayer( + 3U, 3U, 512U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_4_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_4_b.npy"), + PadStrideInfo(1, 1, 1, 1)) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) + // Layer 6 + << FullyConnectedLayer( + 4096U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc6_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc6_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 7 + << FullyConnectedLayer( + 4096U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc7_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc7_b.npy")) + << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) + // Layer 8 + << FullyConnectedLayer( + 1000U, + get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc8_w.npy"), + get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc8_b.npy")) + // Softmax + << SoftmaxLayer() + << Tensor(get_output_accessor(label, 5)); } - else + void do_run() override { - data_path = argv[2]; - image = argv[3]; - label = argv[4]; + // Run graph + graph.run(); } - Graph graph; - - graph << target_hint - << convolution_hint - << Tensor(TensorInfo(TensorShape(224U, 224U, 3U, 1U), 1, DataType::F32), - get_input_accessor(image, mean_r, mean_g, mean_b)) - // Layer 1 - << ConvolutionLayer( - 3U, 3U, 64U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 64U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv1_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 2 - << ConvolutionLayer( - 3U, 3U, 128U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 128U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv2_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 3 - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 256U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_4_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv3_4_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 4 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_4_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv4_4_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 5 - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_1_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_1_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_2_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_2_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_3_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_3_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << ConvolutionLayer( - 3U, 3U, 512U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_4_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/conv5_4_b.npy"), - PadStrideInfo(1, 1, 1, 1)) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))) - // Layer 6 - << FullyConnectedLayer( - 4096U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc6_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc6_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 7 - << FullyConnectedLayer( - 4096U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc7_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc7_b.npy")) - << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)) - // Layer 8 - << FullyConnectedLayer( - 1000U, - get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc8_w.npy"), - get_weights_accessor(data_path, "/cnn_data/vgg19_model/fc8_b.npy")) - // Softmax - << SoftmaxLayer() - << Tensor(get_output_accessor(label, 5)); - - // Run graph - graph.run(); -} +private: + Graph graph{}; +}; /** Main program for VGG19 * @@ -227,5 +235,5 @@ void main_graph_vgg19(int argc, char **argv) */ int main(int argc, char **argv) { - return arm_compute::utils::run_example(argc, argv, main_graph_vgg19); + return arm_compute::utils::run_example(argc, argv); } diff --git a/examples/neon_cartoon_effect.cpp b/examples/neon_cartoon_effect.cpp index 0ecd9410a1..da8ce3f84f 100644 --- a/examples/neon_cartoon_effect.cpp +++ b/examples/neon_cartoon_effect.cpp @@ -30,67 +30,76 @@ using namespace arm_compute; using namespace utils; -void main_neon_cartoon_effect(int argc, char **argv) +class NEONCartoonEffectExample : public Example { - // Open PPM file - PPMLoader ppm; - Image src_img; - Image dst_img; - Image gaus5x5_img; - Image canny_edge_img; - - if(argc < 2) - { - // Print help - std::cout << "Usage: ./build/neon_cartoon_effect [input_image.ppm]\n\n"; - std::cout << "No input_image provided, creating a dummy 640x480 image\n"; - // Create an empty grayscale 640x480 image - src_img.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else +public: + void do_setup(int argc, char **argv) override { - ppm.open(argv[1]); - ppm.init_image(src_img, Format::U8); - } + // Open PPM file + PPMLoader ppm; - // Initialize just the dimensions and format of the images: - gaus5x5_img.allocator()->init(*src_img.info()); - canny_edge_img.allocator()->init(*src_img.info()); - dst_img.allocator()->init(*src_img.info()); + if(argc < 2) + { + // Print help + std::cout << "Usage: ./build/neon_cartoon_effect [input_image.ppm]\n\n"; + std::cout << "No input_image provided, creating a dummy 640x480 image\n"; + // Create an empty grayscale 640x480 image + src_img.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm.open(argv[1]); + ppm.init_image(src_img, Format::U8); + } - NEGaussian5x5 gaus5x5; - NECannyEdge canny_edge; - NEArithmeticSubtraction sub; + // Initialize just the dimensions and format of the images: + gaus5x5_img.allocator()->init(*src_img.info()); + canny_edge_img.allocator()->init(*src_img.info()); + dst_img.allocator()->init(*src_img.info()); - // Configure the functions to call - gaus5x5.configure(&src_img, &gaus5x5_img, BorderMode::REPLICATE); - canny_edge.configure(&src_img, &canny_edge_img, 100, 80, 3, 1, BorderMode::REPLICATE); - sub.configure(&gaus5x5_img, &canny_edge_img, &dst_img, ConvertPolicy::SATURATE); + // Configure the functions to call + gaus5x5.configure(&src_img, &gaus5x5_img, BorderMode::REPLICATE); + canny_edge.configure(&src_img, &canny_edge_img, 100, 80, 3, 1, BorderMode::REPLICATE); + sub.configure(&gaus5x5_img, &canny_edge_img, &dst_img, ConvertPolicy::SATURATE); - // Now that the padding requirements are known we can allocate the images: - src_img.allocator()->allocate(); - dst_img.allocator()->allocate(); - gaus5x5_img.allocator()->allocate(); - canny_edge_img.allocator()->allocate(); + // Now that the padding requirements are known we can allocate the images: + src_img.allocator()->allocate(); + dst_img.allocator()->allocate(); + gaus5x5_img.allocator()->allocate(); + canny_edge_img.allocator()->allocate(); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm.is_open()) - { - ppm.fill_image(src_img); + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm.is_open()) + { + ppm.fill_image(src_img); + output_filename = std::string(argv[1]) + "_out.ppm"; + } } - // Execute the functions: - gaus5x5.run(); - canny_edge.run(); - sub.run(); + void do_run() override + { + // Execute the functions: + gaus5x5.run(); + canny_edge.run(); + sub.run(); + } - // Save the result to file: - if(ppm.is_open()) + void do_teardown() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - save_to_ppm(dst_img, output_filename); + // Save the result to file: + if(!output_filename.empty()) + { + save_to_ppm(dst_img, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + } } -} + +private: + Image src_img{}, dst_img{}, gaus5x5_img{}, canny_edge_img{}; + NEGaussian5x5 gaus5x5{}; + NECannyEdge canny_edge{}; + NEArithmeticSubtraction sub{}; + std::string output_filename{}; +}; /** Main program for cartoon effect test * @@ -99,5 +108,5 @@ void main_neon_cartoon_effect(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_neon_cartoon_effect); + return utils::run_example(argc, argv); } diff --git a/examples/neon_cnn.cpp b/examples/neon_cnn.cpp index 2be5acfbaf..05b6c832bc 100644 --- a/examples/neon_cnn.cpp +++ b/examples/neon_cnn.cpp @@ -33,254 +33,261 @@ using namespace arm_compute; using namespace utils; -void main_cnn(int argc, char **argv) +class NEONCNNExample : public Example { - ARM_COMPUTE_UNUSED(argc); - ARM_COMPUTE_UNUSED(argv); +public: + void do_setup(int argc, char **argv) override + { + ARM_COMPUTE_UNUSED(argc); + ARM_COMPUTE_UNUSED(argv); - // Create NEON allocator - Allocator allocator; + // Create memory manager components + // We need 2 memory managers: 1 for handling the tensors within the functions (mm_layers) and 1 for handling the input and output tensors of the functions (mm_transitions)) + auto lifetime_mgr0 = std::make_shared(); // Create lifetime manager + auto lifetime_mgr1 = std::make_shared(); // Create lifetime manager + auto pool_mgr0 = std::make_shared(); // Create pool manager + auto pool_mgr1 = std::make_shared(); // Create pool manager + auto mm_layers = std::make_shared(lifetime_mgr0, pool_mgr0); // Create the memory manager + auto mm_transitions = std::make_shared(lifetime_mgr1, pool_mgr1); // Create the memory manager - // Create memory manager components - // We need 2 memory managers: 1 for handling the tensors within the functions (mm_layers) and 1 for handling the input and output tensors of the functions (mm_transitions)) - auto lifetime_mgr0 = std::make_shared(); // Create lifetime manager - auto lifetime_mgr1 = std::make_shared(); // Create lifetime manager - auto pool_mgr0 = std::make_shared(); // Create pool manager - auto pool_mgr1 = std::make_shared(); // Create pool manager - auto mm_layers = std::make_shared(lifetime_mgr0, pool_mgr0); // Create the memory manager - auto mm_transitions = std::make_shared(lifetime_mgr1, pool_mgr1); // Create the memory manager + // The weights and biases tensors should be initialized with the values inferred with the training - // The src tensor should contain the input image - Tensor src; - - // The weights and biases tensors should be initialized with the values inferred with the training - Tensor weights0; - Tensor weights1; - Tensor weights2; - Tensor biases0; - Tensor biases1; - Tensor biases2; - - Tensor out_conv0; - Tensor out_conv1; - Tensor out_act0; - Tensor out_act1; - Tensor out_act2; - Tensor out_pool0; - Tensor out_pool1; - Tensor out_fc0; - Tensor out_softmax; - - // Create layers and set memory manager where allowed to manage internal memory requirements - NEConvolutionLayer conv0(mm_layers); - NEConvolutionLayer conv1(mm_layers); - NEPoolingLayer pool0; - NEPoolingLayer pool1; - NEFullyConnectedLayer fc0(mm_layers); - NEActivationLayer act0; - NEActivationLayer act1; - NEActivationLayer act2; - NESoftmaxLayer softmax(mm_layers); + // Set memory manager where allowed to manage internal memory requirements + conv0 = arm_compute::support::cpp14::make_unique(mm_layers); + conv1 = arm_compute::support::cpp14::make_unique(mm_layers); + fc0 = arm_compute::support::cpp14::make_unique(mm_layers); + softmax = arm_compute::support::cpp14::make_unique(mm_layers); - /* [Initialize tensors] */ + /* [Initialize tensors] */ - // Initialize src tensor - constexpr unsigned int width_src_image = 32; - constexpr unsigned int height_src_image = 32; - constexpr unsigned int ifm_src_img = 1; + // Initialize src tensor + constexpr unsigned int width_src_image = 32; + constexpr unsigned int height_src_image = 32; + constexpr unsigned int ifm_src_img = 1; - const TensorShape src_shape(width_src_image, height_src_image, ifm_src_img); - src.allocator()->init(TensorInfo(src_shape, 1, DataType::F32)); + const TensorShape src_shape(width_src_image, height_src_image, ifm_src_img); + src.allocator()->init(TensorInfo(src_shape, 1, DataType::F32)); - // Initialize tensors of conv0 - constexpr unsigned int kernel_x_conv0 = 5; - constexpr unsigned int kernel_y_conv0 = 5; - constexpr unsigned int ofm_conv0 = 8; + // Initialize tensors of conv0 + constexpr unsigned int kernel_x_conv0 = 5; + constexpr unsigned int kernel_y_conv0 = 5; + constexpr unsigned int ofm_conv0 = 8; - const TensorShape weights_shape_conv0(kernel_x_conv0, kernel_y_conv0, src_shape.z(), ofm_conv0); - const TensorShape biases_shape_conv0(weights_shape_conv0[3]); - const TensorShape out_shape_conv0(src_shape.x(), src_shape.y(), weights_shape_conv0[3]); + const TensorShape weights_shape_conv0(kernel_x_conv0, kernel_y_conv0, src_shape.z(), ofm_conv0); + const TensorShape biases_shape_conv0(weights_shape_conv0[3]); + const TensorShape out_shape_conv0(src_shape.x(), src_shape.y(), weights_shape_conv0[3]); - weights0.allocator()->init(TensorInfo(weights_shape_conv0, 1, DataType::F32)); - biases0.allocator()->init(TensorInfo(biases_shape_conv0, 1, DataType::F32)); - out_conv0.allocator()->init(TensorInfo(out_shape_conv0, 1, DataType::F32)); - - // Initialize tensor of act0 - out_act0.allocator()->init(TensorInfo(out_shape_conv0, 1, DataType::F32)); - - // Initialize tensor of pool0 - TensorShape out_shape_pool0 = out_shape_conv0; - out_shape_pool0.set(0, out_shape_pool0.x() / 2); - out_shape_pool0.set(1, out_shape_pool0.y() / 2); - out_pool0.allocator()->init(TensorInfo(out_shape_pool0, 1, DataType::F32)); - - // Initialize tensors of conv1 - constexpr unsigned int kernel_x_conv1 = 3; - constexpr unsigned int kernel_y_conv1 = 3; - constexpr unsigned int ofm_conv1 = 16; - - const TensorShape weights_shape_conv1(kernel_x_conv1, kernel_y_conv1, out_shape_pool0.z(), ofm_conv1); - - const TensorShape biases_shape_conv1(weights_shape_conv1[3]); - const TensorShape out_shape_conv1(out_shape_pool0.x(), out_shape_pool0.y(), weights_shape_conv1[3]); - - weights1.allocator()->init(TensorInfo(weights_shape_conv1, 1, DataType::F32)); - biases1.allocator()->init(TensorInfo(biases_shape_conv1, 1, DataType::F32)); - out_conv1.allocator()->init(TensorInfo(out_shape_conv1, 1, DataType::F32)); - - // Initialize tensor of act1 - out_act1.allocator()->init(TensorInfo(out_shape_conv1, 1, DataType::F32)); - - // Initialize tensor of pool1 - TensorShape out_shape_pool1 = out_shape_conv1; - out_shape_pool1.set(0, out_shape_pool1.x() / 2); - out_shape_pool1.set(1, out_shape_pool1.y() / 2); - out_pool1.allocator()->init(TensorInfo(out_shape_pool1, 1, DataType::F32)); - - // Initialize tensor of fc0 - constexpr unsigned int num_labels = 128; - - const TensorShape weights_shape_fc0(out_shape_pool1.x() * out_shape_pool1.y() * out_shape_pool1.z(), num_labels); - const TensorShape biases_shape_fc0(num_labels); - const TensorShape out_shape_fc0(num_labels); - - weights2.allocator()->init(TensorInfo(weights_shape_fc0, 1, DataType::F32)); - biases2.allocator()->init(TensorInfo(biases_shape_fc0, 1, DataType::F32)); - out_fc0.allocator()->init(TensorInfo(out_shape_fc0, 1, DataType::F32)); - - // Initialize tensor of act2 - out_act2.allocator()->init(TensorInfo(out_shape_fc0, 1, DataType::F32)); - - // Initialize tensor of softmax - const TensorShape out_shape_softmax(out_shape_fc0.x()); - out_softmax.allocator()->init(TensorInfo(out_shape_softmax, 1, DataType::F32)); + weights0.allocator()->init(TensorInfo(weights_shape_conv0, 1, DataType::F32)); + biases0.allocator()->init(TensorInfo(biases_shape_conv0, 1, DataType::F32)); + out_conv0.allocator()->init(TensorInfo(out_shape_conv0, 1, DataType::F32)); - /* -----------------------End: [Initialize tensors] */ + // Initialize tensor of act0 + out_act0.allocator()->init(TensorInfo(out_shape_conv0, 1, DataType::F32)); - /* [Configure functions] */ + // Initialize tensor of pool0 + TensorShape out_shape_pool0 = out_shape_conv0; + out_shape_pool0.set(0, out_shape_pool0.x() / 2); + out_shape_pool0.set(1, out_shape_pool0.y() / 2); + out_pool0.allocator()->init(TensorInfo(out_shape_pool0, 1, DataType::F32)); - // in:32x32x1: 5x5 convolution, 8 output features maps (OFM) - conv0.configure(&src, &weights0, &biases0, &out_conv0, PadStrideInfo(1 /* stride_x */, 1 /* stride_y */, 2 /* pad_x */, 2 /* pad_y */)); + // Initialize tensors of conv1 + constexpr unsigned int kernel_x_conv1 = 3; + constexpr unsigned int kernel_y_conv1 = 3; + constexpr unsigned int ofm_conv1 = 16; - // in:32x32x8, out:32x32x8, Activation function: relu - act0.configure(&out_conv0, &out_act0, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + const TensorShape weights_shape_conv1(kernel_x_conv1, kernel_y_conv1, out_shape_pool0.z(), ofm_conv1); - // in:32x32x8, out:16x16x8 (2x2 pooling), Pool type function: Max - pool0.configure(&out_act0, &out_pool0, PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2 /* stride_x */, 2 /* stride_y */))); + const TensorShape biases_shape_conv1(weights_shape_conv1[3]); + const TensorShape out_shape_conv1(out_shape_pool0.x(), out_shape_pool0.y(), weights_shape_conv1[3]); + + weights1.allocator()->init(TensorInfo(weights_shape_conv1, 1, DataType::F32)); + biases1.allocator()->init(TensorInfo(biases_shape_conv1, 1, DataType::F32)); + out_conv1.allocator()->init(TensorInfo(out_shape_conv1, 1, DataType::F32)); + + // Initialize tensor of act1 + out_act1.allocator()->init(TensorInfo(out_shape_conv1, 1, DataType::F32)); - // in:16x16x8: 3x3 convolution, 16 output features maps (OFM) - conv1.configure(&out_pool0, &weights1, &biases1, &out_conv1, PadStrideInfo(1 /* stride_x */, 1 /* stride_y */, 1 /* pad_x */, 1 /* pad_y */)); + // Initialize tensor of pool1 + TensorShape out_shape_pool1 = out_shape_conv1; + out_shape_pool1.set(0, out_shape_pool1.x() / 2); + out_shape_pool1.set(1, out_shape_pool1.y() / 2); + out_pool1.allocator()->init(TensorInfo(out_shape_pool1, 1, DataType::F32)); - // in:16x16x16, out:16x16x16, Activation function: relu - act1.configure(&out_conv1, &out_act1, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + // Initialize tensor of fc0 + constexpr unsigned int num_labels = 128; - // in:16x16x16, out:8x8x16 (2x2 pooling), Pool type function: Average - pool1.configure(&out_act1, &out_pool1, PoolingLayerInfo(PoolingType::AVG, 2, PadStrideInfo(2 /* stride_x */, 2 /* stride_y */))); + const TensorShape weights_shape_fc0(out_shape_pool1.x() * out_shape_pool1.y() * out_shape_pool1.z(), num_labels); + const TensorShape biases_shape_fc0(num_labels); + const TensorShape out_shape_fc0(num_labels); - // in:8x8x16, out:128 - fc0.configure(&out_pool1, &weights2, &biases2, &out_fc0); + weights2.allocator()->init(TensorInfo(weights_shape_fc0, 1, DataType::F32)); + biases2.allocator()->init(TensorInfo(biases_shape_fc0, 1, DataType::F32)); + out_fc0.allocator()->init(TensorInfo(out_shape_fc0, 1, DataType::F32)); - // in:128, out:128, Activation function: relu - act2.configure(&out_fc0, &out_act2, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + // Initialize tensor of act2 + out_act2.allocator()->init(TensorInfo(out_shape_fc0, 1, DataType::F32)); - // in:128, out:128 - softmax.configure(&out_act2, &out_softmax); + // Initialize tensor of softmax + const TensorShape out_shape_softmax(out_shape_fc0.x()); + out_softmax.allocator()->init(TensorInfo(out_shape_softmax, 1, DataType::F32)); - /* -----------------------End: [Configure functions] */ + /* -----------------------End: [Initialize tensors] */ - /*[ Add tensors to memory manager ]*/ + /* [Configure functions] */ - // We need 2 memory groups for handling the input and output - // We call explicitly allocate after manage() in order to avoid overlapping lifetimes - MemoryGroup memory_group0(mm_transitions); - MemoryGroup memory_group1(mm_transitions); + // in:32x32x1: 5x5 convolution, 8 output features maps (OFM) + conv0->configure(&src, &weights0, &biases0, &out_conv0, PadStrideInfo(1 /* stride_x */, 1 /* stride_y */, 2 /* pad_x */, 2 /* pad_y */)); - memory_group0.manage(&out_conv0); - out_conv0.allocator()->allocate(); - memory_group1.manage(&out_act0); - out_act0.allocator()->allocate(); - memory_group0.manage(&out_pool0); - out_pool0.allocator()->allocate(); - memory_group1.manage(&out_conv1); - out_conv1.allocator()->allocate(); - memory_group0.manage(&out_act1); - out_act1.allocator()->allocate(); - memory_group1.manage(&out_pool1); - out_pool1.allocator()->allocate(); - memory_group0.manage(&out_fc0); - out_fc0.allocator()->allocate(); - memory_group1.manage(&out_act2); - out_act2.allocator()->allocate(); - memory_group0.manage(&out_softmax); - out_softmax.allocator()->allocate(); + // in:32x32x8, out:32x32x8, Activation function: relu + act0.configure(&out_conv0, &out_act0, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - /* -----------------------End: [ Add tensors to memory manager ] */ + // in:32x32x8, out:16x16x8 (2x2 pooling), Pool type function: Max + pool0.configure(&out_act0, &out_pool0, PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2 /* stride_x */, 2 /* stride_y */))); - /* [Allocate tensors] */ + // in:16x16x8: 3x3 convolution, 16 output features maps (OFM) + conv1->configure(&out_pool0, &weights1, &biases1, &out_conv1, PadStrideInfo(1 /* stride_x */, 1 /* stride_y */, 1 /* pad_x */, 1 /* pad_y */)); - // Now that the padding requirements are known we can allocate all tensors - src.allocator()->allocate(); - weights0.allocator()->allocate(); - weights1.allocator()->allocate(); - weights2.allocator()->allocate(); - biases0.allocator()->allocate(); - biases1.allocator()->allocate(); - biases2.allocator()->allocate(); + // in:16x16x16, out:16x16x16, Activation function: relu + act1.configure(&out_conv1, &out_act1, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - /* -----------------------End: [Allocate tensors] */ + // in:16x16x16, out:8x8x16 (2x2 pooling), Pool type function: Average + pool1.configure(&out_act1, &out_pool1, PoolingLayerInfo(PoolingType::AVG, 2, PadStrideInfo(2 /* stride_x */, 2 /* stride_y */))); - // Finalize layers memory manager + // in:8x8x16, out:128 + fc0->configure(&out_pool1, &weights2, &biases2, &out_fc0); - // Set allocator that the memory manager will use - mm_layers->set_allocator(&allocator); + // in:128, out:128, Activation function: relu + act2.configure(&out_fc0, &out_act2, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); - // Number of pools that the manager will create. This specifies how many layers you want to run in parallel - mm_layers->set_num_pools(1); + // in:128, out:128 + softmax->configure(&out_act2, &out_softmax); - // Finalize the manager. (Validity checks, memory allocations etc) - mm_layers->finalize(); + /* -----------------------End: [Configure functions] */ - // Finalize transitions memory manager + /*[ Add tensors to memory manager ]*/ - // Set allocator that the memory manager will use - mm_transitions->set_allocator(&allocator); + // We need 2 memory groups for handling the input and output + // We call explicitly allocate after manage() in order to avoid overlapping lifetimes + memory_group0 = arm_compute::support::cpp14::make_unique(mm_transitions); + memory_group1 = arm_compute::support::cpp14::make_unique(mm_transitions); - // Number of pools that the manager will create. This specifies how many models we can run in parallel. - // Setting to 2 as we need one for the input and one for the output at any given time - mm_transitions->set_num_pools(2); + memory_group0->manage(&out_conv0); + out_conv0.allocator()->allocate(); + memory_group1->manage(&out_act0); + out_act0.allocator()->allocate(); + memory_group0->manage(&out_pool0); + out_pool0.allocator()->allocate(); + memory_group1->manage(&out_conv1); + out_conv1.allocator()->allocate(); + memory_group0->manage(&out_act1); + out_act1.allocator()->allocate(); + memory_group1->manage(&out_pool1); + out_pool1.allocator()->allocate(); + memory_group0->manage(&out_fc0); + out_fc0.allocator()->allocate(); + memory_group1->manage(&out_act2); + out_act2.allocator()->allocate(); + memory_group0->manage(&out_softmax); + out_softmax.allocator()->allocate(); - // Finalize the manager. (Validity checks, memory allocations etc) - mm_transitions->finalize(); + /* -----------------------End: [ Add tensors to memory manager ] */ - /* [Initialize weights and biases tensors] */ + /* [Allocate tensors] */ - // Once the tensors have been allocated, the src, weights and biases tensors can be initialized - // ... + // Now that the padding requirements are known we can allocate all tensors + src.allocator()->allocate(); + weights0.allocator()->allocate(); + weights1.allocator()->allocate(); + weights2.allocator()->allocate(); + biases0.allocator()->allocate(); + biases1.allocator()->allocate(); + biases2.allocator()->allocate(); - /* -----------------------[Initialize weights and biases tensors] */ + /* -----------------------End: [Allocate tensors] */ - /* [Execute the functions] */ + // Finalize layers memory manager - // Acquire memory for the memory groups - memory_group0.acquire(); - memory_group1.acquire(); + // Set allocator that the memory manager will use + mm_layers->set_allocator(&allocator); - conv0.run(); - act0.run(); - pool0.run(); - conv1.run(); - act1.run(); - pool1.run(); - fc0.run(); - act2.run(); - softmax.run(); + // Number of pools that the manager will create. This specifies how many layers you want to run in parallel + mm_layers->set_num_pools(1); - // Release memory - memory_group0.release(); - memory_group1.release(); + // Finalize the manager. (Validity checks, memory allocations etc) + mm_layers->finalize(); - /* -----------------------End: [Execute the functions] */ -} + // Finalize transitions memory manager + + // Set allocator that the memory manager will use + mm_transitions->set_allocator(&allocator); + + // Number of pools that the manager will create. This specifies how many models we can run in parallel. + // Setting to 2 as we need one for the input and one for the output at any given time + mm_transitions->set_num_pools(2); + + // Finalize the manager. (Validity checks, memory allocations etc) + mm_transitions->finalize(); + } + void do_run() override + { + // Acquire memory for the memory groups + memory_group0->acquire(); + memory_group1->acquire(); + + conv0->run(); + act0.run(); + pool0.run(); + conv1->run(); + act1.run(); + pool1.run(); + fc0->run(); + act2.run(); + softmax->run(); + + // Release memory + memory_group0->release(); + memory_group1->release(); + } + +private: + // The src tensor should contain the input image + Tensor src{}; + + // Intermediate tensors used + Tensor weights0{}; + Tensor weights1{}; + Tensor weights2{}; + Tensor biases0{}; + Tensor biases1{}; + Tensor biases2{}; + Tensor out_conv0{}; + Tensor out_conv1{}; + Tensor out_act0{}; + Tensor out_act1{}; + Tensor out_act2{}; + Tensor out_pool0{}; + Tensor out_pool1{}; + Tensor out_fc0{}; + Tensor out_softmax{}; + + // NEON allocator + Allocator allocator{}; + + // Memory groups + std::unique_ptr memory_group0{}; + std::unique_ptr memory_group1{}; + + // Layers + std::unique_ptr conv0{}; + std::unique_ptr conv1{}; + std::unique_ptr fc0{}; + std::unique_ptr softmax{}; + NEPoolingLayer pool0{}; + NEPoolingLayer pool1{}; + NEActivationLayer act0{}; + NEActivationLayer act1{}; + NEActivationLayer act2{}; +}; /** Main program for cnn test * @@ -293,5 +300,5 @@ void main_cnn(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_cnn); + return utils::run_example(argc, argv); } diff --git a/examples/neon_convolution.cpp b/examples/neon_convolution.cpp index 79800ae897..d51d2013f6 100644 --- a/examples/neon_convolution.cpp +++ b/examples/neon_convolution.cpp @@ -49,62 +49,72 @@ const int16_t gaussian5x5[] = 1, 4, 6, 4, 1 }; -void main_neon_convolution(int argc, char **argv) +class NEONConvolutionExample : public Example { - /** [Accurate padding] **/ - PPMLoader ppm; - Image src, tmp, dst; - - if(argc < 2) - { - // Print help - std::cout << "Usage: ./build/neon_convolution [input_image.ppm]\n\n"; - std::cout << "No input_image provided, creating a dummy 640x480 image\n"; - // Initialize just the dimensions and format of your buffers: - src.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else +public: + void do_setup(int argc, char **argv) override { - ppm.open(argv[1]); - // Initialize just the dimensions and format of your buffers: - ppm.init_image(src, Format::U8); - } + /** [Accurate padding] **/ + PPMLoader ppm; - // Initialize just the dimensions and format of the temporary and destination images: - tmp.allocator()->init(*src.info()); - dst.allocator()->init(*src.info()); + if(argc < 2) + { + // Print help + std::cout << "Usage: ./build/neon_convolution [input_image.ppm]\n\n"; + std::cout << "No input_image provided, creating a dummy 640x480 image\n"; + // Initialize just the dimensions and format of your buffers: + src.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm.open(argv[1]); + // Initialize just the dimensions and format of your buffers: + ppm.init_image(src, Format::U8); + } - NEConvolution3x3 conv3x3; - NEConvolution5x5 conv5x5; + // Initialize just the dimensions and format of the temporary and destination images: + tmp.allocator()->init(*src.info()); + dst.allocator()->init(*src.info()); - // Apply a Gaussian 3x3 filter to the source image followed by a Gaussian 5x5: - // The function will automatically update the padding information inside input and output to match its requirements - conv3x3.configure(&src, &tmp, gaussian3x3, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); - conv5x5.configure(&tmp, &dst, gaussian5x5, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); + // Apply a Gaussian 3x3 filter to the source image followed by a Gaussian 5x5: + // The function will automatically update the padding information inside input and output to match its requirements + conv3x3.configure(&src, &tmp, gaussian3x3, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); + conv5x5.configure(&tmp, &dst, gaussian5x5, 0 /* Let arm_compute calculate the scale */, BorderMode::UNDEFINED); - // Now that the padding requirements are known we can allocate the images: - src.allocator()->allocate(); - tmp.allocator()->allocate(); - dst.allocator()->allocate(); + // Now that the padding requirements are known we can allocate the images: + src.allocator()->allocate(); + tmp.allocator()->allocate(); + dst.allocator()->allocate(); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm.is_open()) + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm.is_open()) + { + ppm.fill_image(src); + output_filename = std::string(argv[1]) + "_out.ppm"; + } + /** [Accurate padding] **/ + } + void do_run() override { - ppm.fill_image(src); + //Execute the functions: + conv3x3.run(); + conv5x5.run(); } - - //Execute the functions: - conv3x3.run(); - conv5x5.run(); - - // Save the result to file: - if(ppm.is_open()) + void do_teardown() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - save_to_ppm(dst, output_filename); + // Save the result to file: + if(!output_filename.empty()) + { + save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + } } - /** [Accurate padding] **/ -} + +private: + Image src{}, tmp{}, dst{}; + NEConvolution3x3 conv3x3{}; + NEConvolution5x5 conv5x5{}; + std::string output_filename{}; +}; /** Main program for convolution test * @@ -113,5 +123,5 @@ void main_neon_convolution(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_neon_convolution); + return utils::run_example(argc, argv); } diff --git a/examples/neon_copy_objects.cpp b/examples/neon_copy_objects.cpp index 55d03dd8bf..9409cf366c 100644 --- a/examples/neon_copy_objects.cpp +++ b/examples/neon_copy_objects.cpp @@ -31,116 +31,128 @@ #include using namespace arm_compute; +using namespace utils; -void main_neon_copy_objects(int argc, char **argv) +class NEONCopyObjectsExample : public Example { - ARM_COMPUTE_UNUSED(argc); - ARM_COMPUTE_UNUSED(argv); +public: + void do_setup(int argc, char **argv) override + { + ARM_COMPUTE_UNUSED(argc); + ARM_COMPUTE_UNUSED(argv); - /** [Copy objects example] */ - constexpr unsigned int width = 4; - constexpr unsigned int height = 3; - constexpr unsigned int batch = 2; + /** [Copy objects example] */ + constexpr unsigned int width = 4; + constexpr unsigned int height = 3; + constexpr unsigned int batch = 2; - auto *src_data = new float[width * height * batch]; - auto *dst_data = new float[width * height * batch]; + src_data = new float[width * height * batch]; + dst_data = new float[width * height * batch]; - // Fill src_data with dummy values: - for(unsigned int b = 0; b < batch; b++) - { - for(unsigned int h = 0; h < height; h++) + // Fill src_data with dummy values: + for(unsigned int b = 0; b < batch; b++) { - for(unsigned int w = 0; w < width; w++) + for(unsigned int h = 0; h < height; h++) { - src_data[b * (width * height) + h * width + w] = static_cast(100 * b + 10 * h + w); + for(unsigned int w = 0; w < width; w++) + { + src_data[b * (width * height) + h * width + w] = static_cast(100 * b + 10 * h + w); + } } } - } - Tensor input, output; - NESoftmaxLayer softmax; - - // Initialize the tensors dimensions and type: - const TensorShape shape(width, height, batch); - input.allocator()->init(TensorInfo(shape, 1, DataType::F32)); - output.allocator()->init(TensorInfo(shape, 1, DataType::F32)); - - // Configure softmax: - softmax.configure(&input, &output); - - // Allocate the input / output tensors: - input.allocator()->allocate(); - output.allocator()->allocate(); - - // Fill the input tensor: - // Simplest way: create an iterator to iterate through each element of the input tensor: - Window input_window; - input_window.use_tensor_dimensions(input.info()->tensor_shape()); - std::cout << " Dimensions of the input's iterator:\n"; - std::cout << " X = [start=" << input_window.x().start() << ", end=" << input_window.x().end() << ", step=" << input_window.x().step() << "]\n"; - std::cout << " Y = [start=" << input_window.y().start() << ", end=" << input_window.y().end() << ", step=" << input_window.y().step() << "]\n"; - std::cout << " Z = [start=" << input_window.z().start() << ", end=" << input_window.z().end() << ", step=" << input_window.z().step() << "]\n"; - - // Create an iterator: - Iterator input_it(&input, input_window); - - // Iterate through the elements of src_data and copy them one by one to the input tensor: - // This is equivalent to: - // for( unsigned int z = 0; z < batch; ++z) - // { - // for( unsigned int y = 0; y < height; ++y) - // { - // for( unsigned int x = 0; x < width; ++x) - // { - // *reinterpret_cast( input.buffer() + input.info()->offset_element_in_bytes(Coordinates(x,y,z))) = src_data[ z * (width*height) + y * width + x]; - // } - // } - // } - // Except it works for an arbitrary number of dimensions - execute_window_loop(input_window, [&](const Coordinates & id) + // Initialize the tensors dimensions and type: + const TensorShape shape(width, height, batch); + input.allocator()->init(TensorInfo(shape, 1, DataType::F32)); + output.allocator()->init(TensorInfo(shape, 1, DataType::F32)); + + // Configure softmax: + softmax.configure(&input, &output); + + // Allocate the input / output tensors: + input.allocator()->allocate(); + output.allocator()->allocate(); + + // Fill the input tensor: + // Simplest way: create an iterator to iterate through each element of the input tensor: + Window input_window; + input_window.use_tensor_dimensions(input.info()->tensor_shape()); + std::cout << " Dimensions of the input's iterator:\n"; + std::cout << " X = [start=" << input_window.x().start() << ", end=" << input_window.x().end() << ", step=" << input_window.x().step() << "]\n"; + std::cout << " Y = [start=" << input_window.y().start() << ", end=" << input_window.y().end() << ", step=" << input_window.y().step() << "]\n"; + std::cout << " Z = [start=" << input_window.z().start() << ", end=" << input_window.z().end() << ", step=" << input_window.z().step() << "]\n"; + + // Create an iterator: + Iterator input_it(&input, input_window); + + // Iterate through the elements of src_data and copy them one by one to the input tensor: + // This is equivalent to: + // for( unsigned int z = 0; z < batch; ++z) + // { + // for( unsigned int y = 0; y < height; ++y) + // { + // for( unsigned int x = 0; x < width; ++x) + // { + // *reinterpret_cast( input.buffer() + input.info()->offset_element_in_bytes(Coordinates(x,y,z))) = src_data[ z * (width*height) + y * width + x]; + // } + // } + // } + // Except it works for an arbitrary number of dimensions + execute_window_loop(input_window, [&](const Coordinates & id) + { + std::cout << "Setting item [" << id.x() << "," << id.y() << "," << id.z() << "]\n"; + *reinterpret_cast(input_it.ptr()) = src_data[id.z() * (width * height) + id.y() * width + id.x()]; + }, + input_it); + + // More efficient way: create an iterator to iterate through each row (instead of each element) of the output tensor: + Window output_window; + output_window.use_tensor_dimensions(output.info()->tensor_shape(), /* first_dimension =*/Window::DimY); // Iterate through the rows (not each element) + std::cout << " Dimensions of the output's iterator:\n"; + std::cout << " X = [start=" << output_window.x().start() << ", end=" << output_window.x().end() << ", step=" << output_window.x().step() << "]\n"; + std::cout << " Y = [start=" << output_window.y().start() << ", end=" << output_window.y().end() << ", step=" << output_window.y().step() << "]\n"; + std::cout << " Z = [start=" << output_window.z().start() << ", end=" << output_window.z().end() << ", step=" << output_window.z().step() << "]\n"; + + // Create an iterator: + Iterator output_it(&output, output_window); + + // Iterate through the rows of the output tensor and copy them to dst_data: + // This is equivalent to: + // for( unsigned int z = 0; z < batch; ++z) + // { + // for( unsigned int y = 0; y < height; ++y) + // { + // memcpy( dst_data + z * (width*height) + y * width, input.buffer() + input.info()->offset_element_in_bytes(Coordinates(0,y,z)), width * sizeof(float)); + // } + // } + // Except it works for an arbitrary number of dimensions + execute_window_loop(output_window, [&](const Coordinates & id) + { + std::cout << "Copying one row starting from [" << id.x() << "," << id.y() << "," << id.z() << "]\n"; + // Copy one whole row: + memcpy(dst_data + id.z() * (width * height) + id.y() * width, output_it.ptr(), width * sizeof(float)); + }, + output_it); + + /** [Copy objects example] */ + } + void do_run() override { - std::cout << "Setting item [" << id.x() << "," << id.y() << "," << id.z() << "]\n"; - *reinterpret_cast(input_it.ptr()) = src_data[id.z() * (width * height) + id.y() * width + id.x()]; - }, - input_it); - - // Run NEON softmax: - softmax.run(); - - // More efficient way: create an iterator to iterate through each row (instead of each element) of the output tensor: - Window output_window; - output_window.use_tensor_dimensions(output.info()->tensor_shape(), /* first_dimension =*/Window::DimY); // Iterate through the rows (not each element) - std::cout << " Dimensions of the output's iterator:\n"; - std::cout << " X = [start=" << output_window.x().start() << ", end=" << output_window.x().end() << ", step=" << output_window.x().step() << "]\n"; - std::cout << " Y = [start=" << output_window.y().start() << ", end=" << output_window.y().end() << ", step=" << output_window.y().step() << "]\n"; - std::cout << " Z = [start=" << output_window.z().start() << ", end=" << output_window.z().end() << ", step=" << output_window.z().step() << "]\n"; - - // Create an iterator: - Iterator output_it(&output, output_window); - - // Iterate through the rows of the output tensor and copy them to dst_data: - // This is equivalent to: - // for( unsigned int z = 0; z < batch; ++z) - // { - // for( unsigned int y = 0; y < height; ++y) - // { - // memcpy( dst_data + z * (width*height) + y * width, input.buffer() + input.info()->offset_element_in_bytes(Coordinates(0,y,z)), width * sizeof(float)); - // } - // } - // Except it works for an arbitrary number of dimensions - execute_window_loop(output_window, [&](const Coordinates & id) + // Run NEON softmax: + softmax.run(); + } + void do_teardown() override { - std::cout << "Copying one row starting from [" << id.x() << "," << id.y() << "," << id.z() << "]\n"; - // Copy one whole row: - memcpy(dst_data + id.z() * (width * height) + id.y() * width, output_it.ptr(), width * sizeof(float)); - }, - output_it); - - delete[] src_data; - delete[] dst_data; - /** [Copy objects example] */ -} + delete[] src_data; + delete[] dst_data; + } +private: + Tensor input{}, output{}; + float *src_data{}; + float *dst_data{}; + NESoftmaxLayer softmax{}; +}; /** Main program for the copy objects test * * @param[in] argc Number of arguments @@ -148,5 +160,5 @@ void main_neon_copy_objects(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_neon_copy_objects); + return utils::run_example(argc, argv); } diff --git a/examples/neon_scale.cpp b/examples/neon_scale.cpp index 3911f5b3ef..bec277da43 100644 --- a/examples/neon_scale.cpp +++ b/examples/neon_scale.cpp @@ -29,55 +29,68 @@ using namespace arm_compute; using namespace utils; -void main_neon_scale(int argc, char **argv) +class NEONScaleExample : public Example { - PPMLoader ppm; - Image src, dst; - - if(argc < 2) - { - // Print help - std::cout << "Usage: ./build/neon_scale[input_image.ppm]\n\n"; - std::cout << "No input_image provided, creating a dummy 640x480 image\n"; - // Create an empty grayscale 640x480 image - src.allocator()->init(TensorInfo(640, 480, Format::U8)); - } - else +public: + void do_setup(int argc, char **argv) override { - ppm.open(argv[1]); - ppm.init_image(src, Format::U8); - } + PPMLoader ppm; - constexpr int scale_factor = 2; + if(argc < 2) + { + // Print help + std::cout << "Usage: ./build/neon_scale[input_image.ppm]\n\n"; + std::cout << "No input_image provided, creating a dummy 640x480 image\n"; + // Create an empty grayscale 640x480 image + src.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm.open(argv[1]); + ppm.init_image(src, Format::U8); + } - TensorInfo dst_tensor_info(src.info()->dimension(0) / scale_factor, src.info()->dimension(1) / scale_factor, Format::U8); + constexpr int scale_factor = 2; - // Configure the destination image - dst.allocator()->init(dst_tensor_info); + TensorInfo dst_tensor_info(src.info()->dimension(0) / scale_factor, src.info()->dimension(1) / scale_factor, + Format::U8); - // Create and initialize a Scale function object: - NEScale scale; - scale.configure(&src, &dst, InterpolationPolicy::NEAREST_NEIGHBOR, BorderMode::UNDEFINED); + // Configure the destination image + dst.allocator()->init(dst_tensor_info); - // Allocate all the images - src.allocator()->allocate(); - dst.allocator()->allocate(); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm.is_open()) - { - ppm.fill_image(src); - } + // Configure Scale function object: + scale.configure(&src, &dst, InterpolationPolicy::NEAREST_NEIGHBOR, BorderMode::UNDEFINED); - // Run the scale operation: - scale.run(); + // Allocate all the images + src.allocator()->allocate(); + dst.allocator()->allocate(); - // Save the result to file: - if(ppm.is_open()) + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm.is_open()) + { + ppm.fill_image(src); + output_filename = std::string(argv[1]) + "_out.ppm"; + } + } + void do_run() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - save_to_ppm(dst, output_filename); + // Run the scale operation: + scale.run(); } -} + void do_teardown() override + { + // Save the result to file: + if(!output_filename.empty()) + { + save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + } + } + +private: + Image src{}, dst{}; + NEScale scale{}; + std::string output_filename{}; +}; /** Main program for convolution test * @@ -86,5 +99,5 @@ void main_neon_scale(int argc, char **argv) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_neon_scale); + return utils::run_example(argc, argv); } diff --git a/examples/neoncl_scale_median_gaussian.cpp b/examples/neoncl_scale_median_gaussian.cpp index 0b72314f7b..084005fd1b 100644 --- a/examples/neoncl_scale_median_gaussian.cpp +++ b/examples/neoncl_scale_median_gaussian.cpp @@ -39,91 +39,100 @@ using namespace utils; * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ -void main_neoncl_scale_median_gaussian(int argc, char **argv) +class NEONCLScaleMedianGaussianExample : public Example { - /** [NEON / OpenCL Interop] */ - PPMLoader ppm; - CLImage src, scale_median, median_gauss, dst; - - CLScheduler::get().default_init(); - - if(argc < 2) +public: + void do_setup(int argc, char **argv) override { - // Print help - std::cout << "Usage: ./build/cl_convolution [input_image.ppm]\n\n"; - std::cout << "No input_image provided, creating a dummy 640x480 image\n"; - // Create an empty grayscale 640x480 image - src.allocator()->init(TensorInfo(640, 480, Format::U8)); + /** [NEON / OpenCL Interop] */ + PPMLoader ppm; + + CLScheduler::get().default_init(); + + if(argc < 2) + { + // Print help + std::cout << "Usage: ./build/cl_convolution [input_image.ppm]\n\n"; + std::cout << "No input_image provided, creating a dummy 640x480 image\n"; + // Create an empty grayscale 640x480 image + src.allocator()->init(TensorInfo(640, 480, Format::U8)); + } + else + { + ppm.open(argv[1]); + ppm.init_image(src, Format::U8); + } + + TensorInfo scale_median_info(TensorInfo(src.info()->dimension(0) / 2, src.info()->dimension(1) / 2, Format::U8)); + + // Configure the temporary and destination images + scale_median.allocator()->init(scale_median_info); + median_gauss.allocator()->init(scale_median_info); + dst.allocator()->init(scale_median_info); + + scale.configure(&src, &scale_median, InterpolationPolicy::NEAREST_NEIGHBOR, BorderMode::REPLICATE); + median.configure(&scale_median, &median_gauss, BorderMode::REPLICATE); + gauss.configure(&median_gauss, &dst, BorderMode::REPLICATE); + + // Allocate all the images + src.allocator()->allocate(); + scale_median.allocator()->allocate(); + median_gauss.allocator()->allocate(); + dst.allocator()->allocate(); + + // Fill the input image with the content of the PPM image if a filename was provided: + if(ppm.is_open()) + { + ppm.fill_image(src); + const std::string output_filename = std::string(argv[1]) + "_out.ppm"; + } + /** [NEON / OpenCL Interop] */ } - else + void do_run() override { - ppm.open(argv[1]); - ppm.init_image(src, Format::U8); - } - - TensorInfo scale_median_info(TensorInfo(src.info()->dimension(0) / 2, src.info()->dimension(1) / 2, Format::U8)); + // Enqueue and flush the OpenCL kernel: + scale.run(); - // Configure the temporary and destination images - scale_median.allocator()->init(scale_median_info); - median_gauss.allocator()->init(scale_median_info); - dst.allocator()->init(scale_median_info); + // Do a blocking map of the input and output buffers of the NEON function: + scale_median.map(); + median_gauss.map(); - // Declare and configure the functions to create the following pipeline: scale -> median -> gauss - CLScale scale; - NEMedian3x3 median; - CLGaussian5x5 gauss; + // Run the NEON function: + median.run(); - scale.configure(&src, &scale_median, InterpolationPolicy::NEAREST_NEIGHBOR, BorderMode::REPLICATE); - median.configure(&scale_median, &median_gauss, BorderMode::REPLICATE); - gauss.configure(&median_gauss, &dst, BorderMode::REPLICATE); + // Unmap the output buffer before it's used again by OpenCL: + scale_median.unmap(); + median_gauss.unmap(); - // Allocate all the images - src.allocator()->allocate(); - scale_median.allocator()->allocate(); - median_gauss.allocator()->allocate(); - dst.allocator()->allocate(); + // Run the final OpenCL function: + gauss.run(); - // Fill the input image with the content of the PPM image if a filename was provided: - if(ppm.is_open()) - { - ppm.fill_image(src); + // Make sure all the OpenCL jobs are done executing: + CLScheduler::get().sync(); } - - // Enqueue and flush the OpenCL kernel: - scale.run(); - - // Do a blocking map of the input and output buffers of the NEON function: - scale_median.map(); - median_gauss.map(); - - // Run the NEON function: - median.run(); - - // Unmap the output buffer before it's used again by OpenCL: - scale_median.unmap(); - median_gauss.unmap(); - - // Run the final OpenCL function: - gauss.run(); - - // Make sure all the OpenCL jobs are done executing: - CLScheduler::get().sync(); - - // Save the result to file: - if(ppm.is_open()) + void do_teardown() override { - const std::string output_filename = std::string(argv[1]) + "_out.ppm"; - save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + // Save the result to file: + if(!output_filename.empty()) + { + save_to_ppm(dst, output_filename); // save_to_ppm maps and unmaps the image to store as PPM + } } - /** [NEON / OpenCL Interop] */ -} -/** Main program for convolution test +private: + CLImage src{}, scale_median{}, median_gauss{}, dst{}; + CLScale scale{}; + NEMedian3x3 median{}; + CLGaussian5x5 gauss{}; + std::string output_filename{}; +}; + +/** Main program for neon/cl scale median gaussian test * * @param[in] argc Number of arguments * @param[in] argv Arguments ( [optional] Path to PPM image to process ) */ int main(int argc, char **argv) { - return utils::run_example(argc, argv, main_neoncl_scale_median_gaussian); + return utils::run_example(argc, argv); } diff --git a/utils/Utils.cpp b/utils/Utils.cpp index c2f5449a28..32d5e3a6c0 100644 --- a/utils/Utils.cpp +++ b/utils/Utils.cpp @@ -66,41 +66,6 @@ void discard_comments_and_spaces(std::ifstream &fs) } } // namespace -//FIXME: Delete once tests have been ported (COMPMID-782) -int run_example(int argc, char **argv, example &func) -{ - std::cout << "\n" - << argv[0] << "\n\n"; - - try - { - func(argc, argv); - - std::cout << "\nTest passed\n"; - return 0; - } -#ifdef ARM_COMPUTE_CL - catch(cl::Error &err) - { - std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cerr << std::endl - << "ERROR " << err.what() << "(" << err.err() << ")" << std::endl; - std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - } -#endif /* ARM_COMPUTE_CL */ - catch(std::runtime_error &err) - { - std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cerr << std::endl - << "ERROR " << err.what() << " " << (errno ? strerror(errno) : "") << std::endl; - std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - } - - std::cout << "\nTest FAILED\n"; - - return -1; -} - #ifndef BENCHMARK_EXAMPLES int run_example(int argc, char **argv, Example &example) { diff --git a/utils/Utils.h b/utils/Utils.h index 9b5d0c4aa9..01e5137669 100644 --- a/utils/Utils.h +++ b/utils/Utils.h @@ -55,23 +55,6 @@ namespace arm_compute { namespace utils { -//FIXME: Delete once tests have been ported (COMPMID-782) -/** Signature of an example to run - * - * @param[in] argc Number of command line arguments - * @param[in] argv Command line arguments - */ -using example = void(int argc, char **argv); - -//FIXME: Delete once tests have been ported (COMPMID-782) -/** Run an example and handle the potential exceptions it throws - * - * @param[in] argc Number of command line arguments - * @param[in] argv Command line arguments - * @param[in] func Pointer to the function containing the code to run - */ -int run_example(int argc, char **argv, example &func); - /** Abstract Example class. * * All examples have to inherit from this class. -- cgit v1.2.1