@@ -24,17 +24,31 @@ Specify the name of your op, its inputs (types and names) and outputs (types and
24
24
```
25
25
#include "tensorflow/core/framework/op.h"
26
26
#include "tensorflow/core/framework/shape_inference.h"
27
+ #include "tensorflow/core/framework/register_types.h"
27
28
28
29
using namespace tensorflow;
29
30
30
31
31
- REGISTER_OP("AddOne")
32
- .Input("add_one: int32")
33
- .Output("result: int32")
32
+ // opregister
33
+ REGISTER_OP("DoubleAndAddOne")
34
+ .Input("x: T")
35
+ .Output("result: T")
36
+ .Attr("T: {float, double, int32}")
34
37
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext *c) {
35
- c->set_output(0, c->input(0));
38
+ ::tensorflow::shape_inference::ShapeHandle shape_x = c->input(0);
39
+ if (!c->RankKnown(shape_x)) {
40
+ c->set_output(0, c->UnknownShape());
41
+ return Status::OK();
42
+ }
43
+ c->set_output(0, shape_x);
36
44
return Status::OK();
37
- });
45
+ })
46
+ .Doc(R"doc(
47
+ Calculate the value 2x + 1.
48
+ x: A Tensor `Tensor`. Must be one of the types in `T`.
49
+
50
+ Returns: A `Tensor`. Has the same type with `x`.
51
+ )doc");
38
52
```
39
53
40
54
#### Implement the op kernel
@@ -43,35 +57,34 @@ Create a class that extends `OpKernel` and overrides the `Compute()` method. The
43
57
```
44
58
#include "tensorflow/core/framework/op_kernel.h"
45
59
46
- void AddOneKernelLauncher(const Tensor* t_in, const int n, Tensor* t_out);
47
-
48
- class AddOneOp : public OpKernel {
60
+ template <typename T>
61
+ class DoubleAndAddOneOp : public OpKernel {
49
62
public:
50
- explicit AddOneOp (OpKernelConstruction* context) : OpKernel(context) {}
63
+ explicit DoubleAndAddOneOp (OpKernelConstruction* context) : OpKernel(context) {}
51
64
52
65
void Compute(OpKernelContext* context) override {
53
- // Tensore in input
66
+ // Grab the input tensor
54
67
const Tensor& input_tensor = context->input(0);
55
- auto input = input_tensor.flat<int32 >();
68
+ auto input = input_tensor.flat<T >();
56
69
57
- // Tensore in output
70
+ // Tensor in output
58
71
Tensor* output_tensor = NULL;
59
72
OP_REQUIRES_OK(context, context->allocate_output(0, input_tensor.shape(), &output_tensor));
60
- auto output = output_tensor->flat<int32 >();
73
+ auto output = output_tensor->flat<T >();
61
74
62
- #if GOOGLE_CUDA
63
- AddOneKernelLauncher(input, input.size(), output);
64
- #else
65
75
const int N = input.size();
66
- for (int i = 0; i < N; i++) output(i) += 1;
67
- #endif
68
- if (N > 0) output(0) = input(0);
76
+ for (int i = 0; i < N; i++) {
77
+ output(i) = output(i) * T(2) + T(1);
78
+ }
69
79
}
70
80
};
71
81
```
72
82
Add the Register kernel build,
73
83
```
74
- REGISTER_KERNEL_BUILDER(Name("AddOne").Device(DEVICE_CPU), AddOneOp);
84
+ REGISTER_KERNEL_BUILDER(Name("DoubleAndAddOne")
85
+ .Device(DEVICE_CPU)
86
+ .TypeConstraint<int>("T"),
87
+ DoubleAndAddOneOp<int>);
75
88
```
76
89
Save below code in C++ ` .cc ` file,
77
90
@@ -80,9 +93,9 @@ Assuming you have g++ installed, here is the sequence of commands you can use to
80
93
```
81
94
TF_CFLAGS=( $(python -c 'import tensorflow as tf; print(" ".join(tf.sysconfig.get_compile_flags()))') )
82
95
TF_LFLAGS=( $(python -c 'import tensorflow as tf; print(" ".join(tf.sysconfig.get_link_flags()))') )
83
- g++ -std=c++14 -shared add_one .cc -o add_one .so -fPIC ${TF_CFLAGS[@]} ${TF_LFLAGS[@]} -O2
96
+ g++ -std=c++14 -shared double_and_add_one .cc -o double_and_add_one .so -fPIC ${TF_CFLAGS[@]} ${TF_LFLAGS[@]} -O2
84
97
```
85
- After below steps, we can get a TensorFlow custom op library ` add_one .so` .
98
+ After below steps, we can get a TensorFlow custom op library ` double_and_add_one .so` .
86
99
87
100
88
101
### Convert the Operator to ONNX
@@ -105,21 +118,30 @@ from tf2onnx.tf_loader import tf_placeholder
105
118
106
119
DIR_PATH = os.path.realpath(os.path.dirname(__file__))
107
120
saved_model_path = os.path.join(DIR_PATH, "model.onnx")
108
- tf_library_path = os.path.join(DIR_PATH, "add_one .so")
121
+ tf_library_path = os.path.join(DIR_PATH, "double_and_add_one .so")
109
122
110
123
111
- @tf_op("AddOne", onnx_op="Add ")
112
- class AddOne :
124
+ @tf_op("DoubleAndAddOne ")
125
+ class DoubleAndAddOne :
113
126
@classmethod
114
127
def version_1(cls, ctx, node, **kwargs):
128
+ node.type = "Mul"
115
129
node_shape = ctx.get_shape(node.input[0])
116
- const_one = ctx.make_const(utils.make_name("const_one"), np.ones(node_shape, dtype = np.int32)).output[0]
117
- node.input.append(const_one)
130
+ node_dtype = ctx.get_dtype(node.input[0])
131
+ node_np_dtype = utils.map_onnx_to_numpy_type(node_dtype)
132
+
133
+ const_two = ctx.make_const(utils.make_name("cosnt_two"), np.array([2]).astype(node_np_dtype)).output[0]
134
+ node.input.append(const_two)
135
+
136
+ const_one = ctx.make_const(utils.make_name("const_one"), np.ones(node_shape, dtype=node_np_dtype)).output[0]
137
+ op_name = utils.make_name(node.name)
138
+ ctx.insert_new_node_on_output("Add", node.output[0], inputs=[node.output[0], const_one], name=op_name)
139
+
118
140
119
141
@tf.function
120
142
def func(x):
121
- AddOne = tf.load_op_library(tf_library_path)
122
- x_ = AddOne.add_one (x)
143
+ custom_op = tf.load_op_library(tf_library_path)
144
+ x_ = custom_op.double_and_add_one (x)
123
145
output = tf.identity(x_, name="output")
124
146
return output
125
147
0 commit comments