Browse Source

pnnx convert onnx conv convtranspose (#5515)

tags/20240820
nihui GitHub 1 year ago
parent
commit
21babb7eed
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
29 changed files with 2363 additions and 21 deletions
  1. +1
    -1
      .ci/pnnx.yml
  2. +3
    -0
      tools/pnnx/src/CMakeLists.txt
  3. +21
    -0
      tools/pnnx/src/load_onnx.cpp
  4. +154
    -0
      tools/pnnx/src/pass_level2/F_conv1d.cpp
  5. +154
    -0
      tools/pnnx/src/pass_level2/F_conv3d.cpp
  6. +276
    -0
      tools/pnnx/src/pass_level2/F_conv_transpose1d.cpp
  7. +102
    -1
      tools/pnnx/src/pass_level2/F_conv_transpose2d.cpp
  8. +276
    -0
      tools/pnnx/src/pass_level2/F_conv_transpose3d.cpp
  9. +78
    -4
      tools/pnnx/src/pass_level2/F_pad.cpp
  10. +37
    -0
      tools/pnnx/src/pass_level2/Tensor_reshape.cpp
  11. +27
    -0
      tools/pnnx/src/pass_level2/torch_mean.cpp
  12. +6
    -6
      tools/pnnx/src/pass_level5/fuse_pad_conv2d.cpp
  13. +0
    -9
      tools/pnnx/src/pass_onnx.cpp
  14. +271
    -0
      tools/pnnx/src/pass_onnx/fuse_constant_as_attribute.cpp
  15. +25
    -0
      tools/pnnx/src/pass_onnx/fuse_constant_as_attribute.h
  16. +15
    -0
      tools/pnnx/tests/onnx/CMakeLists.txt
  17. +66
    -0
      tools/pnnx/tests/onnx/test_F_conv1d.py
  18. +66
    -0
      tools/pnnx/tests/onnx/test_F_conv2d.py
  19. +66
    -0
      tools/pnnx/tests/onnx/test_F_conv3d.py
  20. +65
    -0
      tools/pnnx/tests/onnx/test_F_conv_transpose1d.py
  21. +65
    -0
      tools/pnnx/tests/onnx/test_F_conv_transpose2d.py
  22. +65
    -0
      tools/pnnx/tests/onnx/test_F_conv_transpose3d.py
  23. +73
    -0
      tools/pnnx/tests/onnx/test_F_pad.py
  24. +73
    -0
      tools/pnnx/tests/onnx/test_nn_Conv1d.py
  25. +73
    -0
      tools/pnnx/tests/onnx/test_nn_Conv2d.py
  26. +77
    -0
      tools/pnnx/tests/onnx/test_nn_Conv3d.py
  27. +76
    -0
      tools/pnnx/tests/onnx/test_nn_ConvTranspose1d.py
  28. +76
    -0
      tools/pnnx/tests/onnx/test_nn_ConvTranspose2d.py
  29. +76
    -0
      tools/pnnx/tests/onnx/test_nn_ConvTranspose3d.py

+ 1
- 1
.ci/pnnx.yml View File

@@ -75,7 +75,7 @@ jobs:
python3 -m pip install --upgrade pip
apt-get remove -y python3-setuptools
pip3 install -U setuptools==69.5.1
pip3 install -U pytest wheel twine requests einops
pip3 install -U pytest wheel twine requests einops numpy==1.26.4
cd ${{ci.workspace}}
wget -q https://github.com/Kitware/CMake/releases/download/v3.29.3/cmake-3.29.3-linux-x86_64.tar.gz
tar -xf cmake-3.29.3-linux-x86_64.tar.gz


+ 3
- 0
tools/pnnx/src/CMakeLists.txt View File

@@ -124,7 +124,9 @@ set(pnnx_pass_level2_SRCS
pass_level2/F_conv2d.cpp
pass_level2/F_conv3d.cpp
pass_level2/F_conv_transpose123d.cpp
pass_level2/F_conv_transpose1d.cpp
pass_level2/F_conv_transpose2d.cpp
pass_level2/F_conv_transpose3d.cpp
pass_level2/F_dropout.cpp
pass_level2/F_dropout23d.cpp
pass_level2/F_elu.cpp
@@ -650,6 +652,7 @@ if(onnxruntime_FOUND)
pass_onnx/inline_containers.cpp
pass_onnx/model_stat.cpp
pass_onnx/shape_inference.cpp
pass_onnx/fuse_constant_as_attribute.cpp

pass_onnx/nn_AdaptiveAvgPool2d.cpp
pass_onnx/nn_AdaptiveAvgPool3d.cpp


+ 21
- 0
tools/pnnx/src/load_onnx.cpp View File

@@ -34,6 +34,7 @@
#include "pass_onnx/inline_containers.h"
#include "pass_onnx/model_stat.h"
#include "pass_onnx/shape_inference.h"
#include "pass_onnx/fuse_constant_as_attribute.h"

#include "pass_onnx.h"

@@ -652,6 +653,26 @@ int load_onnx(const std::string& onnxpath, Graph& pnnx_graph,
}
}

fprintf(stderr, "%-34s", "fuse_constant_as_attribute ... ");

t0 = get_current_time();

onnx2pnnx::fuse_constant_as_attribute(model);

t1 = get_current_time();

fprintf(stderr, "%8.2fms\n", t1 - t0);

fprintf(stderr, "%-34s", "dead_code_elimination ... ");

t0 = get_current_time();

onnx2pnnx::dead_code_elimination(model);

t1 = get_current_time();

fprintf(stderr, "%8.2fms\n", t1 - t0);

onnx2pnnx::ModelStat newstat = onnx2pnnx::get_model_stat(model);

onnx2pnnx::print_model_stat(oldstat, newstat);


+ 154
- 0
tools/pnnx/src/pass_level2/F_conv1d.cpp View File

@@ -77,4 +77,158 @@ pnnx.Output output 1 0 out

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_convmode, 10)

class F_conv1d_onnx : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
Conv op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv1d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 1)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 1)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 1)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 2 || pads[0] != pads[1])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0]};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv1d_onnx, 10)

class F_conv1d_onnx_0 : public F_conv1d_onnx
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
Conv op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv1d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv1d_onnx_0, 10)

class F_conv1d_onnx_1 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
Conv op_0 3 1 input weight bias out strides=%strides pads=%pads dilations=%dilations group=%group auto_pad=NOTSET
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv1d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 1)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 1)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 2 || pads[0] != pads[1])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0]};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv1d_onnx_1, 10)

} // namespace pnnx

+ 154
- 0
tools/pnnx/src/pass_level2/F_conv3d.cpp View File

@@ -98,4 +98,158 @@ pnnx.Output output 1 0 out

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv3d_0, 10)

