// Tencent is pleased to support the open source community by making ncnn available. // // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. // // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // https://opensource.org/licenses/BSD-3-Clause // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "concat.h" #include namespace ncnn { DEFINE_LAYER_CREATOR(Concat) Concat::Concat() { one_blob_only = false; support_inplace = false; support_vulkan = true; #if NCNN_VULKAN pipeline_concat = 0; pipeline_concat_pack4 = 0; pipeline_concat_pack4to1 = 0; #endif // NCNN_VULKAN } int Concat::load_param(const ParamDict& pd) { axis = pd.get(0, 0); return 0; } int Concat::forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const { int dims = bottom_blobs[0].dims; size_t elemsize = bottom_blobs[0].elemsize; if (dims == 1) // axis == 0 { // concat vector // total length int top_w = 0; for (size_t b=0; b specializations(1); specializations[0].i = axis; // pack1 { pipeline_concat = new Pipeline(vkdev); pipeline_concat->set_optimal_local_size_xyz(); pipeline_concat->create("concat", specializations, 2, 11); } // pack4 { pipeline_concat_pack4 = new Pipeline(vkdev); pipeline_concat_pack4->set_optimal_local_size_xyz(); pipeline_concat_pack4->create("concat_pack4", specializations, 2, 11); } // pack4to1 { pipeline_concat_pack4to1 = new Pipeline(vkdev); pipeline_concat_pack4to1->set_optimal_local_size_xyz(); pipeline_concat_pack4to1->create("concat_pack4to1", specializations, 2, 11); } return 0; } int Concat::destroy_pipeline() { delete pipeline_concat; pipeline_concat = 0; delete pipeline_concat_pack4; pipeline_concat_pack4 = 0; delete pipeline_concat_pack4to1; pipeline_concat_pack4to1 = 0; return 0; } int Concat::forward(const std::vector& bottom_blobs, std::vector& top_blobs, VkCompute& cmd, const Option& opt) const { int dims = bottom_blobs[0].dims; if (dims == 1) // axis == 0 { // concat vector // total length size_t elemsize = bottom_blobs[0].elemsize; int packing = bottom_blobs[0].packing; int top_w = 0; for (size_t b=0; b bindings(2); bindings[0] = bottom_blob; bindings[1] = top_blob; std::vector constants(11); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; constants[2].i = bottom_blob.h; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; constants[7].i = top_blob.h; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; constants[10].i = woffset; const Pipeline* pipeline = 0; if (bottom_blob.packing == 1 && out_packing == 1) { pipeline = pipeline_concat; } else if (bottom_blob.packing == 4 && out_packing == 4) { pipeline = pipeline_concat_pack4; } else if (bottom_blob.packing == 4 && out_packing == 1) { pipeline = pipeline_concat_pack4to1; } // record cmd.record_prepare_compute_barrier(bottom_blob); cmd.record_pipeline(pipeline, bindings, constants, bottom_blob); woffset += bottom_blob.w * bottom_blob.packing / out_packing; } return 0; } if (dims == 2 && axis == 0) { // concat image int w = bottom_blobs[0].w; // total height size_t elemsize = bottom_blobs[0].elemsize; int packing = bottom_blobs[0].packing; int top_h = 0; for (size_t b=0; b bindings(2); bindings[0] = bottom_blob; bindings[1] = top_blob; std::vector constants(11); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; constants[2].i = bottom_blob.h; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; constants[7].i = top_blob.h; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; constants[10].i = hoffset; const Pipeline* pipeline = 0; if (bottom_blob.packing == 1 && out_packing == 1) { pipeline = pipeline_concat; } else if (bottom_blob.packing == 4 && out_packing == 4) { pipeline = pipeline_concat_pack4; } else if (bottom_blob.packing == 4 && out_packing == 1) { pipeline = pipeline_concat_pack4to1; } // record cmd.record_prepare_compute_barrier(bottom_blob); cmd.record_pipeline(pipeline, bindings, constants, bottom_blob); hoffset += bottom_blob.h * bottom_blob.packing / out_packing; } return 0; } if (dims == 2 && axis == 1) { // interleave image row int h = bottom_blobs[0].h; size_t elemsize = bottom_blobs[0].elemsize; int packing = bottom_blobs[0].packing; // total width int top_w = 0; for (size_t b=0; b bindings(2); bindings[0] = bottom_blob; bindings[1] = top_blob; std::vector constants(11); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; constants[2].i = bottom_blob.h; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; constants[7].i = top_blob.h; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; constants[10].i = woffset; const Pipeline* pipeline = packing == 4 ? pipeline_concat_pack4 : pipeline_concat; // record cmd.record_prepare_compute_barrier(bottom_blob); cmd.record_pipeline(pipeline, bindings, constants, bottom_blob); woffset += bottom_blob.w; } return 0; } if (dims == 3 && axis == 0) { // concat dim int w = bottom_blobs[0].w; int h = bottom_blobs[0].h; // total channels size_t elemsize = bottom_blobs[0].elemsize; int packing = bottom_blobs[0].packing; int top_channels = 0; for (size_t b=0; b bindings(2); bindings[0] = bottom_blob; bindings[1] = top_blob; std::vector constants(11); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; constants[2].i = bottom_blob.h; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; constants[7].i = top_blob.h; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; constants[10].i = coffset; const Pipeline* pipeline = 0; if (bottom_blob.packing == 1 && out_packing == 1) { pipeline = pipeline_concat; } else if (bottom_blob.packing == 4 && out_packing == 4) { pipeline = pipeline_concat_pack4; } else if (bottom_blob.packing == 4 && out_packing == 1) { pipeline = pipeline_concat_pack4to1; } // record cmd.record_prepare_compute_barrier(bottom_blob); cmd.record_pipeline(pipeline, bindings, constants, bottom_blob); coffset += bottom_blob.c * bottom_blob.packing / out_packing; } return 0; } if (dims == 3 && axis == 1) { // interleave dim height int w = bottom_blobs[0].w; int channels = bottom_blobs[0].c; size_t elemsize = bottom_blobs[0].elemsize; int packing = bottom_blobs[0].packing; // total height int top_h = 0; for (size_t b=0; b bindings(2); bindings[0] = bottom_blob; bindings[1] = top_blob; std::vector constants(11); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; constants[2].i = bottom_blob.h; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; constants[7].i = top_blob.h; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; constants[10].i = hoffset; const Pipeline* pipeline = packing == 4 ? pipeline_concat_pack4 : pipeline_concat; // record cmd.record_prepare_compute_barrier(bottom_blob); cmd.record_pipeline(pipeline, bindings, constants, bottom_blob); hoffset += bottom_blob.h; } return 0; } if (dims == 3 && axis == 2) { // interleave dim width int h = bottom_blobs[0].h; int channels = bottom_blobs[0].c; size_t elemsize = bottom_blobs[0].elemsize; int packing = bottom_blobs[0].packing; // total height int top_w = 0; for (size_t b=0; b bindings(2); bindings[0] = bottom_blob; bindings[1] = top_blob; std::vector constants(11); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; constants[2].i = bottom_blob.h; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; constants[7].i = top_blob.h; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; constants[10].i = woffset; const Pipeline* pipeline = packing == 4 ? pipeline_concat_pack4 : pipeline_concat; // record cmd.record_prepare_compute_barrier(bottom_blob); cmd.record_pipeline(pipeline, bindings, constants, bottom_blob); woffset += bottom_blob.w; } return 0; } return 0; } #endif // NCNN_VULKAN } // namespace ncnn