Skip to content

Commit 82358bf

Browse files
authored
ont hot support tensor depth (#16972)
* support some input tensor remain on cpu; test=develop * fix input = none; test=develop * fix unfound bug; test=develop * fix proto None case; test=develop * fix bug; test=develop * fix proto null bug; test=develop * remove conv check; test=develop * fix test bug; test=develop * move fill constant; test=develop * no change in proto; test=develop * fix bug; test=develop * change attr detph name; test=develop * remove remain cpu; test=develop * fix bug; test=develop * merge develop; test=develop * fix one_hot bug; test=develop * fix bug; test=develop * fix bug; test=develop * fix bug; test=develop * fix python api bug; test=develop
1 parent 7cfddf2 commit 82358bf

File tree

9 files changed

+141
-15
lines changed

9 files changed

+141
-15
lines changed

paddle/fluid/operators/one_hot_op.cc

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// limitations under the License.
1414

1515
#include "paddle/fluid/operators/one_hot_op.h"
16+
#include <string>
17+
#include <vector>
1618
#include "paddle/fluid/framework/framework.pb.h"
1719

1820
namespace paddle {
@@ -34,15 +36,34 @@ class OneHotOp : public framework::OperatorWithKernel {
3436
PADDLE_ENFORCE_GE(x_dims[x_dims.size() - 1], 1U,
3537
"Last dimension of Input(X) should be 1.");
3638
}
37-
int depth = ctx->Attrs().Get<int>("depth");
38-
39-
PADDLE_ENFORCE_GT(depth, 0, "Should provide a positive depth (%d).", depth);
4039

4140
framework::DDim out_dims(x_dims);
41+
int depth = ctx->Attrs().Get<int>("depth");
42+
if (ctx->HasInput("depth_tensor")) {
43+
depth = -1;
44+
}
45+
4246
out_dims[out_dims.size() - 1] = depth;
4347
ctx->SetOutputDim("Out", out_dims);
4448
ctx->ShareLoD("X", /* --> */ "Out");
4549
}
50+
51+
protected:
52+
framework::OpKernelType GetExpectedKernelType(
53+
const framework::ExecutionContext& ctx) const override {
54+
return framework::OpKernelType(ctx.Input<Tensor>("X")->type(),
55+
ctx.device_context());
56+
}
57+
58+
framework::OpKernelType GetKernelTypeForVar(
59+
const std::string& var_name, const Tensor& tensor,
60+
const framework::OpKernelType& expected_kernel_type) const override {
61+
if (var_name == "depth_tensor") {
62+
return expected_kernel_type;
63+
}
64+
return framework::OpKernelType(expected_kernel_type.data_type_,
65+
tensor.place(), tensor.layout());
66+
}
4667
};
4768

4869
class OneHotOpMaker : public framework::OpProtoAndCheckerMaker {
@@ -52,11 +73,15 @@ class OneHotOpMaker : public framework::OpProtoAndCheckerMaker {
5273
"(LoDTensor, LoDTensor<int>) Input variable with rank at least 2. "
5374
"The last dimension of X should be 1. Each value of X is an index "
5475
"to indicate the position.");
76+
AddInput("depth_tensor", "(Tensor, Tensor<int>), Length of one-hot vector")
77+
.AsDispensable();
5578
AddOutput("Out",
5679
"(Tensor, Tensor<float>) Output tensor with same rank as X. "
5780
"The tensor consists of one-hot representations of values in X.");
81+
5882
AddAttr<int>("depth",
59-
"A positive integer to specify the length of one-hot vector.");
83+
"A positive integer to specify the length of one-hot vector.")
84+
.SetDefault(-1);
6085
AddAttr<int>("dtype",
6186
"An integer to specify the data type of one-hot "
6287
"vector. The default value is FP32.")

