diff --git a/paddle/fluid/operators/sequence_ops/sequence_slice_op.cc b/paddle/fluid/operators/sequence_ops/sequence_slice_op.cc deleted file mode 100644 index 701727a2cf4ca6..00000000000000 --- a/paddle/fluid/operators/sequence_ops/sequence_slice_op.cc +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (c) 2016 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. */ - -#include "paddle/fluid/operators/sequence_ops/sequence_slice_op.h" - -#include - -namespace paddle { -namespace operators { - -class SequenceSliceOp : public framework::OperatorWithKernel { - public: - using framework::OperatorWithKernel::OperatorWithKernel; - - void InferShape(framework::InferShapeContext* ctx) const override { - OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "SequenceSlice"); - OP_INOUT_CHECK(ctx->HasInput("Offset"), "Input", "Offset", "SequenceSlice"); - OP_INOUT_CHECK(ctx->HasInput("Length"), "Input", "Length", "SequenceSlice"); - OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "SequenceSlice"); - auto input_dims = ctx->GetInputDim("X"); - - auto offset_dim = ctx->GetInputDim("Offset"); - auto length_dim = ctx->GetInputDim("Length"); - - PADDLE_ENFORCE_EQ( - offset_dim.size(), - 2UL, - phi::errors::InvalidArgument( - "Input Offset dimension error. SequenceSlice operator only support " - "one level sequence now, the dimension of input Offset must be 2, " - "but received dimension is %d.", - offset_dim.size())); - PADDLE_ENFORCE_EQ( - length_dim.size(), - 2UL, - phi::errors::InvalidArgument( - "Input Length dimension error. SequenceSlice operator only support " - "one level sequence now, the dimension of input Length must be 2, " - "but received dimension is %d.", - offset_dim.size())); - - // Initialize the output's dims to maximum, - // and re-set to real dims by the value of Offset and Length at kernel - ctx->SetOutputDim("Out", input_dims); - } - - protected: - phi::KernelKey GetExpectedKernelType( - const framework::ExecutionContext& ctx) const override { - return phi::KernelKey(OperatorWithKernel::IndicateVarDataType(ctx, "X"), - ctx.GetPlace()); - } -}; - -class SequenceSliceGradOp : public framework::OperatorWithKernel { - public: - using framework::OperatorWithKernel::OperatorWithKernel; - - void InferShape(framework::InferShapeContext* ctx) const override { - OP_INOUT_CHECK(ctx->HasInput(framework::GradVarName("Out")), - "Input", - framework::GradVarName("Out"), - "SequenceSliceGrad"); - OP_INOUT_CHECK(ctx->HasOutputs(framework::GradVarName("X")), - "Output", - framework::GradVarName("X"), - "SequenceSliceGrad"); - ctx->SetOutputsDim(framework::GradVarName("X"), ctx->GetInputsDim("X")); - } - - protected: - phi::KernelKey GetExpectedKernelType( - const framework::ExecutionContext& ctx) const override { - return phi::KernelKey(OperatorWithKernel::IndicateVarDataType( - ctx, framework::GradVarName("Out")), - ctx.GetPlace()); - } -}; - -class SequenceSliceOpMaker : public framework::OpProtoAndCheckerMaker { - public: - void Make() override { - AddInput("X", - "(LoDTensor), " - "the input of SequenceSliceOp."); - AddInput("Offset", - "(Tensor), " - "a vector to describe the offset of every input sequence for " - "sub sequence item."); - AddInput("Length", - "(Tensor), " - "a vector to describe the length of every input sequence for " - "sub sequence item."); - AddOutput("Out", "(LoDTensor), the output of SequenceSliceOp."); - AddComment(R"DOC( -Sequence slice operator - -The operator crops a subsequence from given sequence with given start offset and subsequence length. -It only supports sequence (LoD Tensor with level number is 1). -- Case: - X = [[a1, a2; - b1, b2; - c1, c2] - [d1, d2; - e1, e2]] - LoD(X) = {{0, 3, 5}}; Dims(X) = (5, 2) - Offset = [[0], [1]]; Length = [[2], [1]] - - Out = [[a1, a2; - b1, b2] - [e1, e2]] - LoD(Out) = {{0, 2, 3}}; Dims(Out) = (3, 2) -NOTE: The first dimension size of input, the size of offset and Length, should be equal. The offset start from 0. - )DOC"); - } -}; - -template -class SequenceSliceGradOpMaker : public framework::SingleGradOpMaker { - public: - using framework::SingleGradOpMaker::SingleGradOpMaker; - - protected: - void Apply(GradOpPtr op) const override { - op->SetType("sequence_slice_grad"); - op->SetInput("X", this->Input("X")); - op->SetInput("Offset", this->Input("Offset")); - op->SetInput("Length", this->Input("Length")); - op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out")); - op->SetOutput(framework::GradVarName("X"), this->InputGrad("X")); - op->SetAttrMap(this->Attrs()); - } -}; - -DECLARE_NO_NEED_BUFFER_VARS_INFERER(SequenceSliceGradNoNeedBufferVarsInferer, - "X"); - -} // namespace operators -} // namespace paddle - -namespace ops = paddle::operators; -REGISTER_OPERATOR(sequence_slice, - ops::SequenceSliceOp, - ops::SequenceSliceOpMaker, - ops::SequenceSliceGradOpMaker, - ops::SequenceSliceGradOpMaker); -REGISTER_OPERATOR(sequence_slice_grad, - ops::SequenceSliceGradOp, - ops::SequenceSliceGradNoNeedBufferVarsInferer); -PD_REGISTER_STRUCT_KERNEL(sequence_slice, - CPU, - ALL_LAYOUT, - ops::SequenceSliceOpKernel, - float, - double, - int, - int64_t) {} -PD_REGISTER_STRUCT_KERNEL(sequence_slice_grad, - CPU, - ALL_LAYOUT, - ops::SequenceSliceGradOpKernel, - float, - double, - int, - int64_t) {} diff --git a/paddle/fluid/operators/sequence_ops/sequence_slice_op.cu b/paddle/fluid/operators/sequence_ops/sequence_slice_op.cu deleted file mode 100644 index 407eb2e3ad7db8..00000000000000 --- a/paddle/fluid/operators/sequence_ops/sequence_slice_op.cu +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (c) 2016 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. */ - -#include "paddle/fluid/operators/sequence_ops/sequence_slice_op.h" - -namespace ops = paddle::operators; -PD_REGISTER_STRUCT_KERNEL(sequence_slice, - GPU, - ALL_LAYOUT, - ops::SequenceSliceOpKernel, - float, - double, - int, - int64_t) {} -PD_REGISTER_STRUCT_KERNEL(sequence_slice_grad, - GPU, - ALL_LAYOUT, - ops::SequenceSliceGradOpKernel, - float, - double, - int, - int64_t) {} diff --git a/paddle/fluid/operators/sequence_ops/sequence_slice_op.h b/paddle/fluid/operators/sequence_ops/sequence_slice_op.h deleted file mode 100644 index ee826570b37e79..00000000000000 --- a/paddle/fluid/operators/sequence_ops/sequence_slice_op.h +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (c) 2016 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. */ - -#pragma once -#include "paddle/fluid/framework/op_registry.h" -#include "paddle/phi/kernels/funcs/math_function.h" -#include "paddle/phi/kernels/funcs/strided_memcpy.h" - -namespace paddle { -namespace operators { - -using Tensor = phi::DenseTensor; -using LoDTensor = phi::DenseTensor; -using LoD = framework::LoD; - -template -inline LoD SequenceSliceLoD(const T& in, - const int64_t* offset_data, - const int64_t* length_data) { - auto out_lod = in.lod(); - size_t lod_offset = 0; - - auto n = in.lod()[0].size() - 1; - out_lod[0][0] = 0; - for (size_t i = 0; i < n; ++i) { - lod_offset += length_data[i]; - out_lod[0][i + 1] = lod_offset; - } - return out_lod; -} - -template -class SequenceSliceOpKernel : public framework::OpKernel { - public: - void Compute(const framework::ExecutionContext& ctx) const override { - auto* in = ctx.Input("X"); - auto* offset = ctx.Input("Offset"); - auto* length = ctx.Input("Length"); - auto* out = ctx.Output("Out"); - - auto lod = in->lod(); - PADDLE_ENFORCE_EQ(lod.empty(), - false, - phi::errors::InvalidArgument( - "Input(X) Tensor of SequenceSlice operator does not " - "contain LoD information.")); - - PADDLE_ENFORCE_EQ( - lod.size(), - 1UL, - phi::errors::InvalidArgument( - "LoD information error. SequenceSlice operator only support one " - "level sequence now, but received LoD level is %d.", - lod.size())); - auto n = lod[0].size() - 1; - PADDLE_ENFORCE_EQ( - n, - static_cast(length->dims()[0]), - phi::errors::InvalidArgument( - "Input length shape error. The length of input LoD sequence and " - "input length-array‘s first dimension should be equal, but the LoD " - "sequence length is %d, the length-array‘s first dimension is %d.", - n, - static_cast(length->dims()[0]))); - PADDLE_ENFORCE_EQ( - n, - static_cast(offset->dims()[0]), - phi::errors::InvalidArgument( - "Input offset shape error. The length of input LoD sequence and " - "input offset-array‘s first dimension should be equal, but the LoD " - "sequence length is %d, the offset-array‘s first dimension is %d.", - n, - static_cast(offset->dims()[0]))); - - const int64_t* offset_data = offset->data(); - const int64_t* length_data = length->data(); - phi::DenseTensor offset_cpu; - phi::DenseTensor length_cpu; - - if (platform::is_gpu_place(ctx.GetPlace())) { - offset_cpu.mutable_data(offset->dims(), platform::CPUPlace()); - framework::TensorCopySync(*offset, platform::CPUPlace(), &offset_cpu); - offset_data = offset_cpu.data(); - - length_cpu.mutable_data(length->dims(), platform::CPUPlace()); - framework::TensorCopySync(*length, platform::CPUPlace(), &length_cpu); - length_data = length_cpu.data(); - } - - for (size_t i = 0; i < n; ++i) { - PADDLE_ENFORCE_LE(0, - offset_data[i], - phi::errors::InvalidArgument( - "The input offset[%d]'s value is negative, its " - "value is %d, expect it to be non-negative.", - i, - offset_data[i])); - PADDLE_ENFORCE_LE(0, - length_data[i], - phi::errors::InvalidArgument( - "The input length[%d]'s value is negative, its " - "value is %d, expect it to be non-negative.", - i, - offset_data[i])); - PADDLE_ENFORCE_LE( - lod[0][i] + offset_data[i] + length_data[i], - lod[0][i + 1], - phi::errors::OutOfRange( - "The slice end index of target tensor is out of range. expect it " - "less than or equal to %d, but the actual slice end index is %d.", - lod[0][i + 1], - lod[0][i] + offset_data[i] + length_data[i])); - } - - out->mutable_data(ctx.GetPlace()); - auto out_lod = SequenceSliceLoD(*in, offset_data, length_data); - auto out_dims = in->dims(); - out_dims[0] = out_lod[0][out_lod[0].size() - 1]; - out->Resize(out_dims); - out->set_lod(out_lod); - - auto in_stride = common::stride(in->dims()); - auto out_stride = common::stride(out->dims()); - - size_t out_offset = 0; - for (size_t i = 0; i < n; ++i) { - if (length_data[i] == 0) continue; - Tensor in_t = in->Slice( - static_cast(lod[0][i] + offset_data[i]), - static_cast(lod[0][i] + offset_data[i] + length_data[i])); - - phi::funcs::StridedMemcpy(ctx.device_context(), - in_t.data(), - in_stride, - in_t.dims(), - out_stride, - out->data() + out_offset); - out_offset += length_data[i] * in_stride[0]; - } - } -}; - -template -class SequenceSliceGradOpKernel : public framework::OpKernel { - public: - void Compute(const framework::ExecutionContext& ctx) const override { - auto* in = ctx.Input("X"); - auto* offset = ctx.Input("Offset"); - auto* length = ctx.Input("Length"); - auto* out_grad = ctx.Input(framework::GradVarName("Out")); - auto* x_grad = ctx.Output(framework::GradVarName("X")); - - const int64_t* offset_data = offset->data(); - const int64_t* length_data = length->data(); - phi::DenseTensor offset_cpu; - phi::DenseTensor length_cpu; - - if (platform::is_gpu_place(ctx.GetPlace())) { - offset_cpu.mutable_data(offset->dims(), platform::CPUPlace()); - framework::TensorCopySync(*offset, platform::CPUPlace(), &offset_cpu); - offset_data = offset_cpu.data(); - - length_cpu.mutable_data(length->dims(), platform::CPUPlace()); - framework::TensorCopySync(*length, platform::CPUPlace(), &length_cpu); - length_data = length_cpu.data(); - } - - auto lod = in->lod(); - // to avoid out_grad missing lod, compute lod again - auto out_lod = SequenceSliceLoD(*in, offset_data, length_data); - - if (x_grad) { - x_grad->mutable_data(ctx.GetPlace()); - x_grad->set_lod(in->lod()); - phi::funcs::SetConstant set_zero; - set_zero(ctx.template device_context(), - x_grad, - static_cast(0)); - - for (size_t i = 0; i < out_lod[0].size() - 1; ++i) { - if (length_data[i] == 0) continue; - Tensor out_grad_t = - out_grad->Slice(static_cast(out_lod[0][i]), - static_cast(out_lod[0][i + 1])); - auto out_grad_stride = common::stride(out_grad_t.dims()); - - auto x_grad_stride = common::stride(x_grad->dims()); - - Tensor x_grad_t = x_grad->Slice( - static_cast(lod[0][i] + offset_data[i]), - static_cast(lod[0][i] + offset_data[i] + length_data[i])); - - phi::funcs::StridedMemcpy(ctx.device_context(), - out_grad_t.data(), - out_grad_stride, - out_grad_t.dims(), - x_grad_stride, - x_grad_t.data()); - } - } - } -}; - -} // namespace operators -} // namespace paddle diff --git a/test/sequence/test_sequence_slice_op.py b/test/sequence/test_sequence_slice_op.py deleted file mode 100644 index 22c276824c8a58..00000000000000 --- a/test/sequence/test_sequence_slice_op.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) 2018 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. - -import unittest - -import numpy as np -from op_test import OpTest - - -class TestSequenceSliceOp(OpTest): - def set_data(self): - self.init_test_case() - # only supprot one level LoD - x = np.random.random(self.x_dim).astype('float32') - lod = self.x_lod - offset = np.array(self.offset).astype("int64") - length = np.array(self.length).astype("int64") - - self.inputs = {'X': (x, lod), 'Offset': offset, 'Length': length} - outs = [] # np.zeros((100, 3, 2)).astype('float32') - out_lod = [[]] - lod_offset = 0 - for i in range(len(offset)): - sub_x = x[ - lod_offset - + offset[i, 0] : lod_offset - + offset[i, 0] - + length[i, 0], - :, - ] - outs.append(sub_x) - out_lod[0].append(len(sub_x)) - lod_offset += lod[0][i] - outs = np.concatenate(outs, axis=0) - self.outputs = {'Out': (outs, out_lod)} - - def init_test_case(self): - self.x_dim = (100, 3, 2) - self.x_lod = [[20, 20, 20, 20, 20]] - self.offset = [[1], [2], [3], [4], [5]] - self.length = [[10], [8], [6], [4], [2]] - - def setUp(self): - self.op_type = "sequence_slice" - self.set_data() - - def test_check_output(self): - self.check_output() - - def test_check_grad(self): - self.check_grad(['X'], 'Out') - - -class TestSequenceSliceOpSeqlen0Case0(TestSequenceSliceOp): - def init_test_case(self): - self.x_dim = (100, 3, 2) - self.x_lod = [[20, 30, 0, 30, 20]] - self.offset = [[1], [2], [0], [4], [5]] - self.length = [[10], [8], [0], [4], [2]] - - -class TestSequenceSliceOpSeqlen0Case1(TestSequenceSliceOp): - def init_test_case(self): - self.x_dim = (100, 3, 2) - self.x_lod = [[0, 70, 0, 30, 0]] - self.offset = [[0], [2], [0], [4], [0]] - self.length = [[0], [8], [0], [4], [0]] - - -class TestSequenceSliceOpSeqlen0Case2(TestSequenceSliceOp): - def init_test_case(self): - self.x_dim = (100, 3, 2) - self.x_lod = [[0, 100, 0, 0, 0]] - self.offset = [[0], [2], [0], [0], [0]] - self.length = [[0], [8], [0], [0], [0]] - - -if __name__ == '__main__': - unittest.main()