class F_conv3d_onnx : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
Conv op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv3d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 3)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 3)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 3)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 6 || pads[0] != pads[3] || pads[1] != pads[4] || pads[2] != pads[5])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0], pads[1], pads[2]};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv3d_onnx, 10)

class F_conv3d_onnx_0 : public F_conv3d_onnx
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
Conv op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv3d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv3d_onnx_0, 10)

class F_conv3d_onnx_1 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
Conv op_0 3 1 input weight bias out strides=%strides pads=%pads dilations=%dilations group=%group auto_pad=NOTSET
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv3d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 3)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 3)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 6 || pads[0] != pads[3] || pads[1] != pads[4] || pads[2] != pads[5])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0], pads[1], pads[2]};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv3d_onnx_1, 10)

} // namespace pnnx

+ 276
- 0
tools/pnnx/src/pass_level2/F_conv_transpose1d.cpp View File

@@ -0,0 +1,276 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2024 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 "pass_level2.h"

namespace pnnx {

class F_conv_transpose1d_onnx : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose1d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 1)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 1)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 1)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 2 || pads[0] != pads[1])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0]};
op->params["output_padding"] = {0};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose1d_onnx, 10)

class F_conv_transpose1d_onnx_0 : public F_conv_transpose1d_onnx
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
ConvTranspose op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv_transpose1d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose1d_onnx_0, 10)

class F_conv_transpose1d_onnx_1 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out strides=%strides pads=%pads dilations=%dilations group=%group auto_pad=NOTSET
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose1d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 1)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 1)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 2 || pads[0] != pads[1])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0]};
op->params["output_padding"] = {0};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose1d_onnx_1, 10)

class F_conv_transpose1d_onnx_2 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group output_padding=%output_padding
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose1d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 1)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 1)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 1)
return false;

if (captured_params.at("output_padding").type != 5)
return false;

if (captured_params.at("output_padding").ai.size() != 1)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 2 || pads[0] != pads[1])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0]};
op->params["output_padding"] = captured_params.at("output_padding");
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose1d_onnx_2, 10)

class F_conv_transpose1d_onnx_3 : public F_conv_transpose1d_onnx_2
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
ConvTranspose op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group output_padding=%output_padding
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv_transpose1d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose1d_onnx_3, 10)

} // namespace pnnx

+ 102
- 1
tools/pnnx/src/pass_level2/F_conv_transpose2d.cpp View File

@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
// Copyright (C) 2024 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
@@ -172,4 +172,105 @@ pnnx.Output output 1 0 out

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose2d_onnx_1, 10)

class F_conv_transpose2d_onnx_2 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group output_padding=%output_padding
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 2)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 2)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 2)
return false;

if (captured_params.at("output_padding").type != 5)
return false;

if (captured_params.at("output_padding").ai.size() != 2)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 4 || pads[0] != pads[2] || pads[1] != pads[3])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0], pads[1]};
op->params["output_padding"] = captured_params.at("output_padding");
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose2d_onnx_2, 10)

class F_conv_transpose2d_onnx_3 : public F_conv_transpose2d_onnx_2
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
ConvTranspose op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group output_padding=%output_padding
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv_transpose2d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose2d_onnx_3, 10)

} // namespace pnnx

+ 276
- 0
tools/pnnx/src/pass_level2/F_conv_transpose3d.cpp View File

@@ -0,0 +1,276 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2024 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 "pass_level2.h"

namespace pnnx {

class F_conv_transpose3d_onnx : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose3d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 3)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 3)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 3)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 6 || pads[0] != pads[3] || pads[1] != pads[4] || pads[2] != pads[5])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0], pads[1], pads[2]};
op->params["output_padding"] = {0, 0, 0};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose3d_onnx, 10)

class F_conv_transpose3d_onnx_0 : public F_conv_transpose3d_onnx
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
ConvTranspose op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv_transpose3d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose3d_onnx_0, 10)

class F_conv_transpose3d_onnx_1 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out strides=%strides pads=%pads dilations=%dilations group=%group auto_pad=NOTSET
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose3d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 3)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 3)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 6 || pads[0] != pads[3] || pads[1] != pads[4] || pads[2] != pads[5])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0], pads[1], pads[2]};
op->params["output_padding"] = {0, 0, 0};
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose3d_onnx_1, 10)

class F_conv_transpose3d_onnx_2 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
5 4
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
pnnx.Input input_2 0 1 bias
ConvTranspose op_0 3 1 input weight bias out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group output_padding=%output_padding
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "F.conv_transpose3d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
{
if (captured_params.at("kernel_shape").type != 5)
return false;

if (captured_params.at("kernel_shape").ai.size() != 3)
return false;

if (captured_params.at("strides").type != 5)
return false;

if (captured_params.at("strides").ai.size() != 3)
return false;

if (captured_params.at("dilations").type != 5)
return false;

if (captured_params.at("dilations").ai.size() != 3)
return false;

if (captured_params.at("output_padding").type != 5)
return false;

if (captured_params.at("output_padding").ai.size() != 3)
return false;

if (captured_params.at("group").type != 2)
return false;

if (captured_params.at("pads").type != 5)
return false;

const std::vector<int>& pads = captured_params.at("pads").ai;
if (pads.size() != 6 || pads[0] != pads[3] || pads[1] != pads[4] || pads[2] != pads[5])
return false;

return true;
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::vector<int>& pads = captured_params.at("pads").ai;

op->params["stride"] = captured_params.at("strides");
op->params["dilation"] = captured_params.at("dilations");
op->params["groups"] = captured_params.at("group");
op->params["padding"] = {pads[0], pads[1], pads[2]};
op->params["output_padding"] = captured_params.at("output_padding");
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose3d_onnx_2, 10)

class F_conv_transpose3d_onnx_3 : public F_conv_transpose3d_onnx_2
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
ConvTranspose op_0 2 1 input weight out kernel_shape=%kernel_shape strides=%strides pads=%pads dilations=%dilations group=%group output_padding=%output_padding
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* replace_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 weight
F.conv_transpose3d conv 2 1 input weight out bias=None
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_conv_transpose3d_onnx_3, 10)

} // namespace pnnx

+ 78
- 4
tools/pnnx/src/pass_level2/F_pad.cpp View File

