summaryrefslogtreecommitdiff
path: root/runtimes/neurun/core/src/exec/interp/operations/MaxPool2D.cc
blob: e53fa14738987adb54091ce352403ea18860030e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 <cker/operation/MaxPool.h>

#include "OperationUtil.h"

#include "exec/interp/Registration.h"
#include "model/operation/MaxPool2DNode.h"
#include "util/Utils.h"
#include "util/Padding.h"
#include "util/ShapeInference.h"
#include "misc/polymorphic_downcast.h"

namespace neurun
{
namespace exec
{
namespace interp
{
namespace
{

void prepareMaxPool2D(ExecEnv *env, const model::Operation &node)
{
  const auto in_index = node.getInputs().at(0);
  const auto out_index = node.getOutputs().at(0);

  const auto in_tensor = env->tensorAt(in_index);

  assert(in_tensor->num_dimensions() == 4);
  UNUSED_RELEASE(in_tensor);

  const auto output_info = env->model().operands.at(out_index).info();
  if (output_info.total_size() == 0)
  {
    // Handle unspecified output shape
    const auto &maxpool_node =
        nnfw::misc::polymorphic_downcast<const model::operation::MaxPool2DNode &>(node);
    const auto infered_output_shapes =
        shape_inference::inferMaxPoolShape(in_tensor->tensorInfo().shape(), maxpool_node.param());
    env->allocateIfNeeded(out_index, {infered_output_shapes[0], output_info.typeInfo()});
  }
  else
  {
    env->allocateIfNeeded(out_index, output_info);
  }

  auto out_tensor = env->tensorAt(out_index);
  UNUSED_RELEASE(out_tensor);

  // Handle same ifm & ofm data type only
  assert(in_tensor->data_type() == out_tensor->data_type());
  assert(out_tensor->num_dimensions() == 4);
}

void invoke(const ITensor *in_tensor, const ITensor *out_tensor,
            const model::operation::MaxPool2DNode::Param &param)
{
  // TODO support NCHW frontend
  const auto ifm_shape = in_tensor->tensorInfo().shape().asFeature(model::Layout::NHWC);
  const auto ofm_shape = out_tensor->tensorInfo().shape().asFeature(model::Layout::NHWC);
  const auto padding = neurun::util::calculatePadding(param.padding, ifm_shape, ofm_shape,
                                                      param.stride, param.kw, param.kh);
  // Calculate
  nnfw::cker::MaxPoolParams cker_param;
  calculateActivationRange(param.activation, &cker_param.float_activation_min,
                           &cker_param.float_activation_max);
  cker_param.filter_width = param.kw;
  cker_param.filter_height = param.kh;
  cker_param.padding_values.width = padding.left;
  cker_param.padding_values.height = padding.top;
  cker_param.stride_width = param.stride.horizontal;
  cker_param.stride_height = param.stride.vertical;

  const auto in_shape = convertShape(in_tensor->tensorInfo().shape());
  const auto out_shape = convertShape(out_tensor->tensorInfo().shape());
  const float *in_ptr = reinterpret_cast<const float *>(in_tensor->bufferRO());
  float *out_ptr = reinterpret_cast<float *>(out_tensor->buffer());

  nnfw::cker::MaxPool(cker_param, in_shape, in_ptr, out_shape, out_ptr);
}

void invokeMaxPool2D(const ExecEnv *env, const model::Operation &node)
{
  const auto &maxpool_node =
      nnfw::misc::polymorphic_downcast<const model::operation::MaxPool2DNode &>(node);

  const auto in_index = node.getInputs().at(0);
  const auto out_index = node.getOutputs().at(0);

  const auto in_tensor = env->tensorAt(in_index);
  const auto out_tensor = env->tensorAt(out_index);

  const auto data_type = in_tensor->data_type();
  if (data_type == model::DataType::FLOAT32)
  {
    invoke(in_tensor, out_tensor, maxpool_node.param());
  }
  else
  {
    throw std::runtime_error{"NYI: Support float32 only"};
  }
}
} // namespace

OpKernel *getMaxPool2DNode()
{
  static OpKernel kernel = {prepareMaxPool2D, invokeMaxPool2D};
  return &kernel;
}

} // namespace interp
} // namespace exec
} // namespace neurun