Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 1 | /* |
Teresa Charlin | 2788609 | 2021-02-25 20:15:01 +0000 | [diff] [blame] | 2 | * Copyright (c) 2017-2021 Arm Limited. |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: MIT |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to |
| 8 | * deal in the Software without restriction, including without limitation the |
| 9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
| 10 | * sell copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in all |
| 14 | * copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 | * SOFTWARE. |
| 23 | */ |
| 24 | #include "arm_compute/runtime/CL/functions/CLFullyConnectedLayer.h" |
| 25 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 26 | #include "arm_compute/core/CL/CLKernelLibrary.h" |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 27 | #include "arm_compute/runtime/CL/CLScheduler.h" |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 28 | #include "src/core/helpers/MemoryHelpers.h" |
| 29 | #include "src/runtime/gpu/cl/operators/ClFullyConnected.h" |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 30 | |
Michalis Spyrou | b27e13a | 2019-09-27 11:04:27 +0100 | [diff] [blame] | 31 | namespace arm_compute |
| 32 | { |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 33 | using namespace arm_compute::experimental; |
Georgios Pinitas | 358ca20 | 2017-12-07 16:47:52 +0000 | [diff] [blame] | 34 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 35 | struct CLFullyConnectedLayer::Impl |
Georgios Pinitas | 358ca20 | 2017-12-07 16:47:52 +0000 | [diff] [blame] | 36 | { |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 37 | MemoryGroup memory_group{}; |
| 38 | IWeightsManager *weights_manager{ nullptr }; |
Georgios Pinitas | 8b72199 | 2019-10-28 16:24:28 +0000 | [diff] [blame] | 39 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 40 | std::unique_ptr<opencl::ClFullyConnected> op{ nullptr }; |
Sang-Hoon Park | b66aa3b | 2020-01-10 14:44:13 +0000 | [diff] [blame] | 41 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 42 | const ITensor *original_weights{ nullptr }; |
Georgios Pinitas | 8b72199 | 2019-10-28 16:24:28 +0000 | [diff] [blame] | 43 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 44 | ITensorPack run_pack{}; |
| 45 | WorkspaceData<CLTensor> workspace{}; |
| 46 | experimental::MemoryRequirements aux_mem_req{}; |
Georgios Pinitas | 8b72199 | 2019-10-28 16:24:28 +0000 | [diff] [blame] | 47 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 48 | bool is_prepared{ false }; |
| 49 | }; |
Gian Marco Iodice | edfa9f4 | 2017-08-15 11:45:22 +0100 | [diff] [blame] | 50 | |
Michalis Spyrou | 1a569a3 | 2019-09-10 17:20:34 +0100 | [diff] [blame] | 51 | CLFullyConnectedLayer::CLFullyConnectedLayer(std::shared_ptr<IMemoryManager> memory_manager, IWeightsManager *weights_manager) |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 52 | : _impl(std::make_unique<Impl>()) |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 53 | { |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 54 | _impl->memory_group = MemoryGroup(std::move(memory_manager)); |
| 55 | _impl->weights_manager = weights_manager; |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 56 | } |
Teresa Charlin | 2788609 | 2021-02-25 20:15:01 +0000 | [diff] [blame] | 57 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 58 | CLFullyConnectedLayer::~CLFullyConnectedLayer() = default; |
Gian Marco Iodice | edfa9f4 | 2017-08-15 11:45:22 +0100 | [diff] [blame] | 59 | |
Georgios Pinitas | 7d66a8e | 2018-07-17 12:28:42 +0100 | [diff] [blame] | 60 | void CLFullyConnectedLayer::configure(const ICLTensor *input, const ICLTensor *weights, const ICLTensor *biases, ICLTensor *output, |
| 61 | FullyConnectedLayerInfo fc_info) |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 62 | { |
Manuel Bottini | 2b84be5 | 2020-04-08 10:15:51 +0100 | [diff] [blame] | 63 | configure(CLKernelLibrary::get().get_compile_context(), input, weights, biases, output, fc_info); |
| 64 | } |
| 65 | |
| 66 | void CLFullyConnectedLayer::configure(const CLCompileContext &compile_context, const ICLTensor *input, const ICLTensor *weights, const ICLTensor *biases, ICLTensor *output, |
| 67 | FullyConnectedLayerInfo fc_info) |
| 68 | { |
Georgios Pinitas | 358ca20 | 2017-12-07 16:47:52 +0000 | [diff] [blame] | 69 | // Perform validate step |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 70 | ARM_COMPUTE_ERROR_ON_NULLPTR(input, weights, output); |
Georgios Pinitas | 358ca20 | 2017-12-07 16:47:52 +0000 | [diff] [blame] | 71 | ARM_COMPUTE_ERROR_THROW_ON(CLFullyConnectedLayer::validate(input->info(), |
| 72 | weights->info(), |
| 73 | biases != nullptr ? biases->info() : nullptr, |
| 74 | output->info(), |
Georgios Pinitas | 7d66a8e | 2018-07-17 12:28:42 +0100 | [diff] [blame] | 75 | fc_info)); |
Gian Marco Iodice | edfa9f4 | 2017-08-15 11:45:22 +0100 | [diff] [blame] | 76 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 77 | _impl->op = std::make_unique<opencl::ClFullyConnected>(); |
| 78 | _impl->original_weights = weights; |
Georgios Pinitas | f5d51f3 | 2021-08-17 16:09:10 +0100 | [diff] [blame] | 79 | _impl->is_prepared = fc_info.retain_internal_weights; |
Gian Marco Iodice | edfa9f4 | 2017-08-15 11:45:22 +0100 | [diff] [blame] | 80 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 81 | _impl->op->configure(compile_context, input->info(), weights->info(), (biases != nullptr) ? biases->info() : nullptr, output->info(), fc_info); |
Michalis Spyrou | b27e13a | 2019-09-27 11:04:27 +0100 | [diff] [blame] | 82 | |
Georgios Pinitas | 45fbf9f | 2021-08-13 12:07:59 +0100 | [diff] [blame] | 83 | if(_impl->weights_manager != nullptr) |
| 84 | { |
Giorgio Arena | 73df931 | 2021-08-16 12:29:27 +0100 | [diff] [blame] | 85 | _impl->weights_manager->manage(_impl->original_weights); |
Georgios Pinitas | 45fbf9f | 2021-08-13 12:07:59 +0100 | [diff] [blame] | 86 | } |
| 87 | |
Georgios Pinitas | f5d51f3 | 2021-08-17 16:09:10 +0100 | [diff] [blame] | 88 | if(!_impl->is_prepared) |
| 89 | { |
| 90 | _impl->aux_mem_req = _impl->op->workspace(); |
| 91 | _impl->run_pack = { { ACL_SRC_0, input }, { ACL_SRC_1, weights }, { ACL_SRC_2, biases }, { ACL_DST, output } }; |
| 92 | _impl->workspace = manage_workspace<CLTensor>(_impl->aux_mem_req, _impl->memory_group, _impl->run_pack, _impl->run_pack); |
| 93 | } |
| 94 | else |
| 95 | { |
| 96 | _impl->run_pack.add_tensor(ACL_SRC_0, input); |
| 97 | _impl->run_pack.add_tensor(ACL_DST, output); |
| 98 | } |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 99 | } |
| 100 | |
Georgios Pinitas | 7d66a8e | 2018-07-17 12:28:42 +0100 | [diff] [blame] | 101 | Status CLFullyConnectedLayer::validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, |
| 102 | FullyConnectedLayerInfo fc_info) |
Georgios Pinitas | 358ca20 | 2017-12-07 16:47:52 +0000 | [diff] [blame] | 103 | { |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 104 | return opencl::ClFullyConnected::validate(input, weights, biases, output, fc_info); |
Georgios Pinitas | 358ca20 | 2017-12-07 16:47:52 +0000 | [diff] [blame] | 105 | } |
| 106 | |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 107 | void CLFullyConnectedLayer::run() |
| 108 | { |
Georgios Pinitas | e043767 | 2018-05-02 14:07:55 +0100 | [diff] [blame] | 109 | prepare(); |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 110 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 111 | MemoryGroupResourceScope scope_mg(_impl->memory_group); |
| 112 | _impl->op->run(_impl->run_pack); |
Anthony Barbier | 6ff3b19 | 2017-09-04 18:44:23 +0100 | [diff] [blame] | 113 | } |
Georgios Pinitas | e043767 | 2018-05-02 14:07:55 +0100 | [diff] [blame] | 114 | |
| 115 | void CLFullyConnectedLayer::prepare() |
| 116 | { |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 117 | if(!_impl->is_prepared) |
Georgios Pinitas | e043767 | 2018-05-02 14:07:55 +0100 | [diff] [blame] | 118 | { |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 119 | _impl->op->prepare(_impl->run_pack); |
Georgios Pinitas | e043767 | 2018-05-02 14:07:55 +0100 | [diff] [blame] | 120 | |
Georgios Pinitas | 529b5a2 | 2021-07-27 15:55:30 +0100 | [diff] [blame] | 121 | // Release temporary tensors that are only used in prepare stage |
| 122 | release_temporaries<CLTensor>(_impl->aux_mem_req, _impl->workspace); |
| 123 | _impl->is_prepared = true; |
Georgios Pinitas | 45fbf9f | 2021-08-13 12:07:59 +0100 | [diff] [blame] | 124 | |
| 125 | // Handle weights managed infrastructure |
| 126 | if(_impl->weights_manager != nullptr && _impl->weights_manager->are_weights_managed(_impl->original_weights)) |
| 127 | { |
Giorgio Arena | 73df931 | 2021-08-16 12:29:27 +0100 | [diff] [blame] | 128 | // Ensure that b gets marked as unused (memory released) only after the last function which uses b also finishes its prepare |
| 129 | // This is for cases where multiple functions share the same b (weights) |
| 130 | // Therefore when a function marks original b as unused, we pre-mark it in weights manager, and mark it back to used so that it doesn't get released before its last reference |
Georgios Pinitas | 45fbf9f | 2021-08-13 12:07:59 +0100 | [diff] [blame] | 131 | const ITensor *original_b = _impl->original_weights; |
| 132 | if(!original_b->is_used()) |
| 133 | { |
Giorgio Arena | 73df931 | 2021-08-16 12:29:27 +0100 | [diff] [blame] | 134 | _impl->weights_manager->pre_mark_as_unused(original_b); |
Georgios Pinitas | 45fbf9f | 2021-08-13 12:07:59 +0100 | [diff] [blame] | 135 | } |
| 136 | _impl->original_weights->mark_as_used(); |
| 137 | _impl->weights_manager->release(_impl->original_weights); |
| 138 | } |
Georgios Pinitas | e043767 | 2018-05-02 14:07:55 +0100 | [diff] [blame] | 139 | } |
| 140 | } |
Michalis Spyrou | b27e13a | 2019-09-27 11:04:27 +0100 | [diff] [blame] | 141 | } // namespace arm_compute |