@@ -265,10 +265,9 @@ public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
4 3
pnnx.Input input_0 0 1 input
pnnx.Input input_1 0 1 pad
Pad op_0 2 1 input pad out mode=constant
3 2
pnnx.Input input 0 1 input
Pad op_0 1 1 input out mode=%mode pads=%pads
pnnx.Output output 1 0 out
)PNNXIR";
}
@@ -277,8 +276,83 @@ pnnx.Output output 1 0 out
{
return "F.pad";
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
const std::string& mode = captured_params.at("mode").s;
if (mode == "constant") op->params["mode"] = "constant";
if (mode == "reflect") op->params["mode"] = "reflect";
if (mode == "edge") op->params["mode"] = "replicate";
if (mode == "wrap") op->params["mode"] = "circular";

const std::vector<int>& pads = captured_params.at("pads").ai;

if (pads.size() == 2)
op->params["pad"] = pads;

if (pads.size() == 4)
{
if (pads[0] == 0 && pads[2] == 0)
op->params["pad"] = std::vector<int>{pads[1], pads[3]};
else
op->params["pad"] = std::vector<int>{pads[1], pads[3], pads[0], pads[2]};
}

if (pads.size() == 6)
{
if (pads[1] == 0 && pads[4] == 0 && pads[0] == 0 && pads[3] == 0)
op->params["pad"] = std::vector<int>{pads[2], pads[5]};
else if (pads[0] == 0 && pads[3] == 0)
op->params["pad"] = std::vector<int>{pads[2], pads[5], pads[1], pads[4]};
else
op->params["pad"] = std::vector<int>{pads[2], pads[5], pads[1], pads[4], pads[0], pads[3]};
}

if (pads.size() == 8)
{
if (pads[1] == 0 && pads[5] == 0 && pads[0] == 0 && pads[4] == 0)
op->params["pad"] = std::vector<int>{pads[3], pads[7], pads[2], pads[6]};
else if (pads[0] == 0 && pads[4] == 0)
op->params["pad"] = std::vector<int>{pads[3], pads[7], pads[2], pads[6], pads[1], pads[5]};
else
op->params["pad"] = std::vector<int>{pads[3], pads[7], pads[2], pads[6], pads[1], pads[5], pads[0], pads[4]};
}

if (pads.size() == 10)
{
if (pads[1] == 0 && pads[6] == 0 && pads[0] == 0 && pads[5] == 0)
op->params["pad"] = std::vector<int>{pads[4], pads[9], pads[3], pads[8], pads[2], pads[7]};
else if (pads[0] == 0 && pads[5] == 0)
op->params["pad"] = std::vector<int>{pads[4], pads[9], pads[3], pads[8], pads[2], pads[7], pads[1], pads[6]};
else
op->params["pad"] = std::vector<int>{pads[4], pads[9], pads[3], pads[8], pads[2], pads[7], pads[1], pads[6], pads[0], pads[5]};
}
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_pad_onnx, 10)

class F_pad_onnx_1 : public F_pad_onnx
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
3 2
pnnx.Input input 0 1 input
Pad op_0 1 1 input out mode=%mode pads=%pads value=%value
pnnx.Output output 1 0 out
)PNNXIR";
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
F_pad_onnx::write(op, captured_params);

op->params["value"] = captured_params.at("value");
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(F_pad_onnx_1, 10)

} // namespace pnnx

+ 37
- 0
tools/pnnx/src/pass_level2/Tensor_reshape.cpp View File

@@ -113,4 +113,41 @@ pnnx.Output output 1 0 out

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(Tensor_reshape_onnx_3, 20)

class Tensor_reshape_onnx_4 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
3 2
pnnx.Input input 0 1 input
Reshape op_1 1 1 input out shape=%shape allowzero=*
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "Tensor.reshape";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(Tensor_reshape_onnx_4, 20)

class Tensor_reshape_onnx_5 : public Tensor_reshape_onnx_4
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
3 2
pnnx.Input input 0 1 input
Reshape op_1 1 1 input out shape=%shape
pnnx.Output output 1 0 out
)PNNXIR";
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(Tensor_reshape_onnx_5, 20)

} // namespace pnnx

+ 27
- 0
tools/pnnx/src/pass_level2/torch_mean.cpp View File

@@ -180,4 +180,31 @@ pnnx.Output output 1 0 out

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(torch_mean_onnx_2, 20)

class torch_mean_onnx_3 : public GraphRewriterPass
{
public:
const char* match_pattern_graph() const
{
return R"PNNXIR(7767517
3 2
pnnx.Input input 0 1 input
ReduceMean op_0 1 1 input out axes=%axes keepdims=%keepdims noop_with_empty_axes=0
pnnx.Output output 1 0 out
)PNNXIR";
}

const char* type_str() const
{
return "torch.mean";
}

void write(Operator* op, const std::map<std::string, Parameter>& captured_params) const
{
op->params["dim"] = captured_params.at("axes");
op->params["keepdim"] = captured_params.at("keepdims").i ? true : false;
}
};

REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(torch_mean_onnx_3, 20)

} // namespace pnnx

+ 6
- 6
tools/pnnx/src/pass_level5/fuse_pad_conv2d.cpp View File

@@ -42,7 +42,7 @@ pnnx.Output output 1 0 out

