Skip to content

Commit

Permalink
update Ops(one_hot, split, layer_norm) (PaddlePaddle#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
yaozhixin authored Dec 20, 2021
1 parent 2d496e0 commit a9a1a3d
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ Node *cross_entropy2_handler(Graph *graph, Node *node) {
new_cast = new_cast->outputs[0];
}
auto label_shape_ = GetInputVarNode("Label", node)->Var()->GetShape();
if (label_shape_.size() == 1) {
if (label_shape_[label_shape_.size() - 1] != 1) {
auto log = CreateBaseOp(graph, node, "popart_log",
{GetInputVarNode("X", node)}, {}, {});
return CreateBaseOp(
Expand Down
19 changes: 15 additions & 4 deletions paddle/fluid/framework/ipu/popart_canonicalization/nn_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,21 @@ Node *layer_norm_handler(Graph *graph, Node *node) {
auto *op = node->Op();
auto begin_norm_axis_ = BOOST_GET_CONST(int, op->GetAttr("begin_norm_axis"));
auto input_shape_ = GetInputVarNode("X", node)->Var()->GetShape();
auto epsilon_ = BOOST_GET_CONST(float, op->GetAttr("epsilon"));
int64_t groups_ = 1;

auto groupnorm_attrs_ =
AttributeMap{{"epsilon", epsilon_}, {"num_groups", groups_}};

if (input_shape_.size() == 2) {
return CreateBaseOp(
graph, node, "popart_groupnormalization_v2",
{GetInputVarNode("X", node), GetInputVarNode("Scale", node),
GetInputVarNode("Bias", node)},
{GetOutputVarNode("Y", node), GetOutputVarNode("Mean", node),
GetOutputVarNode("Variance", node)},
groupnorm_attrs_);
}

std::vector<int64_t> norm_shape_{1, 1};
for (int i = 0; i < input_shape_.size(); i++) {
Expand All @@ -213,10 +228,6 @@ Node *layer_norm_handler(Graph *graph, Node *node) {
graph, node, "popart_reshape",
{GetInputVarNode("X", node), reshape1_const->outputs[0]}, {}, {});

auto epsilon_ = BOOST_GET_CONST(float, op->GetAttr("epsilon"));
int64_t groups_ = 1;
auto groupnorm_attrs_ =
AttributeMap{{"epsilon", epsilon_}, {"num_groups", groups_}};
auto out_Y_ = MakeVarNode(graph, node);
CreateBaseOp(graph, node, "popart_groupnormalization_v2",
{new_node_reshape1->outputs[0], GetInputVarNode("Scale", node),
Expand Down
38 changes: 38 additions & 0 deletions paddle/fluid/framework/ipu/popart_canonicalization/tensor_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,42 @@ Node *fill_any_like_handler(Graph *graph, Node *node) {
});
}

Node *one_hot_handler(Graph *graph, Node *node) {
auto *op = node->Op();
auto depth = BOOST_GET_CONST(int, op->GetAttr("depth"));
auto allow_out_of_range =
BOOST_GET_CONST(bool, op->GetAttr("allow_out_of_range"));
if (allow_out_of_range) {
PADDLE_THROW(platform::errors::Unimplemented(
"Do not support allow_out_of_range=True"));
} else {
auto depth_tensor = CreateConst(graph, node, {}, {},
{{"value", std::vector<int64_t>{depth}},
{"dims", std::vector<int64_t>{1}},
{"dtype", ONNXDataType::INT64}});
auto value_tensor =
CreateConst(graph, node, {}, {}, {{"value", std::vector<float>{0, 1}},
{"dims", std::vector<int64_t>{2}},
{"dtype", ONNXDataType::FLOAT}});
return CreateBaseOp(graph, node, "popart_onehot",
{GetInputVarNode("X", node), depth_tensor->outputs[0],
value_tensor->outputs[0]},
{GetOutputVarNode("Out", node)},
{{"axis", int64_t{-1}}});
}
}

Node *split_handler(Graph *graph, Node *node) {
auto *op = node->Op();
auto axis = BOOST_GET_CONST(int, op->GetAttr("axis"));
auto sections = BOOST_GET_CONST(std::vector<int>, op->GetAttr("sections"));
return CreateBaseOp(
graph, node, "popart_split", {GetInputVarNode("X", node)}, node->outputs,
{{"num_outputs", int64_t(sections.size())},
{"axis", int64_t(axis)},
{"split", std::vector<int64_t>{sections.begin(), sections.end()}}});
}

REGISTER_HANDLER(fill_constant, fill_constant_handler);
REGISTER_HANDLER(gaussian_random, gaussian_random_handler);
REGISTER_HANDLER(uniform_random, uniform_random_handler);
Expand All @@ -477,6 +513,8 @@ REGISTER_HANDLER(expand, expand_handler);
REGISTER_HANDLER(assign, assign_handler);
REGISTER_HANDLER(fill_any_like, fill_any_like_handler);
REGISTER_HANDLER(lookup_table_v2, lookup_table_v2_handler);
REGISTER_HANDLER(split, split_handler);
REGISTER_HANDLER(one_hot, one_hot_handler);

} // namespace
} // namespace ipu
Expand Down
118 changes: 118 additions & 0 deletions python/paddle/fluid/tests/unittests/ipu/test_onehot_op_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Copyright (c) 2021 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
import paddle
import paddle.fluid.compiler as compiler
import paddle.fluid.contrib.mixed_precision.fp16_utils as fp16_utils
from paddle.fluid.tests.unittests.ipu.op_test_ipu import IPUOpTest, ExecutionMode


@unittest.skipIf(not paddle.is_compiled_with_ipu(),
"core is not compiled with IPU")
class TestBase(IPUOpTest):
def setUp(self):
self.set_atol()
self.set_training()
self.set_data_feed()
self.set_feed_attr()
self.set_op_attrs()

@property
def fp16_enabled(self):
return True

def set_data_feed(self):
data1 = np.array([[1], [1], [3], [0]])

self.feed = {'x': data1.astype(np.int32)}

def set_feed_attr(self):
self.feed_shape = [x.shape for x in self.feed.values()]
self.feed_list = list(self.feed.keys())

def set_op_attrs(self):
self.attrs = {"depth": 4, "allow_out_of_range": False}

def _test_base(self, exec_mode):
scope = paddle.fluid.core.Scope()
main_prog = paddle.static.Program()
startup_prog = paddle.static.Program()
main_prog.random_seed = self.SEED
startup_prog.random_seed = self.SEED

with paddle.fluid.scope_guard(scope):
with paddle.static.program_guard(main_prog, startup_prog):
x = paddle.static.data(
name=self.feed_list[0],
shape=self.feed_shape[0],
dtype='int32')

with paddle.static.amp.fp16_guard():
out = paddle.fluid.layers.one_hot(x, **self.attrs)

fetch_list = [out.name]

if exec_mode == ExecutionMode.CPU_FP32:
place = paddle.CPUPlace()
else:
place = paddle.IPUPlace()

if exec_mode == ExecutionMode.IPU_PADDLE_FP16:
fp16_utils.rewrite_program_v2(
startup_prog=startup_prog,
main_prog=main_prog,
amp_lists=self.amp_list)

exe = paddle.static.Executor(place)
exe.run(startup_prog)

if exec_mode != ExecutionMode.CPU_FP32:
feed_list = self.feed_list
ipu_strategy = compiler.get_ipu_strategy()
ipu_strategy.is_training = self.is_training
if exec_mode == ExecutionMode.IPU_POPART_FP16:
ipu_strategy.enable_fp16 = True
program = compiler.IpuCompiler(
main_prog,
ipu_strategy=ipu_strategy).compile(feed_list, fetch_list)
else:
program = main_prog

feed = self.feed

result = exe.run(program, feed=feed, fetch_list=fetch_list)

return result[0]

def test_base(self):
output_dict = {}
for mode in ExecutionMode:
if (mode > ExecutionMode.IPU_FP32 and not self.fp16_enabled):
break
output_dict[mode] = self._test_base(mode).flatten()

self.check(output_dict)


@unittest.skip('')
class TestCase1(TestBase):
def set_op_attrs(self):
self.attrs = {"depth": 4, "allow_out_of_range": True}


if __name__ == "__main__":
unittest.main()
121 changes: 121 additions & 0 deletions python/paddle/fluid/tests/unittests/ipu/test_split_op_ipu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Copyright (c) 2021 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
import paddle
import paddle.fluid.compiler as compiler
import paddle.fluid.contrib.mixed_precision.fp16_utils as fp16_utils
from paddle.fluid.tests.unittests.ipu.op_test_ipu import IPUOpTest, ExecutionMode


@unittest.skipIf(not paddle.is_compiled_with_ipu(),
"core is not compiled with IPU")
class TestBase(IPUOpTest):
def setUp(self):
self.set_atol()
self.set_training()
self.set_data_feed()
self.set_feed_attr()
self.set_op_attrs()

@property
def fp16_enabled(self):
return True

def set_data_feed(self):
data1 = np.random.uniform(size=[1, 3, 10, 10])

self.feed_fp32 = {'x': data1.astype(np.float32)}
self.feed_fp16 = {'x': data1.astype(np.float16)}

def set_feed_attr(self):
self.feed_shape = [x.shape for x in self.feed_fp32.values()]
self.feed_list = list(self.feed_fp32.keys())

def set_op_attrs(self):
self.attrs = {"num_or_sections": [1, 1, 1], "axis": 1}

def _test_base(self, exec_mode):
scope = paddle.fluid.core.Scope()
main_prog = paddle.static.Program()
startup_prog = paddle.static.Program()
main_prog.random_seed = self.SEED
startup_prog.random_seed = self.SEED

with paddle.fluid.scope_guard(scope):
with paddle.static.program_guard(main_prog, startup_prog):
x = paddle.static.data(
name=self.feed_list[0],
shape=self.feed_shape[0],
dtype='float32')

with paddle.static.amp.fp16_guard():
out = paddle.split(x, **self.attrs)

fetch_list = [fetch.name for fetch in out]

if exec_mode == ExecutionMode.CPU_FP32:
place = paddle.CPUPlace()
else:
place = paddle.IPUPlace()

if exec_mode == ExecutionMode.IPU_PADDLE_FP16:
fp16_utils.rewrite_program_v2(
startup_prog=startup_prog,
main_prog=main_prog,
amp_lists=self.amp_list)

exe = paddle.static.Executor(place)
exe.run(startup_prog)

if exec_mode != ExecutionMode.CPU_FP32:
feed_list = self.feed_list
ipu_strategy = compiler.get_ipu_strategy()
ipu_strategy.is_training = self.is_training
if exec_mode == ExecutionMode.IPU_POPART_FP16:
ipu_strategy.enable_fp16 = True
program = compiler.IpuCompiler(
main_prog,
ipu_strategy=ipu_strategy).compile(feed_list, fetch_list)
else:
program = main_prog

feed = self.feed_fp32
if exec_mode > ExecutionMode.IPU_FP32:
feed = self.feed_fp16

result = exe.run(program, feed=feed, fetch_list=fetch_list)

return result[0]

def test_base(self):
output_dict = {}
for mode in ExecutionMode:
if (mode > ExecutionMode.IPU_FP32 and not self.fp16_enabled
) or mode == ExecutionMode.IPU_POPART_FP16:
break
output_dict[mode] = self._test_base(mode).flatten()

self.check(output_dict)


class TestCase1(TestBase):
def set_op_attrs(self):
self.attrs = {"num_or_sections": [2, 8], "axis": 2}


if __name__ == "__main__":
unittest.main()

0 comments on commit a9a1a3d

Please sign in to comment.