mul,
add,
max,
- div
+ div,
+ sub,
};
/**
case ops::ElementwiseOp::OpType::div:
func = [](float a, float b) { return a / b; };
break;
+ case ops::ElementwiseOp::OpType::sub:
+ func = [](float a, float b) { return a - b; };
+ break;
default:
assert(false && "Unsupported Optype");
}
assert(input_shape.rank() == 4);
assert(kernel_shape.rank() == 4);
assert(kernel_shape.dim(3) == input_shape.dim(3));
- assert(_strides.dim(2) == 1);
assert(_op.getPaddingBefore().size() == 2);
assert(_op.getPaddingAfter().size() == 2);
}
case ops::ElementwiseOp::OpType::div:
func_name = "ElementWise<Div>";
break;
+ case ops::ElementwiseOp::OpType::sub:
+ func_name = "ElementWise<Sub>";
+ break;
default:
assert(false && "unsupported elementwise operation type");
}
}
}
+struct Sub {
+ static inline void Sub_(const float* input1_data, const float* input2_data,
+ float* output_data, const int size) {
+ int i = 0;
+#ifdef USE_NEON
+ for (; i <= size - 16; i += 16) {
+ auto a10 = vld1q_f32(input1_data + i);
+ auto a11 = vld1q_f32(input1_data + i + 4);
+ auto a12 = vld1q_f32(input1_data + i + 8);
+ auto a13 = vld1q_f32(input1_data + i + 12);
+ auto a20 = vld1q_f32(input2_data + i);
+ auto a21 = vld1q_f32(input2_data + i + 4);
+ auto a22 = vld1q_f32(input2_data + i + 8);
+ auto a23 = vld1q_f32(input2_data + i + 12);
+ auto x0 = vsubq_f32(a10, a20);
+ auto x1 = vsubq_f32(a11, a21);
+ auto x2 = vsubq_f32(a12, a22);
+ auto x3 = vsubq_f32(a13, a23);
+ vst1q_f32(output_data + i, x0);
+ vst1q_f32(output_data + i + 4, x1);
+ vst1q_f32(output_data + i + 8, x2);
+ vst1q_f32(output_data + i + 12, x3);
+ }
+ for (; i <= size - 4; i += 4) {
+ auto a1 = vld1q_f32(input1_data + i);
+ auto a2 = vld1q_f32(input2_data + i);
+ auto x = vsubq_f32(a1, a2);
+ vst1q_f32(output_data + i, x);
+ }
+#endif // NEON
+
+ for (; i < size; i++) {
+ output_data[i] = input1_data[i] - input2_data[i];
+ }
+ }
+
+ static inline void Call(
+ const float* input1_data, RuntimeShape in1_shape,
+ const float* input2_data, RuntimeShape in2_shape,
+ float* output_data, RuntimeShape out_shape,
+ bool needsBroadcast) {
+ if (needsBroadcast) {
+ BroadcastBinaryFunction4DSlow<float, float, float>(
+ in1_shape, input1_data,
+ in2_shape, input2_data,
+ out_shape, output_data,
+ [](float a, float b) { return a - b; }
+ );
+ } else {
+ Sub_(input1_data, input2_data, output_data, out_shape.FlatSize());
+ }
+ }
+};
+
struct Add {
static inline void Add_(const float* input1_data, const float* input2_data,
float* output_data, const int size) {
output = output.cwiseQuotient(MapAsVector(input2_data, out_shape.FlatSize()));
}
}
-};
\ No newline at end of file
+};
RuntimeShape out_shape = shapeToRuntimeShape(out_s);
+ assert(strides.getDims() == 2);
const short stride_w = strides[1];
const short stride_h = strides[0];
- assert(strides[2] == 1);
+ assert(pads.getDims() == 2);
const short pad_w = pads[1];
const short pad_h = pads[0];
BOOL = 6,
INT16 = 7,
COMPLEX64 = 8,
+ INT8 = 9,
}
-// Parameters for converting a quantized tensor back to float. Given a
-// quantized value q, the corresponding float value f should be:
-// f = scale * (q - zero_point)
+// Custom quantization parameters for experimenting with new quantization
+// techniques.
+table CustomQuantization {
+ custom:[ubyte] (force_align: 16);
+}
+
+// Represents a specific quantization technique's parameters.
+union QuantizationDetails {
+ CustomQuantization,
+}
+
+// Parameters for converting a quantized tensor back to float.
table QuantizationParameters {
+ // These four parameters are the asymmetric linear quantization parameters.
+ // Given a quantized value q, the corresponding float value f should be:
+ // f = scale * (q - zero_point)
+ // For other quantization types, the QuantizationDetails below is used.
min:[float]; // For importing back into tensorflow.
max:[float]; // For importing back into tensorflow.
scale:[float]; // For dequantizing the tensor's values.
zero_point:[long];
+
+ // If this is not none, the quantization parameters above are ignored and the
+ // value of the QuantizationDetails union below should be used.
+ details:QuantizationDetails;
}
table Tensor {
FLOOR_MOD = 95,
RANGE = 96,
RESIZE_NEAREST_NEIGHBOR = 97,
+ LEAKY_RELU = 98,
+ SQUARED_DIFFERENCE = 99,
+ MIRROR_PAD = 100,
+ ABS = 101,
+ SPLIT_V = 102,
}
// Options for the builtin operators.
FloorModOptions,
RangeOptions,
ResizeNearestNeighborOptions,
+ LeakyReluOptions,
+ SquaredDifferenceOptions,
+ MirrorPadOptions,
+ AbsOptions,
+ SplitVOptions,
}
enum Padding : byte { SAME, VALID }
num_splits: int;
}
+table SplitVOptions {
+ num_splits: int;
+}
+
table StridedSliceOptions {
begin_mask: int;
end_mask: int;
axis:int;
}
+table AbsOptions {
+}
+
+
table LogicalAndOptions {
}
table RangeOptions {
}
+table LeakyReluOptions {
+ alpha:float;
+}
+
+table SquaredDifferenceOptions {
+}
+
+enum MirrorPadMode : byte {
+ // Doesn't include borders.
+ REFLECT = 0,
+ // Includes borders.
+ SYMMETRIC = 1,
+}
+
+table MirrorPadOptions {
+ mode:MirrorPadMode;
+}
+
// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a
// builtin, or a string if the operator is custom.
table OperatorCode {
metadata_buffer:[int];
}
-root_type Model;
+root_type Model;
\ No newline at end of file
REPO=https://github.com/tensorflow/tensorflow.git
-COMMIT=61c6c84
+COMMIT=49123b0
#include "schema_generated.h"
#include "tflite_importer.h"
+#include "core/modelIR/operations/ElementwiseOp.h"
#include "tflite_op_creator.h"
using namespace ::tflite;
case BuiltinOperator_SQRT:
case BuiltinOperator_PAD:
case BuiltinOperator_ADD:
+ case BuiltinOperator_SUB:
+ case BuiltinOperator_SQUARED_DIFFERENCE:
case BuiltinOperator_MUL:
case BuiltinOperator_MEAN:
case BuiltinOperator_MAXIMUM:
outputs = _opCreator->convertConv2D(inputs, params, op->builtin_options_as<Conv2DOptions>());
break;
case BuiltinOperator_DEPTHWISE_CONV_2D:
- outputs = _opCreator->convertDepthwiseConv2D(inputs, params,
- op->builtin_options_as<DepthwiseConv2DOptions>());
+ outputs = _opCreator->convertDepthwiseConv2D(
+ inputs, params,
+ op->builtin_options_as<DepthwiseConv2DOptions>());
break;
case BuiltinOperator_MAX_POOL_2D:
outputs = _opCreator->convertMaxPool2D(inputs, params,
outputs = _opCreator->createSqrt(inputs, params);
break;
case BuiltinOperator_ADD:
- outputs = _opCreator->createAdd(inputs, params, op->builtin_options_as<AddOptions>());
+ outputs = _opCreator->createElementwise(
+ inputs, params, ops::ElementwiseOp::OpType::add,
+ op->builtin_options_as_AddOptions()->fused_activation_function());
break;
case BuiltinOperator_MUL:
- outputs = _opCreator->createMul(inputs, params, op->builtin_options_as<MulOptions>());
+ outputs = _opCreator->createElementwise(
+ inputs, params, ops::ElementwiseOp::OpType::mul,
+ op->builtin_options_as_MulOptions()->fused_activation_function());
break;
case BuiltinOperator_DIV:
- outputs = _opCreator->createDiv(inputs, params, op->builtin_options_as<DivOptions>());
+ outputs = _opCreator->createElementwise(
+ inputs, params, ops::ElementwiseOp::OpType::div,
+ op->builtin_options_as_DivOptions()->fused_activation_function());
break;
case BuiltinOperator_MAXIMUM:
- outputs = _opCreator->createMax(
- inputs, params, op->builtin_options_as<MaximumMinimumOptions>());
+ outputs = _opCreator->createElementwise(
+ inputs, params, ops::ElementwiseOp::OpType::max,
+ ActivationFunctionType_NONE); // no activation
+ break;
+ case BuiltinOperator_SUB:
+ outputs = _opCreator->createElementwise(
+ inputs, params, ops::ElementwiseOp::OpType::sub,
+ op->builtin_options_as_SubOptions()->fused_activation_function());
+ break;
+ case BuiltinOperator_SQUARED_DIFFERENCE:
+ outputs = _opCreator->createSquaredDifference(inputs, params); // no activation
break;
case BuiltinOperator_TRANSPOSE_CONV:
outputs = _opCreator->createTransposeConv(
std::vector<mir::Operation*>
TFLiteOpCreator::createTransposeConv(InputOps& inputs, const InputParams& params,
const ::tflite::TransposeConvOptions* opts) {
- Shape strides{opts->stride_h(), opts->stride_w(), 1};
+ Shape strides{opts->stride_h(), opts->stride_w()};
return createOp<ops::DeConv2DOp>(ActivationFunctionType_NONE, inputs[0]->getOutput(0), params[1],
strides, paddingMap[opts->padding()]);
}
}
std::vector<mir::Operation*>
-TFLiteOpCreator::createAdd(InputOps& inputs, const InputParams& params,
- const ::tflite::AddOptions* opts) {
+TFLiteOpCreator::createElementwise(const InputOps& inputs, const InputParams& params,
+ ops::ElementwiseOp::OpType opType,
+ const ::tflite::ActivationFunctionType activation) {
std::vector<IODescriptor> descriptors;
for (auto i : inputs)
auto weights_tensor = createOp<ops::ConstantOp>(ActivationFunctionType_NONE, param);
descriptors.push_back(weights_tensor[0]->getOutput(0));
}
-
- return createOp<ops::ElementwiseOp>(opts->fused_activation_function(), descriptors,
- ops::ElementwiseOp::OpType::add);
+ return createOp<ops::ElementwiseOp>(activation, descriptors, opType);
}
std::vector<mir::Operation*>
-TFLiteOpCreator::createMul(InputOps& inputs, const InputParams& params,
- const ::tflite::MulOptions* opts) {
+TFLiteOpCreator::createSquaredDifference(const InputOps& inputs, const InputParams& params) {
std::vector<IODescriptor> descriptors;
for (auto i : inputs)
descriptors.push_back(weights_tensor[0]->getOutput(0));
}
- return createOp<ops::ElementwiseOp>(opts->fused_activation_function(), descriptors,
- ops::ElementwiseOp::OpType::mul);
-}
+ auto sub_result = createOp<ops::ElementwiseOp>(ActivationFunctionType_NONE, descriptors,
+ ops::ElementwiseOp::OpType::sub);
-std::vector<mir::Operation*>
-TFLiteOpCreator::createDiv(InputOps& inputs, const InputParams&,
- const ::tflite::DivOptions* opts) {
- std::vector<IODescriptor> descriptors;
- for (auto i : inputs)
- descriptors.push_back(i->getOutput(0));
- return createOp<ops::ElementwiseOp>(opts->fused_activation_function(), descriptors,
- ops::ElementwiseOp::OpType::div);
-}
-
-std::vector<mir::Operation*>
-TFLiteOpCreator::createMax(InputOps& inputs, const InputParams&,
- const ::tflite::MaximumMinimumOptions* opts) {
- std::vector<IODescriptor> descriptors;
- for (auto i : inputs)
- descriptors.push_back(i->getOutput(0));
- return createOp<ops::ElementwiseOp>(ActivationFunctionType_NONE, descriptors,
- ops::ElementwiseOp::OpType::max);
+ return createOp<ops::ElementwiseOp>(ActivationFunctionType_NONE,
+ std::vector<IODescriptor>{sub_result[0]->getOutput(0),
+ sub_result[0]->getOutput(0)},
+ ops::ElementwiseOp::OpType::mul);
}
std::vector<mir::Operation*>
#include "core/modelIR/operations/CommonProps.h"
#include "core/modelIR/operations/ReduceFOp.h"
+#include "core/modelIR/operations/ElementwiseOp.h"
#include "schema_generated.h"
#include "passes/common_frontend/shape_helper.h"
std::vector<mir::Operation*> createSqueeze(InputOps& inputs, const InputParams& params,
const ::tflite::SqueezeOptions* opts);
- /** @brief Elementwise Add */
- std::vector<mir::Operation*> createAdd(InputOps&, const InputParams&,
- const ::tflite::AddOptions*);
- /** @brief Elementwise product */
- std::vector<mir::Operation*> createMul(InputOps&, const InputParams&,
- const ::tflite::MulOptions*);
- /** @brief Elementwise maximum */
- std::vector<mir::Operation*> createMax(InputOps&, const InputParams&,
- const ::tflite::MaximumMinimumOptions*);
- /** @brief Elementwise division */
- std::vector<mir::Operation*> createDiv(InputOps&, const InputParams&,
- const ::tflite::DivOptions*);
+ /** @brief Elementwise Operation */
+ std::vector<mir::Operation*> createElementwise(
+ const InputOps&, const InputParams&, ops::ElementwiseOp::OpType opType,
+ const ::tflite::ActivationFunctionType);
+
+ std::vector<mir::Operation*> createSquaredDifference(const InputOps&, const InputParams&);
/// @brief Free-standing ( non-fused ) activation function based on tflite activation
std::vector<mir::Operation*> createActivation(InputOps&, const InputParams&,
}
}
+TEST(cpp_operations_test, sub3) {
+ for (int num_dims = 2; num_dims <= 4; ++num_dims) {
+ // test prerequisites
+ vector<int> shape_data{2, 3, 5, 7};
+ shape_data.resize(num_dims);
+ vector<Tensor> input_atensors(3);
+ vector<unique_ptr<mir::TensorVariant>> input_n_tensors(3);
+ fillTensors(input_n_tensors[0], input_atensors[0], shape_data, 1.0f);
+ fillTensors(input_n_tensors[1], input_atensors[1], shape_data, 2.0f);
+ fillTensors(input_n_tensors[2], input_atensors[2], shape_data, 3.0f);
+ auto opGenerator = [](mir::Graph& g, const std::vector<mir::IODescriptor>& inputs) {
+ return g.create<mir::ops::ElementwiseOp>("y", inputs,
+ mir::ops::ElementwiseOp::OpType::sub);
+ };
+
+ createAndRunTestGraph(opGenerator, ElementWise<Sub, Tensor, Tensor, Tensor>, input_n_tensors,
+ input_atensors[0],
+ input_atensors[1],
+ input_atensors[2]);
+ }
+}
+
TEST(cpp_operations_test, mul3) {
for (int num_dims = 2; num_dims <= 4; ++num_dims) {
// test prerequisites
for (iT stride_w = 1; stride_w <= 3; ++stride_w) {
vector<int> input_shape_data{3, 9, 3, static_cast<int>(input_c)}; // NHWC
mir::Shape kernel_shape{kernel_h, kernel_w, output_c, input_c};
- mir::Shape strides{stride_h, stride_w, 1};
+ mir::Shape strides{stride_h, stride_w};
vector<unique_ptr<mir::TensorVariant>> input_ntensors(1);
Tensor input_atensor;
fillTensors(input_ntensors[0], input_atensor, input_shape_data, 1.0f);
TEST(cpp_operations_test, elu) {
// test prerequisites
vector<int> shape_data{2, 3, 4, 5};
- Tensor a_input_tensor;
+ Tensor input_atensor;
vector<unique_ptr<mir::TensorVariant>> input_ntensors(1);
- fillTensors(input_ntensors[0], a_input_tensor, shape_data, 1.0f);
+ fillTensors(input_ntensors[0], input_atensor, shape_data, 1.0f);
auto op_generator = [](mir::Graph& g, const std::vector<mir::IODescriptor>& inputs) {
return g.create<mir::ops::EluOp>("y", inputs[0], 1);
};
- createAndRunTestGraph(op_generator, elu, input_ntensors, a_input_tensor);
+ createAndRunTestGraph(op_generator, elu, input_ntensors, input_atensor);
}
TEST(cpp_operations_test, tanh) {
// test prerequisites
vector<int> shape_data{2, 3, 4, 5};
- Tensor a_input_tensor;
+ Tensor input_atensor;
vector<unique_ptr<mir::TensorVariant>> input_ntensors(1);
- fillTensors(input_ntensors[0], a_input_tensor, shape_data, 1.0f);
+ fillTensors(input_ntensors[0], input_atensor, shape_data, 1.0f);
auto op_generator = [](mir::Graph& g, const std::vector<mir::IODescriptor>& inputs) {
return g.create<mir::ops::TanhOp>("y", inputs[0]);
};
- createAndRunTestGraph(op_generator, tanhActivation, input_ntensors, a_input_tensor);
+ createAndRunTestGraph(op_generator, tanhActivation, input_ntensors, input_atensor);
}
TEST(cpp_operations_test, reduceMeanTst) {
for (const vector<int>& axis_list: test_axis_list) {
for (const bool keep_dims: {true, false}) {
vector<int> input_shape_data{2, 3, 4, 5};
- Tensor a_input_tensor;
+ Tensor input_atensor;
vector<unique_ptr<mir::TensorVariant>> input_ntensors(1);
- fillTensors(input_ntensors[0], a_input_tensor, input_shape_data, 1.0f);
+ fillTensors(input_ntensors[0], input_atensor, input_shape_data, 1.0f);
auto op_generator = [axis_list, keep_dims](mir::Graph& g,
const std::vector<mir::IODescriptor>& inputs) {
auto op = g.create<mir::ops::ReduceFOp>(
return op;
};
- createAndRunTestGraph(op_generator, reduceMean, input_ntensors, a_input_tensor);
+ createAndRunTestGraph(op_generator, reduceMean, input_ntensors, input_atensor);
}
}
}
};
for (auto st : starts) {
for (auto sz : sizes) {
- Tensor a_input_tensor;
+ Tensor input_atensor;
vector<unique_ptr<mir::TensorVariant>> input_n_tensor(1);
- fillTensors(input_n_tensor[0], a_input_tensor, shape_data, 1.0f);
+ fillTensors(input_n_tensor[0], input_atensor, shape_data, 1.0f);
auto op_gen = [&st, &sz](mir::Graph& g, const std::vector<mir::IODescriptor>& inputs) {
return g.create<mir::ops::SliceOp>("y", inputs[0], mir::Shape(st),
mir::Shape(sz));
};
- createAndRunTestGraph(op_gen, slice, input_n_tensor, a_input_tensor);
+ createAndRunTestGraph(op_gen, slice, input_n_tensor, input_atensor);
}
}
}
out = sess.run(out0, feed_dict = {"input:0": np.ones((1, 28, 28, 1)).astype(np.float32)})
frozen_graphdef = tf.graph_util.convert_variables_to_constants(
sess, sess.graph_def, ["out"])
- tflite_model = tf.contrib.lite.TocoConverter(
- frozen_graphdef, [X], [out0]).convert()
+ converter = tf.contrib.lite.TocoConverter.from_session(sess, [X], [out0])
+ tflite_model = converter.convert()
open(resDir+"unsupported.tflite", "wb").write(tflite_model)
-#include "passes/tflite_frontend/tflite_importer.h"
+#include "tflite_importer.h"
#include "gtest/gtest.h"
#include "pass/PassException.h"
#include <string>