const char* name_str() const
{
return "conv2d";
return "padconv2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
@@ -131,7 +131,7 @@ pnnx.Output output 1 0 out

const char* name_str() const
{
return "conv2d";
return "padconv2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
@@ -215,7 +215,7 @@ pnnx.Output output 1 0 out

const char* name_str() const
{
return "conv2d";
return "padconv2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
@@ -293,7 +293,7 @@ pnnx.Output output 1 0 out

const char* name_str() const
{
return "conv2d";
return "padconv2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
@@ -362,7 +362,7 @@ pnnx.Output output 1 0 out

const char* name_str() const
{
return "conv2d";
return "padconv2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const
@@ -431,7 +431,7 @@ pnnx.Output output 1 0 out

const char* name_str() const
{
return "conv2d";
return "padconv2d";
}

bool match(const std::map<std::string, Parameter>& captured_params) const


+ 0
- 9
tools/pnnx/src/pass_onnx.cpp View File

@@ -797,15 +797,6 @@ void pass_onnx(const onnx::ModelProto& model, Graph& pnnx_graph)
{
if (is_aten_op)
is_attr_list = true;

if (sim_op_type == "Reshape" && j == 1)
is_attr_list = true;

if (sim_op_type == "Pad" && j == 1)
is_attr_list = true;

if (sim_op_type == "ReduceMean" && j == 1)
is_attr_list = true;
}

bool is_attr_weight = false;


+ 271
- 0
tools/pnnx/src/pass_onnx/fuse_constant_as_attribute.cpp View File

@@ -0,0 +1,271 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2024 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 "fuse_constant_as_attribute.h"

#include <sstream>
#include <string>
#include <unordered_set>

#include <onnxruntime_c_api.h>

namespace pnnx {

namespace onnx2pnnx {

struct constant_as_attribute
{
const char* op_type;
int input_index;
const char* attribute;
};

static constant_as_attribute caas[] = {
{"Pad", 1, "pads"},
{"Pad", 2, "value"},
{"ReduceMean", 1, "axes"},
{"Reshape", 1, "shape"},
};

static const char* get_constant_as_attribute(const std::string& op_type, int input_index)
{
const int caas_count = sizeof(caas) / sizeof(caas[0]);
for (int i = 0; i < caas_count; i++)
{
if (op_type == caas[i].op_type && input_index == caas[i].input_index)
return caas[i].attribute;
}

return NULL;
}

void fuse_constant_as_attribute(onnx::ModelProto& model)
{
// collect initializers
std::unordered_map<std::string, int> initializers;
{
const onnx::GraphProto& graph = model.graph();
for (int i = 0; i < graph.initializer_size(); i++)
{
initializers.insert(std::make_pair(graph.initializer(i).name(), i));
}
}

onnx::GraphProto* graph = model.mutable_graph();

for (int i = 0; i < graph->node_size(); i++)
{
onnx::NodeProto* node = graph->mutable_node(i);
if (!node->domain().empty())
{
// native onnx op
continue;
}

const std::string& op_type = node->op_type();

std::vector<int> fused_input_indexes;
for (int j = 0; j < node->input_size(); j++)
{
const std::string& input = node->input(j);
if (input.empty())
continue;

if (initializers.find(input) == initializers.end())
continue;

const char* attr_name = get_constant_as_attribute(op_type, j);
if (!attr_name)
continue;

// fprintf(stderr, "fuse_constant_as_attribute %s %d -> %s\n", op_type.c_str(), j, attr_name);

const onnx::TensorProto& tensor = graph->initializer(initializers.at(input));

int64_t numel = 1;
for (int k = 0; k < tensor.dims_size(); k++)
{
numel *= tensor.dims(k);
}

if (numel == 1)
{
// int or float scalar
if (tensor.data_type() == onnx::TensorProto::INT32)
{
int i32;
if (tensor.has_raw_data())
{
// assert tensor.raw_data().size() == 4
i32 = ((int*)tensor.raw_data().data())[0];
}
else
{
// assert tensor.int32_data().size() == 1
i32 = tensor.int32_data().at(0);
}

onnx::AttributeProto* attr = node->add_attribute();
attr->set_name(std::string(attr_name));
attr->set_type(onnx::AttributeProto::INT);
attr->set_i(i32);
}
else if (tensor.data_type() == onnx::TensorProto::INT64)
{
int64_t i64;
if (tensor.has_raw_data())
{
// assert tensor.raw_data().size() == 8
i64 = ((int64_t*)tensor.raw_data().data())[0];
}
else
{
// assert tensor.int64_data().size() == 1
i64 = tensor.int64_data().at(0);
}

if (i64 == std::numeric_limits<int64_t>::max()) i64 = INT_MAX;
if (i64 == std::numeric_limits<int64_t>::min()) i64 = INT_MIN;

onnx::AttributeProto* attr = node->add_attribute();
attr->set_name(std::string(attr_name));
attr->set_type(onnx::AttributeProto::INT);
attr->set_i((int)i64);
}
else if (tensor.data_type() == onnx::TensorProto::FLOAT)
{
float f32;
if (tensor.has_raw_data())
{
// assert tensor.raw_data().size() == 4
f32 = ((float*)tensor.raw_data().data())[0];
}
else
{
// assert tensor.float_data().size() == 1
f32 = tensor.float_data().at(0);
}

onnx::AttributeProto* attr = node->add_attribute();
attr->set_name(std::string(attr_name));
attr->set_type(onnx::AttributeProto::FLOAT);
attr->set_f(f32);
}
else if (tensor.data_type() == onnx::TensorProto::BOOL)
{
bool bb;
if (tensor.has_raw_data())
{
// assert tensor.raw_data().size() == 2
bb = ((uint16_t*)tensor.raw_data().data())[0] ? true : false;
}
else
{
// assert tensor.int32_data().size() == 1
bb = tensor.int32_data().at(0) ? true : false;
}

onnx::AttributeProto* attr = node->add_attribute();
attr->set_name(std::string(attr_name));
attr->set_type(onnx::AttributeProto::INT);
attr->set_i(bb ? 1 : 0);
}
else
{
fprintf(stderr, "unknown constant scalar type %d\n", (int)tensor.data_type());
continue;
}
}
else if (tensor.dims_size() == 1)
{
// int list
const int list_size = tensor.dims(0);
if (tensor.data_type() == onnx::TensorProto::INT32)
{
std::vector<int> ai(list_size);
if (tensor.has_raw_data())
{
// assert tensor.raw_data().size() == 4 * list_size
memcpy((void*)ai.data(), (int*)tensor.raw_data().data(), sizeof(int) * list_size);
}
else
{
// assert tensor.int32_data().size() == list_size
memcpy((void*)ai.data(), tensor.int32_data().data(), sizeof(int) * list_size);
}

onnx::AttributeProto* attr = node->add_attribute();
attr->set_name(std::string(attr_name));
attr->set_type(onnx::AttributeProto::INTS);
for (auto i32 : ai)
{
attr->add_ints(i32);
}
}
else if (tensor.data_type() == onnx::TensorProto::INT64)
{
std::vector<int64_t> ai(list_size);
if (tensor.has_raw_data())
{
// assert tensor.raw_data().size() == 8 * list_size
memcpy((void*)ai.data(), (int64_t*)tensor.raw_data().data(), sizeof(int64_t) * list_size);
}
else
{
// assert tensor.int64_data().size() == list_size
memcpy((void*)ai.data(), tensor.int64_data().data(), sizeof(int64_t) * list_size);
}

onnx::AttributeProto* attr = node->add_attribute();
attr->set_name(std::string(attr_name));
attr->set_type(onnx::AttributeProto::INTS);
for (auto i64 : ai)
{
if (i64 == std::numeric_limits<int64_t>::max()) i64 = INT_MAX;
if (i64 == std::numeric_limits<int64_t>::min()) i64 = INT_MIN;

attr->add_ints((int)i64);
}
}
else
{
fprintf(stderr, "unknown constant list type %d\n", (int)tensor.data_type());
continue;
}
}

fused_input_indexes.push_back(j);
}

// drop inputs
for (size_t j = 0; j < fused_input_indexes.size(); j++)
{
const int fused_input_index = fused_input_indexes[j];

// ..... fii .......
const int node_input_size = node->input_size();
for (int k = fused_input_index; k < node_input_size - 1; k++)
{
node->mutable_input()->SwapElements(k, k + 1);
}

// ..... ....... fii
node->mutable_input()->RemoveLast();
}
}
}

} // namespace onnx2pnnx

} // namespace pnnx

+ 25
- 0
tools/pnnx/src/pass_onnx/fuse_constant_as_attribute.h View File

@@ -0,0 +1,25 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2024 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 "onnx.pb.h"

namespace pnnx {

namespace onnx2pnnx {

void fuse_constant_as_attribute(onnx::ModelProto& model);

} // namespace onnx2pnnx

} // namespace pnnx

+ 15
- 0
tools/pnnx/tests/onnx/CMakeLists.txt View File

@@ -5,8 +5,23 @@ macro(pnnx_onnx_add_test name)
add_test(NAME test_onnx_${name} COMMAND ${CMAKE_COMMAND} -DPYTHON_EXECUTABLE=${Python3_EXECUTABLE} -DPYTHON_SCRIPT=${CMAKE_CURRENT_SOURCE_DIR}/test_${name}.py -P ${CMAKE_CURRENT_SOURCE_DIR}/../run_test.cmake)
endmacro()

pnnx_onnx_add_test(F_conv_transpose1d)
pnnx_onnx_add_test(F_conv_transpose2d)
pnnx_onnx_add_test(F_conv_transpose3d)
pnnx_onnx_add_test(F_conv1d)
pnnx_onnx_add_test(F_conv2d)
pnnx_onnx_add_test(F_conv3d)
pnnx_onnx_add_test(F_pad)
pnnx_onnx_add_test(F_relu)

pnnx_onnx_add_test(nn_Conv1d)
pnnx_onnx_add_test(nn_Conv2d)
pnnx_onnx_add_test(nn_Conv3d)
pnnx_onnx_add_test(nn_ConvTranspose1d)
pnnx_onnx_add_test(nn_ConvTranspose2d)
pnnx_onnx_add_test(nn_ConvTranspose3d)
# pnnx_onnx_add_test(nn_ReLU)

pnnx_onnx_add_test(convnext_tiny)
pnnx_onnx_add_test(mobilenet_v2)
pnnx_onnx_add_test(mobilenet_v3_small)


+ 66
- 0
tools/pnnx/tests/onnx/test_F_conv1d.py View File

@@ -0,0 +1,66 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F
from packaging import version

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.w2 = nn.Parameter(torch.rand(12, 6, 4))
self.b2 = nn.Parameter(torch.rand(12))
self.w3 = nn.Parameter(torch.rand(6, 4, 3))

def forward(self, x, w0, w1, b1, y):
x = F.conv1d(x, w0, None, stride=2, padding=1)
x = F.conv1d(x, w1, b1, stride=1, padding=1, dilation=2, groups=2)
# x = F.conv1d(x, w1, b1, stride=1, padding='same', dilation=2, groups=2)
y = F.conv1d(y, self.w2, self.b2, stride=2, padding=2)
y = F.conv1d(y, self.w3, None, stride=2, padding=1, groups=3)
return x, y

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 52)
w0 = torch.rand(16, 12, 3)
w1 = torch.rand(16, 8, 5)
b1 = torch.rand(16)
y = torch.rand(1, 6, 25)

a0, a1 = net(x, w0, w1, b1, y)

# export onnx
torch.onnx.export(net, (x, w0, w1, b1, y), "test_F_conv1d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_conv1d.onnx inputshape=[1,12,52],[16,12,3],[16,8,5],[16],[1,6,25]")

# pnnx inference
import test_F_conv1d_pnnx
b0, b1 = test_F_conv1d_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 66
- 0
tools/pnnx/tests/onnx/test_F_conv2d.py View File

@@ -0,0 +1,66 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F
from packaging import version

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.w2 = nn.Parameter(torch.rand(12, 6, 4, 4))
self.b2 = nn.Parameter(torch.rand(12))
self.w3 = nn.Parameter(torch.rand(6, 4, 3, 3))

def forward(self, x, w0, w1, b1, y):
x = F.conv2d(x, w0, None, stride=(2,2), padding=(1,1))
x = F.conv2d(x, w1, b1, stride=(1,1), padding=(1,1), dilation=(2,1), groups=2)
# x = F.conv2d(x, w1, b1, stride=(1,1), padding='same', dilation=(2,1), groups=2)
y = F.conv2d(y, self.w2, self.b2, stride=(2,2), padding=(2,2))
y = F.conv2d(y, self.w3, None, stride=(2,2), padding=(1,1), groups=3)
return x, y

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 52, 64)
w0 = torch.rand(16, 12, 3, 3)
w1 = torch.rand(16, 8, 5, 5)
b1 = torch.rand(16)
y = torch.rand(1, 6, 32, 25)

a0, a1 = net(x, w0, w1, b1, y)

# export onnx
torch.onnx.export(net, (x, w0, w1, b1, y), "test_F_conv2d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_conv2d.onnx inputshape=[1,12,52,64],[16,12,3,3],[16,8,5,5],[16],[1,6,32,25]")

# pnnx inference
import test_F_conv2d_pnnx
b0, b1 = test_F_conv2d_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 66
- 0
tools/pnnx/tests/onnx/test_F_conv3d.py View File

@@ -0,0 +1,66 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F
from packaging import version

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.w2 = nn.Parameter(torch.rand(12, 6, 4, 4, 4))
self.b2 = nn.Parameter(torch.rand(12))
self.w3 = nn.Parameter(torch.rand(6, 4, 3, 3, 3))

def forward(self, x, w0, w1, b1, y):
x = F.conv3d(x, w0, None, stride=(2,2,2), padding=(1,0,1))
x = F.conv3d(x, w1, b1, stride=(1,1,1), padding=(1,1,1), dilation=(2,2,1), groups=2)
# x = F.conv3d(x, w1, b1, stride=(1,1,1), padding='same', dilation=(2,2,1), groups=2)
y = F.conv3d(y, self.w2, self.b2, stride=(2,2,2), padding=(2,2,2))
y = F.conv3d(y, self.w3, None, stride=(2,2,2), padding=(1,1,1), groups=3)
return x, y

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 20, 32, 40)
w0 = torch.rand(16, 12, 3, 2, 3)
w1 = torch.rand(16, 8, 5, 4, 5)
b1 = torch.rand(16)
y = torch.rand(1, 6, 12, 11, 10)

a0, a1 = net(x, w0, w1, b1, y)

# export onnx
torch.onnx.export(net, (x, w0, w1, b1, y), "test_F_conv3d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_conv3d.onnx inputshape=[1,12,20,32,40],[16,12,3,2,3],[16,8,5,4,5],[16],[1,6,12,11,10]")

# pnnx inference
import test_F_conv3d_pnnx
b0, b1 = test_F_conv3d_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 65
- 0
tools/pnnx/tests/onnx/test_F_conv_transpose1d.py View File

@@ -0,0 +1,65 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.w2 = nn.Parameter(torch.rand(6, 12, 4))
self.b2 = nn.Parameter(torch.rand(12))
self.w3 = nn.Parameter(torch.rand(12, 2, 3))

def forward(self, x, w0, w1, b1, y):
x = F.conv_transpose1d(x, w0, None, stride=2, padding=1, output_padding=1)
x = F.conv_transpose1d(x, w1, b1, stride=1, padding=2, dilation=2, groups=2)

y = F.conv_transpose1d(y, self.w2, self.b2, stride=2, padding=1, output_padding=1)
y = F.conv_transpose1d(y, self.w3, None, stride=1, padding=2, dilation=2, groups=3)
return x, y

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 22)
w0 = torch.rand(12, 16, 3)
w1 = torch.rand(16, 8, 5)
b1 = torch.rand(16)
y = torch.rand(1, 6, 5)

a0, a1 = net(x, w0, w1, b1, y)

# export onnx
torch.onnx.export(net, (x, w0, w1, b1, y), "test_F_conv_transpose1d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_conv_transpose1d.onnx inputshape=[1,12,22],[12,16,3],[16,8,5],[16],[1,6,5]")

# pnnx inference
import test_F_conv_transpose1d_pnnx
b0, b1 = test_F_conv_transpose1d_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 65
- 0
tools/pnnx/tests/onnx/test_F_conv_transpose2d.py View File

@@ -0,0 +1,65 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.w2 = nn.Parameter(torch.rand(6, 12, 4, 4))
self.b2 = nn.Parameter(torch.rand(12))
self.w3 = nn.Parameter(torch.rand(12, 2, 3, 3))

def forward(self, x, w0, w1, b1, y):
x = F.conv_transpose2d(x, w0, None, stride=(2,2), padding=(1,1), output_padding=(1,1))
x = F.conv_transpose2d(x, w1, b1, stride=(1,2), padding=(2,1), dilation=(2,1), groups=2)

y = F.conv_transpose2d(y, self.w2, self.b2, stride=(2,2), padding=(1,1), output_padding=(1,1))
y = F.conv_transpose2d(y, self.w3, None, stride=(1,2), padding=(2,1), dilation=(2,1), groups=3)
return x, y

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 22, 32)
w0 = torch.rand(12, 16, 3, 3)
w1 = torch.rand(16, 8, 5, 5)
b1 = torch.rand(16)
y = torch.rand(1, 6, 5, 6)

