From d93661942ed69527ea53259a4b6e65e8aef3cbea Mon Sep 17 00:00:00 2001 From: Shang Zhizhou Date: Mon, 21 Sep 2020 19:10:04 +0800 Subject: [PATCH] fix bug sequececonv_eltadd_relu_fuse_pass (#27404) * fix bug sequececonv_eltadd_relu_fuse_pass, output error when sequence_conv's padding_start > 0 * fix seqconv_eltadd_relu_fuse_pass unitest error --- .../ir/seqconv_eltadd_relu_fuse_pass.cc | 7 + .../fused/fusion_seqconv_eltadd_relu_op.cc | 18 ++- .../test_seqconv_eltadd_relu_fuse_pass.py | 140 ++++++++++++++++++ 3 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 python/paddle/fluid/tests/unittests/ir/inference/test_seqconv_eltadd_relu_fuse_pass.py diff --git a/paddle/fluid/framework/ir/seqconv_eltadd_relu_fuse_pass.cc b/paddle/fluid/framework/ir/seqconv_eltadd_relu_fuse_pass.cc index 1485a84d001..75ab04f1b91 100644 --- a/paddle/fluid/framework/ir/seqconv_eltadd_relu_fuse_pass.cc +++ b/paddle/fluid/framework/ir/seqconv_eltadd_relu_fuse_pass.cc @@ -16,6 +16,7 @@ #include #include #include "paddle/fluid/framework/lod_tensor.h" +#include "paddle/fluid/framework/op_version_registry.h" namespace paddle { namespace framework { @@ -98,3 +99,9 @@ void SeqConvEltAddReluFusePass::ApplyImpl(ir::Graph* graph) const { REGISTER_PASS(seqconv_eltadd_relu_fuse_pass, paddle::framework::ir::SeqConvEltAddReluFusePass); +REGISTER_PASS_CAPABILITY(seqconv_eltadd_relu_fuse_pass) + .AddCombination( + paddle::framework::compatible::OpVersionComparatorCombination() + .EQ("sequence_conv", 0) + .EQ("elementwise_add", 0) + .EQ("relu", 0)); diff --git a/paddle/fluid/operators/fused/fusion_seqconv_eltadd_relu_op.cc b/paddle/fluid/operators/fused/fusion_seqconv_eltadd_relu_op.cc index a6c9a137b54..c5a291f10b2 100644 --- a/paddle/fluid/operators/fused/fusion_seqconv_eltadd_relu_op.cc +++ b/paddle/fluid/operators/fused/fusion_seqconv_eltadd_relu_op.cc @@ -192,6 +192,9 @@ class FusionSeqConvEltAddReluKernel : public framework::OpKernel { copy_size += src_mat_w_sz; } // fill data + if (context_start > 0) { + src_data += context_start * src_mat_w; + } for (int j = 0; j < seq_len - up_pad - down_pad; ++j) { std::memcpy(dst_data, src_data, copy_size); dst_data += col_mat_w; @@ -201,18 +204,15 @@ class FusionSeqConvEltAddReluKernel : public framework::OpKernel { std::memset(dst_data, 0, down_pad * col_mat_w_sz); copy_size -= src_mat_w_sz; for (int j = 0; j < down_pad; ++j) { + if (copy_size < 0) { + copy_size = 0; + } std::memcpy(dst_data, src_data, copy_size); dst_data += col_mat_w; src_data += src_mat_w; copy_size -= src_mat_w_sz; } } else { - PADDLE_ENFORCE_GE(context_length, up_pad + down_pad + 1, - platform::errors::InvalidArgument( - "context length must be bigger or equal than " - "up_pad + down_pad + 1, but received context " - "length is: %d, up_pad is: %d, down_pad is: %d.", - context_length, up_pad, down_pad)); std::memset(dst_data, 0, seq_len * col_mat_w_sz); dst_data = dst_data + up_pad * src_mat_w; int zero_sz = up_pad * src_mat_w_sz; @@ -226,9 +226,15 @@ class FusionSeqConvEltAddReluKernel : public framework::OpKernel { // from bottom dst_data = col_data + ed * col_mat_w; src_data = x_data + st * src_mat_w; + if (context_start > 0) { + src_data += context_start * src_mat_w; + } zero_sz = down_pad * src_mat_w_sz; for (int j = 1; j <= std::min(down_pad, seq_len); ++j) { int copy_size = std::min(cur_src_sz, col_mat_w_sz - zero_sz); + if (copy_size < 0) { + copy_size = 0; + } std::memcpy(dst_data - (zero_sz + copy_size) / sizeof(T), src_data + std::max(seq_len - j - up_pad, 0) * src_mat_w, copy_size); diff --git a/python/paddle/fluid/tests/unittests/ir/inference/test_seqconv_eltadd_relu_fuse_pass.py b/python/paddle/fluid/tests/unittests/ir/inference/test_seqconv_eltadd_relu_fuse_pass.py new file mode 100644 index 00000000000..eadda5ba06a --- /dev/null +++ b/python/paddle/fluid/tests/unittests/ir/inference/test_seqconv_eltadd_relu_fuse_pass.py @@ -0,0 +1,140 @@ +# Copyright (c) 2020 PaddlePaddle Authors. 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. + +from __future__ import print_function + +import unittest +import numpy as np +from inference_pass_test import InferencePassTest +import paddle.fluid as fluid +import paddle.fluid.core as core +from paddle.fluid.core import AnalysisConfig +from paddle.fluid.core import PassVersionChecker + + +class SeqconvEltaddReluFusePassTest(InferencePassTest): + def setUp(self): + with fluid.program_guard(self.main_program, self.startup_program): + data = fluid.data(name="data", shape=[100, 100], dtype="float32") + param_attr = fluid.ParamAttr( + initializer=fluid.initializer.Xavier(uniform=False), + learning_rate=0.001) + conv_out = fluid.layers.sequence_conv( + input=data, + num_filters=16, + filter_size=4, + padding_start=0, + act="relu", + bias_attr=param_attr) + + np_data = np.random.random((80, 100)).astype('float32') + x_lod_tensor = fluid.create_lod_tensor(np_data, [[10, 20, 30, 20]], + fluid.CPUPlace()) + self.feeds = {"data": x_lod_tensor} + self.fetch_list = [conv_out] + self.enable_mkldnn = True + + def test_check_output(self): + self.check_output() + self.assertTrue( + PassVersionChecker.IsCompatible('seqconv_eltadd_relu_fuse_pass')) + + +class SeqconvEltaddReluFusePassTestPaddingStartPositive(InferencePassTest): + def setUp(self): + with fluid.program_guard(self.main_program, self.startup_program): + data = fluid.data(name="data", shape=[-1, 4], dtype="float32") + param_attr = fluid.ParamAttr( + initializer=fluid.initializer.Xavier(uniform=False), + learning_rate=0.001) + conv_out = fluid.layers.sequence_conv( + input=data, + num_filters=16, + filter_size=3, + padding_start=2, + act="relu", + bias_attr=param_attr) + + np_data = np.array([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], + [4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6], + [7, 7, 7, 7]]).astype('float32') + x_lod_tensor = fluid.create_lod_tensor(np_data, [[5, 2]], + fluid.CPUPlace()) + self.feeds = {"data": x_lod_tensor} + self.fetch_list = [conv_out] + self.enable_mkldnn = True + + def test_check_output(self): + self.check_output() + self.assertTrue( + PassVersionChecker.IsCompatible('seqconv_eltadd_relu_fuse_pass')) + + +class SeqconvEltaddReluFusePassTestPaddingStartNegative(InferencePassTest): + def setUp(self): + with fluid.program_guard(self.main_program, self.startup_program): + data = fluid.data(name="data", shape=[100, 100], dtype="float32") + param_attr = fluid.ParamAttr( + initializer=fluid.initializer.Xavier(uniform=False), + learning_rate=0.001) + conv_out = fluid.layers.sequence_conv( + input=data, + num_filters=16, + filter_size=4, + padding_start=-1, + act="relu", + bias_attr=param_attr) + + np_data = np.random.random((80, 100)).astype('float32') + x_lod_tensor = fluid.create_lod_tensor(np_data, [[10, 20, 30, 20]], + fluid.CPUPlace()) + self.feeds = {"data": x_lod_tensor} + self.fetch_list = [conv_out] + self.enable_mkldnn = True + + def test_check_output(self): + self.check_output() + self.assertTrue( + PassVersionChecker.IsCompatible('seqconv_eltadd_relu_fuse_pass')) + + +class SeqconvEltaddReluFusePassTestPaddingStartNone(InferencePassTest): + def setUp(self): + with fluid.program_guard(self.main_program, self.startup_program): + data = fluid.data(name="data", shape=[100, 100], dtype="float32") + param_attr = fluid.ParamAttr( + initializer=fluid.initializer.Xavier(uniform=False), + learning_rate=0.001) + conv_out = fluid.layers.sequence_conv( + input=data, + num_filters=16, + filter_size=4, + act="relu", + bias_attr=param_attr) + + np_data = np.random.random((80, 100)).astype('float32') + x_lod_tensor = fluid.create_lod_tensor(np_data, [[10, 20, 30, 20]], + fluid.CPUPlace()) + self.feeds = {"data": x_lod_tensor} + self.fetch_list = [conv_out] + self.enable_mkldnn = True + + def test_check_output(self): + self.check_output() + self.assertTrue( + PassVersionChecker.IsCompatible('seqconv_eltadd_relu_fuse_pass')) + + +if __name__ == "__main__": + unittest.main() -- GitLab