paddle/fluid/operators/one_hot_op.cu

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,25 @@ class OneHotCUDAKernel : public framework::OpKernel<T> {
6262
void Compute(const framework::ExecutionContext& context) const override {
6363
auto* in = context.Input<LoDTensor>("X");
6464
auto* out = context.Output<LoDTensor>("Out");
65-
int depth = context.Attr<int>("depth");
6665

66+
int depth = -1;
67+
if (context.HasInput("depth_tensor")) {
68+
auto* depth_tensor = context.Input<framework::Tensor>("depth_tensor");
69+
if (platform::is_gpu_place(depth_tensor->place())) {
70+
framework::Tensor temp;
71+
TensorCopySync(*depth_tensor, platform::CPUPlace(), &temp);
72+
depth = *temp.data<int32_t>();
73+
} else {
74+
depth = *depth_tensor->data<int32_t>();
75+
}
76+
77+
auto in_dims = in->dims();
78+
framework::DDim out_dims(in_dims);
79+
out_dims[out_dims.size() - 1] = depth;
80+
out->Resize(out_dims);
81+
} else {
82+
depth = context.Attr<int>("depth");
83+
}
6784
framework::VisitDataType(
6885
static_cast<framework::proto::VarType::Type>(
6986
context.Attr<int>("dtype")),

paddle/fluid/operators/one_hot_op.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,23 @@ struct OneHotOpFunctor {
4949
};
5050

5151
using LoDTensor = framework::LoDTensor;
52+
using Tensor = framework::Tensor;
5253
template <typename DeviceContext, typename T>
5354
class OneHotKernel : public framework::OpKernel<T> {
5455
public:
5556
void Compute(const framework::ExecutionContext& context) const override {
5657
auto* in = context.Input<LoDTensor>("X");
5758
auto* out = context.Output<LoDTensor>("Out");
5859
int depth = context.Attr<int>("depth");
60+
if (context.HasInput("depth_tensor")) {
61+
auto* depth_tensor = context.Input<Tensor>("depth_tensor");
62+
auto* depth_data = depth_tensor->data<int32_t>();
63+
depth = depth_data[0];
64+
auto in_dims = in->dims();
65+
framework::DDim out_dims(in_dims);
66+
out_dims[out_dims.size() - 1] = depth;
67+
out->Resize(out_dims);
68+
}
5969

6070
framework::VisitDataType(
6171
static_cast<framework::proto::VarType::Type>(

python/paddle/fluid/framework.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,7 @@ def __init__(self,
10131013
return
10141014
if type is None:
10151015
raise ValueError(
1016-
"`type` to initilized an Operator can not be None.")
1016+
"`type` to initialized an Operator can not be None.")
10171017
else:
10181018
callstack_var_name = op_maker.kOpCreationCallstackAttrName()
10191019
op_attrs[callstack_var_name] = list(
@@ -1036,7 +1036,6 @@ def find_name(var_list, name):
10361036
found = find_name(inputs, in_proto.name)
10371037
assert found or in_proto.dispensable, "Input {} not found".format(
10381038
in_proto.name)
1039-
10401039
if found:
10411040
in_args = inputs[in_proto.name]
10421041
if not isinstance(in_args, list):
@@ -1046,13 +1045,17 @@ def find_name(var_list, name):
10461045
"Input %s expects only one input, but %d are given."
10471046
% (in_proto.name, len(in_args)))
10481047
in_arg_names = []
1049-
for arg in in_args:
1048+
for index, arg in enumerate(in_args):
10501049
if isinstance(arg, six.string_types):
10511050
in_arg_names.append(arg)
10521051
elif isinstance(arg, six.binary_type):
10531052
in_arg_names.append(arg.decode())
1054-
else:
1053+
elif isinstance(arg, Variable):
10551054
in_arg_names.append(cpt.to_text(arg.name))
1055+
else:
1056+
raise ValueError(
1057+
"not suprt args type , should be[ string_type, binary_type, Varibale]"
1058+
)
10561059
self.desc.set_input(in_proto.name, in_arg_names)
10571060
else:
10581061
self.desc.set_input(in_proto.name, [])

python/paddle/fluid/layers/nn.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6564,11 +6564,24 @@ def one_hot(input, depth):
65646564
one_hot_label = fluid.layers.one_hot(input=label, depth=10)
65656565
"""
65666566
helper = LayerHelper("one_hot", **locals())
6567+
65676568
one_hot_out = helper.create_variable_for_type_inference(dtype='float32')
6569+
6570+
if in_dygraph_mode():
6571+
inputs = {'X': input}
6572+
attrs = {'depth': depth}
6573+
else:
6574+
if not isinstance(depth, Variable):
6575+
# user attribute
6576+
inputs = {'X': input}
6577+
attrs = {'depth': depth}
6578+
else:
6579+
inputs = {'X': input, 'depth_tensor': depth}
6580+
attrs = {}
65686581
helper.append_op(
65696582
type="one_hot",
6570-
inputs={'X': input},
6571-
attrs={'depth': depth},
6583+
inputs=inputs,
6584+
attrs=attrs,
65726585
outputs={'Out': one_hot_out},
65736586
stop_gradient=True)
65746587
return one_hot_out

python/paddle/fluid/tests/unittests/test_layers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,12 @@ def make_scatter(self):
12671267
out = layers.scatter(input=x, index=idx, updates=updates)
12681268
return (out)
12691269

1270+
def make_one_hot(self):
1271+
with fluid.framework._dygraph_place_guard(place=fluid.CPUPlace()):
1272+
label = self._get_data(name="label", shape=[1], dtype="int32")
1273+
one_hot_label = layers.one_hot(input=label, depth=10)
1274+
return (one_hot_label)
1275+
12701276
def make_label_smooth(self):
12711277
# TODO(minqiyang): support gpu ut
12721278
self._force_to_use_cpu = True

python/paddle/fluid/tests/unittests/test_one_hot_op.py

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,34 @@ class TestOneHotOp(OpTest):
2828
def setUp(self):
2929
self.op_type = 'one_hot'
3030
depth = 10
31+
depth_np = np.array(10).astype('int32')
3132
dimension = 12
3233
x_lod = [[4, 1, 3, 3]]
3334
x = [np.random.randint(0, depth - 1) for i in range(sum(x_lod[0]))]
34-
x = np.array(x).astype('int').reshape([sum(x_lod[0]), 1])
35+
x = np.array(x).astype('int32').reshape([sum(x_lod[0]), 1])
36+
37+
out = np.zeros(shape=(np.product(x.shape[:-1]),
38+
depth)).astype('float32')
39+
40+
for i in range(np.product(x.shape)):
41+
out[i, x[i]] = 1.0
42+
43+
self.inputs = {'X': (x, x_lod), 'depth_tensor': depth_np}
44+
self.attrs = {'dtype': int(core.VarDesc.VarType.FP32)}
45+
self.outputs = {'Out': (out, x_lod)}
46+
47+
def test_check_output(self):
48+
self.check_output()
49+
50+
51+
class TestOneHotOp_attr(OpTest):
52+
def setUp(self):
53+
self.op_type = 'one_hot'
54+
depth = 10
55+
dimension = 12
56+
x_lod = [[4, 1, 3, 3]]
57+
x = [np.random.randint(0, depth - 1) for i in range(sum(x_lod[0]))]
58+
x = np.array(x).astype('int32').reshape([sum(x_lod[0]), 1])
3559

3660
out = np.zeros(shape=(np.product(x.shape[:-1]),
3761
depth)).astype('float32')
@@ -40,21 +64,45 @@ def setUp(self):
4064
out[i, x[i]] = 1.0
4165

4266
self.inputs = {'X': (x, x_lod)}
43-
self.attrs = {'depth': depth, 'dtype': int(core.VarDesc.VarType.FP32)}
67+
self.attrs = {'dtype': int(core.VarDesc.VarType.FP32), 'depth': depth}
4468
self.outputs = {'Out': (out, x_lod)}
4569

4670
def test_check_output(self):
4771
self.check_output()
4872

4973

5074
class TestOneHotOp_default_dtype(OpTest):
75+
def setUp(self):
76+
self.op_type = 'one_hot'
77+
depth = 10
78+
depth_np = np.array(10).astype('int32')
79+
dimension = 12
80+
x_lod = [[4, 1, 3, 3]]
81+
x = [np.random.randint(0, depth - 1) for i in range(sum(x_lod[0]))]
82+
x = np.array(x).astype('int32').reshape([sum(x_lod[0]), 1])
83+
84+
out = np.zeros(shape=(np.product(x.shape[:-1]),
85+
depth)).astype('float32')
86+
87+
for i in range(np.product(x.shape)):
88+
out[i, x[i]] = 1.0
89+
90+
self.inputs = {'X': (x, x_lod), 'depth_tensor': depth_np}
91+
self.attrs = {}
92+
self.outputs = {'Out': (out, x_lod)}
93+
94+
def test_check_output(self):
95+
self.check_output()
96+
97+
98+
class TestOneHotOp_default_dtype_attr(OpTest):
5199
def setUp(self):
52100
self.op_type = 'one_hot'
53101
depth = 10
54102
dimension = 12
55103
x_lod = [[4, 1, 3, 3]]
56104
x = [np.random.randint(0, depth - 1) for i in range(sum(x_lod[0]))]
57-
x = np.array(x).astype('int').reshape([sum(x_lod[0]), 1])
105+
x = np.array(x).astype('int32').reshape([sum(x_lod[0]), 1])
58106

59107
out = np.zeros(shape=(np.product(x.shape[:-1]),
60108
depth)).astype('float32')

python/paddle/fluid/tests/unittests/test_operator_desc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_error_type(self):
3333
except ValueError as v_err:
3434
self.assertEqual(
3535
cpt.get_exception_message(v_err),
36-
"`type` to initilized an Operator can not be None.")
36+
"`type` to initialized an Operator can not be None.")
3737
try:
3838
block.append_op(type="no_such_op")
3939
self.assertFail()

python/paddle/fluid/tests/unittests/test_recordio_reader.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,7 @@ def test_shuffle_reader(self):
8686
def test_double_buffer_reader(self):
8787
self.test_main(decorator_callback=lambda reader: fluid.layers.io.double_buffer(reader,
8888
place='cuda:0' if fluid.core.is_compiled_with_cuda() else 'cpu'))
89+
90+
91+
if __name__ == '__main__':
92+
unittest.main()

0 commit comments

Comments
 (0)