a0, a1 = net(x, w0, w1, b1, y)

# export onnx
torch.onnx.export(net, (x, w0, w1, b1, y), "test_F_conv_transpose2d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_conv_transpose2d.onnx inputshape=[1,12,22,32],[12,16,3,3],[16,8,5,5],[16],[1,6,5,6]")

# pnnx inference
import test_F_conv_transpose2d_pnnx
b0, b1 = test_F_conv_transpose2d_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 65
- 0
tools/pnnx/tests/onnx/test_F_conv_transpose3d.py View File

@@ -0,0 +1,65 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.w2 = nn.Parameter(torch.rand(6, 12, 4, 4, 4))
self.b2 = nn.Parameter(torch.rand(12))
self.w3 = nn.Parameter(torch.rand(12, 2, 3, 3, 3))

def forward(self, x, w0, w1, b1, y):
x = F.conv_transpose3d(x, w0, None, stride=(2,2,2), padding=(1,0,1), output_padding=(1,1,0))
x = F.conv_transpose3d(x, w1, b1, stride=(1,1,2), padding=(2,2,1), dilation=(2,2,1), groups=2)

y = F.conv_transpose3d(y, self.w2, self.b2, stride=(2,2,2), padding=(1,0,1), output_padding=(1,1,0))
y = F.conv_transpose3d(y, self.w3, None, stride=(1,1,2), padding=(2,2,1), dilation=(2,2,1), groups=3)
return x, y

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 10, 12, 14)
w0 = torch.rand(12, 16, 3, 2, 3)
w1 = torch.rand(16, 8, 5, 4, 5)
b1 = torch.rand(16)
y = torch.rand(1, 6, 4, 5, 6)

