LoginSignup
0
0

More than 3 years have passed since last update.

ONNXで eliminate_nop_pad 最適化

Posted at

NNXがサポートしている最適化 eliminate_nop_pad を調べてみました。

最適化をしている箇所のソースがこちらです。
https://github.com/onnx/onnx/blob/master/onnx/optimizer/passes/eliminate_nop_pad.h

static bool is_nop_pad(Node* node, Graph& graph) {
    if (node->hasAttribute(kpads)) {
      // opset 10 and below
      const auto& pads = node->is(kpads);
      for (size_t i = 0; i < pads.size(); i++) {
        // if pad constant_value is non-zero, this is not a nop pad
        if (pads[i] != 0) {
          return false;                 
        }
      }
      return true;
    } else {
      // opset 11 and above
      const auto& pads_name = node->inputs()[1]->uniqueName();
      const auto pads_initializer = graph.getInitializer(pads_name);
      // 'pad' node has the 'pads' input which has not been initialized -
      // can't proceed with elimination
      if (pads_initializer == graph.initializers().end())
        return false;

      // validate values within 'pads'
      if (pads_initializer->elem_type() == TensorProto::INT64) {
        const auto& pads = ParseData<int64_t>(&*pads_initializer);
        for (const auto& val : pads) {
          // if pad constant_value is non-zero, this is not a nop pad
          if (val != 0) {
            return false;
          }      
        }
        return true;
      }
    }

    return false;
  }

padサイズが0の時、何もPaddingしないの(nop)ので削除する最適化ですね。いちいち名前つけないで、operationがnopと同等の時削除する最適化でくくった方が良いような気がします。

これも実際にやってみましょう。

eliminate_nop_pad.onnx.png

二つあるPadsのうち、片方がpads = [0, 0, 0, 0]、もう片方がpads = [0, 1, 0, 1]です。
最適化すると、片方だけ削除されるはずです。

passes = ['eliminate_nop_pad']

optimized_model = optimizer.optimize(model_def, passes)

eliminate_nop_pad_optimized.onnx.png

上手く行きました。

全ソースはこちら。

import onnx
from onnx import helper
from onnx import TensorProto
from onnx import optimizer

X = helper.make_tensor_value_info('X', TensorProto.FLOAT, [1, 2])
Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, [1, 4])

pad0 = helper.make_node(
    'Pad',
    ['X'],
    ['pad0_out'],
    mode = 'constant',
    value = 1.5,
    pads = [0, 1, 0, 1]
)

pad1 = helper.make_node(
    'Pad',
    ['X'],
    ['pad1_out'],
    mode = 'constant',
    value = 1.5,
    pads = [0, 0, 0, 0]
)

concat = helper.make_node(
    'Concat',
    ['pad0_out', 'pad1_out'],
    ['Y'],
)

graph_def = helper.make_graph(
    [pad0, pad1, concat],
    'test-model',
    [X],
    [Y]
)

model_def = helper.make_model(
    graph_def,
    producer_name='onnx_example'
)

onnx.save(model_def, 'onnx/eliminate_nop_pad.onnx')

# 最適化パスを指定
passes = ['eliminate_nop_pad']

optimized_model = optimizer.optimize(model_def, passes)
onnx.save(optimized_model, 'onnx/eliminate_nop_pad_optimized.onnx')
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0