a0, a1 = net(x, w0, w1, b1, y)

# export onnx
torch.onnx.export(net, (x, w0, w1, b1, y), "test_F_conv_transpose3d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_conv_transpose3d.onnx inputshape=[1,12,10,12,14],[12,16,3,2,3],[16,8,5,4,5],[16],[1,6,4,5,6]")

# pnnx inference
import test_F_conv_transpose3d_pnnx
b0, b1 = test_F_conv_transpose3d_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 73
- 0
tools/pnnx/tests/onnx/test_F_pad.py View File

@@ -0,0 +1,73 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

def forward(self, x, y, z, w):
x = F.pad(x, (3,4), mode='constant', value=1.3)
x = F.pad(x, (2,2))

y = F.pad(y, (5,6), mode='reflect')
y = F.pad(y, (2,1), mode='replicate')
y = F.pad(y, (3,4), mode='constant', value=1.3)
y = F.pad(y, (1,1))

z = F.pad(z, (3,4,3,4), mode='reflect')
z = F.pad(z, (2,1,2,0), mode='replicate')
z = F.pad(z, (1,0,2,0), mode='constant', value=1.3)
z = F.pad(z, (3,3,3,3))

#w = F.pad(w, (1,2,3,4,5,6), mode='reflect')
w = F.pad(w, (5,0,1,2,0,2), mode='replicate')
w = F.pad(w, (0,2,2,1,3,4), mode='constant', value=1.3)
w = F.pad(w, (2,2,2,2,2,2))

return x, y, z, w

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 16)
y = torch.rand(12, 2, 16)
z = torch.rand(1, 3, 12, 16)
w = torch.rand(1, 5, 7, 9, 11)

a0, a1, a2, a3 = net(x, y, z, w)

# export onnx
torch.onnx.export(net, (x, y, z, w), "test_F_pad.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_F_pad.onnx inputshape=[1,16],[12,2,16],[1,3,12,16],[1,5,7,9,11]")

# pnnx inference
import test_F_pad_pnnx
b0, b1, b2, b3 = test_F_pad_pnnx.test_inference()

return torch.equal(a0, b0) and torch.equal(a1, b1) and torch.equal(a2, b2) and torch.equal(a3, b3)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 73
- 0
tools/pnnx/tests/onnx/test_nn_Conv1d.py View File

@@ -0,0 +1,73 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F
from packaging import version

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.conv_0 = nn.Conv1d(in_channels=12, out_channels=16, kernel_size=3)
self.conv_1 = nn.Conv1d(in_channels=16, out_channels=20, kernel_size=2, stride=2, padding=2, dilation=1)
self.conv_2 = nn.Conv1d(in_channels=20, out_channels=24, kernel_size=3, stride=1, padding=(4), dilation=1, groups=1, bias=False)
self.conv_3 = nn.Conv1d(in_channels=24, out_channels=28, kernel_size=5, stride=1, padding=0, dilation=1, groups=4, bias=True)
self.conv_4 = nn.Conv1d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, dilation=2, groups=2, bias=False, padding_mode='zeros')
# self.conv_3 = nn.Conv1d(in_channels=24, out_channels=28, kernel_size=5, stride=1, padding='valid', dilation=1, groups=4, bias=True)
# self.conv_4 = nn.Conv1d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding='same', dilation=2, groups=2, bias=False, padding_mode='zeros')
self.conv_5 = nn.Conv1d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, dilation=1, groups=32, bias=True, padding_mode='reflect')
self.conv_6 = nn.Conv1d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, dilation=1, groups=1, bias=False, padding_mode='replicate')
#self.conv_7 = nn.Conv1d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(5,6), dilation=2, groups=1, bias=True, padding_mode='circular')

def forward(self, x):
x = self.conv_0(x)
x = self.conv_1(x)
x = self.conv_2(x)
x = self.conv_3(x)
x = self.conv_4(x)
x = self.conv_5(x)
x = self.conv_6(x)
#x = self.conv_7(x)

return x

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 64)

a = net(x)

# export onnx
torch.onnx.export(net, (x, ), "test_nn_Conv1d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_nn_Conv1d.onnx inputshape=[1,12,64]")

# pnnx inference
import test_nn_Conv1d_pnnx
b = test_nn_Conv1d_pnnx.test_inference()

return torch.equal(a, b)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 73
- 0
tools/pnnx/tests/onnx/test_nn_Conv2d.py View File

@@ -0,0 +1,73 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F
from packaging import version

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.conv_0 = nn.Conv2d(in_channels=12, out_channels=16, kernel_size=3)
self.conv_1 = nn.Conv2d(in_channels=16, out_channels=20, kernel_size=(2,4), stride=(2,1), padding=2, dilation=1)
self.conv_2 = nn.Conv2d(in_channels=20, out_channels=24, kernel_size=(1,3), stride=1, padding=(2,4), dilation=1, groups=1, bias=False)
self.conv_3 = nn.Conv2d(in_channels=24, out_channels=28, kernel_size=(5,4), stride=1, padding=0, dilation=1, groups=4, bias=True)
self.conv_4 = nn.Conv2d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, dilation=(1,2), groups=2, bias=False, padding_mode='zeros')
# self.conv_3 = nn.Conv2d(in_channels=24, out_channels=28, kernel_size=(5,4), stride=1, padding='valid', dilation=1, groups=4, bias=True)
# self.conv_4 = nn.Conv2d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding='same', dilation=(1,2), groups=2, bias=False, padding_mode='zeros')
self.conv_5 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, dilation=1, groups=32, bias=True, padding_mode='reflect')
self.conv_6 = nn.Conv2d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, dilation=1, groups=1, bias=False, padding_mode='replicate')
#self.conv_7 = nn.Conv2d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(5,6), dilation=2, groups=1, bias=True, padding_mode='circular')

def forward(self, x):
x = self.conv_0(x)
x = self.conv_1(x)
x = self.conv_2(x)
x = self.conv_3(x)
x = self.conv_4(x)
x = self.conv_5(x)
x = self.conv_6(x)
#x = self.conv_7(x)

return x

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 64, 64)

a = net(x)

# export onnx
torch.onnx.export(net, (x, ), "test_nn_Conv2d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_nn_Conv2d.onnx inputshape=[1,12,64,64]")

# pnnx inference
import test_nn_Conv2d_pnnx
b = test_nn_Conv2d_pnnx.test_inference()

return torch.equal(a, b)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 77
- 0
tools/pnnx/tests/onnx/test_nn_Conv3d.py View File

@@ -0,0 +1,77 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F
from packaging import version

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.conv_0 = nn.Conv3d(in_channels=12, out_channels=16, kernel_size=3)
self.conv_1 = nn.Conv3d(in_channels=16, out_channels=20, kernel_size=(2,3,4), stride=(2,2,1), padding=2, dilation=1)
self.conv_2 = nn.Conv3d(in_channels=20, out_channels=24, kernel_size=(1,2,3), stride=1, padding=(2,4,1), dilation=1, groups=1, bias=False)
self.conv_3 = nn.Conv3d(in_channels=24, out_channels=28, kernel_size=(5,4,3), stride=1, padding=0, dilation=1, groups=4, bias=True)
self.conv_4 = nn.Conv3d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, dilation=(1,2,2), groups=2, bias=False, padding_mode='zeros')
# self.conv_3 = nn.Conv3d(in_channels=24, out_channels=28, kernel_size=(5,4,3), stride=1, padding='valid', dilation=1, groups=4, bias=True)
# self.conv_4 = nn.Conv3d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding='same', dilation=(1,2,2), groups=2, bias=False, padding_mode='zeros')
if version.parse(torch.__version__) >= version.parse('1.10'):
self.conv_5 = nn.Conv3d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, dilation=1, groups=32, bias=True, padding_mode='reflect')
self.conv_6 = nn.Conv3d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, dilation=1, groups=1, bias=False, padding_mode='replicate')
# self.conv_7 = nn.Conv3d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(5,6), dilation=2, groups=1, bias=True, padding_mode='circular')

def forward(self, x):
x = self.conv_0(x)
x = self.conv_1(x)
x = self.conv_2(x)
x = self.conv_3(x)
x = self.conv_4(x)
if version.parse(torch.__version__) < version.parse('1.10'):
return x

x = self.conv_5(x)
x = self.conv_6(x)
#x = self.conv_7(x)

return x

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 48, 48, 64)

a = net(x)

# export onnx
torch.onnx.export(net, (x, ), "test_nn_Conv3d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_nn_Conv3d.onnx inputshape=[1,12,48,48,64]")

# pnnx inference
import test_nn_Conv3d_pnnx
b = test_nn_Conv3d_pnnx.test_inference()

return torch.equal(a, b)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 76
- 0
tools/pnnx/tests/onnx/test_nn_ConvTranspose1d.py View File

@@ -0,0 +1,76 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.deconv_0 = nn.ConvTranspose1d(in_channels=12, out_channels=16, kernel_size=3)
self.deconv_1 = nn.ConvTranspose1d(in_channels=16, out_channels=20, kernel_size=2, stride=2, padding=2, output_padding=0)
self.deconv_2 = nn.ConvTranspose1d(in_channels=20, out_channels=24, kernel_size=3, stride=1, padding=(2), output_padding=(0), dilation=1, groups=1, bias=False)
self.deconv_3 = nn.ConvTranspose1d(in_channels=24, out_channels=28, kernel_size=5, stride=2, padding=0, output_padding=(1), dilation=1, groups=4, bias=True)
self.deconv_4 = nn.ConvTranspose1d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, output_padding=0, dilation=2, groups=2, bias=False)
self.deconv_5 = nn.ConvTranspose1d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, output_padding=1, dilation=1, groups=32, bias=True)
self.deconv_6 = nn.ConvTranspose1d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, output_padding=0, dilation=1, groups=1, bias=False)
self.deconv_7 = nn.ConvTranspose1d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(6), output_padding=(1), dilation=2, groups=1, bias=True)

self.downsample = nn.Conv1d(24, 16, 3, stride=2, padding=1)
self.upsample = nn.ConvTranspose1d(16, 24, 3, stride=2, padding=1)

def forward(self, x):
x = self.deconv_0(x)
x = self.deconv_1(x)
x = self.deconv_2(x)
x = self.deconv_3(x)
x = self.deconv_4(x)
x = self.deconv_5(x)
x = self.deconv_6(x)
x = self.deconv_7(x)

y = self.downsample(x)
x = self.upsample(y, output_size=x.size())

return x

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 10)

a = net(x)

# export onnx
torch.onnx.export(net, (x, ), "test_nn_ConvTranspose1d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_nn_ConvTranspose1d.onnx inputshape=[1,12,10]")

# pnnx inference
import test_nn_ConvTranspose1d_pnnx
b = test_nn_ConvTranspose1d_pnnx.test_inference()

return torch.equal(a, b)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 76
- 0
tools/pnnx/tests/onnx/test_nn_ConvTranspose2d.py View File

@@ -0,0 +1,76 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.deconv_0 = nn.ConvTranspose2d(in_channels=12, out_channels=16, kernel_size=3)
self.deconv_1 = nn.ConvTranspose2d(in_channels=16, out_channels=20, kernel_size=(2,4), stride=(2,1), padding=2, output_padding=0)
self.deconv_2 = nn.ConvTranspose2d(in_channels=20, out_channels=24, kernel_size=(1,3), stride=1, padding=(2,4), output_padding=(0,0), dilation=1, groups=1, bias=False)
self.deconv_3 = nn.ConvTranspose2d(in_channels=24, out_channels=28, kernel_size=(5,4), stride=2, padding=0, output_padding=(0,1), dilation=1, groups=4, bias=True)
self.deconv_4 = nn.ConvTranspose2d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, output_padding=0, dilation=(1,2), groups=2, bias=False)
self.deconv_5 = nn.ConvTranspose2d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, output_padding=1, dilation=1, groups=32, bias=True)
self.deconv_6 = nn.ConvTranspose2d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, output_padding=0, dilation=1, groups=1, bias=False)
self.deconv_7 = nn.ConvTranspose2d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(5,6), output_padding=(1,0), dilation=2, groups=1, bias=True)

self.downsample = nn.Conv2d(24, 16, 3, stride=2, padding=1)
self.upsample = nn.ConvTranspose2d(16, 24, 3, stride=2, padding=1)

def forward(self, x):
x = self.deconv_0(x)
x = self.deconv_1(x)
x = self.deconv_2(x)
x = self.deconv_3(x)
x = self.deconv_4(x)
x = self.deconv_5(x)
x = self.deconv_6(x)
x = self.deconv_7(x)

y = self.downsample(x)
x = self.upsample(y, output_size=x.size())

return x

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 10, 10)

a = net(x)

# export onnx
torch.onnx.export(net, (x, ), "test_nn_ConvTranspose2d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_nn_ConvTranspose2d.onnx inputshape=[1,12,10,10]")

# pnnx inference
import test_nn_ConvTranspose2d_pnnx
b = test_nn_ConvTranspose2d_pnnx.test_inference()

return torch.equal(a, b)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

+ 76
- 0
tools/pnnx/tests/onnx/test_nn_ConvTranspose3d.py View File

@@ -0,0 +1,76 @@
# Tencent is pleased to support the open source community by making ncnn available.
#
# Copyright (C) 2024 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.

import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()

self.deconv_0 = nn.ConvTranspose3d(in_channels=12, out_channels=16, kernel_size=3)
self.deconv_1 = nn.ConvTranspose3d(in_channels=16, out_channels=20, kernel_size=(2,3,4), stride=(2,2,1), padding=2, output_padding=0)
self.deconv_2 = nn.ConvTranspose3d(in_channels=20, out_channels=24, kernel_size=(1,2,3), stride=1, padding=(2,3,4), output_padding=(0,0,0), dilation=1, groups=1, bias=False)
self.deconv_3 = nn.ConvTranspose3d(in_channels=24, out_channels=28, kernel_size=(5,4,3), stride=2, padding=0, output_padding=(0,1,1), dilation=1, groups=4, bias=True)
self.deconv_4 = nn.ConvTranspose3d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, output_padding=0, dilation=(1,2,2), groups=2, bias=False)
self.deconv_5 = nn.ConvTranspose3d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, output_padding=1, dilation=1, groups=32, bias=True)
self.deconv_6 = nn.ConvTranspose3d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, output_padding=0, dilation=1, groups=1, bias=False)
self.deconv_7 = nn.ConvTranspose3d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(5,6,7), output_padding=(1,0,1), dilation=2, groups=1, bias=True)

self.downsample = nn.Conv3d(24, 16, 3, stride=2, padding=1)
self.upsample = nn.ConvTranspose3d(16, 24, 3, stride=2, padding=1)

def forward(self, x):
x = self.deconv_0(x)
x = self.deconv_1(x)
x = self.deconv_2(x)
x = self.deconv_3(x)
x = self.deconv_4(x)
x = self.deconv_5(x)
x = self.deconv_6(x)
x = self.deconv_7(x)

y = self.downsample(x)
x = self.upsample(y, output_size=x.size())

return x

def test():
net = Model()
net.eval()

torch.manual_seed(0)
x = torch.rand(1, 12, 7, 7, 10)

a = net(x)

# export onnx
torch.onnx.export(net, (x, ), "test_nn_ConvTranspose3d.onnx")

# onnx to pnnx
import os
os.system("../../src/pnnx test_nn_ConvTranspose3d.onnx inputshape=[1,12,7,7,10]")

# pnnx inference
import test_nn_ConvTranspose3d_pnnx
b = test_nn_ConvTranspose3d_pnnx.test_inference()

return torch.equal(a, b)

if __name__ == "__main__":
if test():
exit(0)
else:
exit(1)

Loading…
Cancel
Save