Promote to ONNX commit that has StringNormalizer (#499)

Promote to ONNX commit that has StringNormalizer
  Adjust implementation to match ONNX spec.
  Remove test exclusions.
  Override BackendTest class to handle strings  comparision
  properly until this is fixed in ONNX.
  Restore test_gru_seq_length_cpu exclusion
This commit is contained in:
Dmitri Smirnov 2019-03-08 17:15:26 -08:00 committed by GitHub
parent 530748ad5c
commit 6136efc0c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 107 deletions

View file

@ -16,7 +16,6 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1,
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, DequantizeLinear);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int8_t, DequantizeLinear);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, QuantizeLinear);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, string, StringNormalizer);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, NonMaxSuppression);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, Range);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, WordConvEmbedding);
@ -43,7 +42,6 @@ void RegisterContribKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, DequantizeLinear)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int8_t, DequantizeLinear)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, QuantizeLinear)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, string, StringNormalizer)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, float, NonMaxSuppression)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, Range)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, WordConvEmbedding)>());

View file

@ -1089,39 +1089,6 @@ The bounding box coordinates corresponding to the selected indices can then be o
updateOutputShape(ctx, 0, input_shape);
});
ONNX_CONTRIB_OPERATOR_SCHEMA(StringNormalizer)
.SetDomain(kMSDomain)
.SinceVersion(1)
.Input(0, "X", "Strings to normalize", "T")
.Output(0, "Y", "Normalized strings", "T")
.TypeConstraint(
"T",
{"tensor(string)"},
"Input/Output is a string tensor")
.Attr(
"casechangeaction",
"string enum that cases output to be lowercased/uppercases/unchanged. Valid values are \"LOWER\", \"UPPER\", \"NONE\"",
AttributeProto::STRING)
.Attr(
"is_case_sensitive",
"Boolean. Whether the identification of stop words in X is case-sensitive.",
AttributeProto::INT)
.Attr(
"stopwords",
"List of stop words",
AttributeProto::STRINGS,
OPTIONAL)
.Attr(
"locale",
"Environment dependent string that denotes the locale according to which output strings needs to be upper/lowercased. Default en_US",
AttributeProto::STRING,
OPTIONAL)
.TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) {
auto output_elem_type = ctx.getOutputType(0)->mutable_tensor_type();
output_elem_type->set_elem_type(ONNX_NAMESPACE::TensorProto::STRING);
})
.SetDoc(R"DOC([optional] Step1: Remove elements in X if they match any of the stop words so that the output tensor will not contain any stop words. This operator only accepts [C]- and [1, C]-tensors. If all elements in X are dropped, the output will be the default value of string tensor with shape [1] if input shape is [C] and shape [1, 1] if input shape is [1, C].)DOC");
ONNX_CONTRIB_OPERATOR_SCHEMA(GatherND)
.SetDomain(kMSDomain)
.SinceVersion(1)

View file

@ -269,6 +269,9 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain,
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, string, Where);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, float, Where);
// Opset 10
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, StringNormalizer);
void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 6, Clip)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 6, Elu)>());
@ -529,6 +532,9 @@ void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, int64_t, NonZero)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, string, Where)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, float, Where)>());
// Opset 10
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, StringNormalizer)>());
}
// Forward declarations of ml op kernels

View file

@ -16,15 +16,13 @@
#include <unordered_set>
namespace onnxruntime {
namespace contrib {
ONNX_CPU_OPERATOR_TYPED_MS_KERNEL(
ONNX_CPU_OPERATOR_KERNEL(
StringNormalizer,
1,
string,
10,
KernelDefBuilder()
.TypeConstraint("T", DataTypeImpl::GetTensorType<std::string>()),
contrib::StringNormalizer);
StringNormalizer);
namespace string_normalizer {
const std::string conv_error("Conversion Error");
@ -157,29 +155,29 @@ using namespace string_normalizer;
StringNormalizer::StringNormalizer(const OpKernelInfo& info) : OpKernel(info),
is_case_sensitive_(true),
casechangeaction_(NONE),
case_change_action_(NONE),
compare_caseaction_(NONE) {
int64_t iscasesensitive = 0;
Status status = info.GetAttr("is_case_sensitive", &iscasesensitive);
ORT_ENFORCE(status.IsOK(), "attribute is_case_sensitive is not set");
is_case_sensitive_ = iscasesensitive != 0;
std::string casechangeaction;
status = info.GetAttr("casechangeaction", &casechangeaction);
ORT_ENFORCE(status.IsOK(), "attribute caseaction is not set");
if (casechangeaction == "LOWER") {
casechangeaction_ = LOWER;
} else if (casechangeaction == "UPPER") {
casechangeaction_ = UPPER;
} else if (casechangeaction == "NONE") {
casechangeaction_ = NONE;
std::string case_change_action;
status = info.GetAttr("case_change_action", &case_change_action);
ORT_ENFORCE(status.IsOK(), "attribute case_change_action is not set");
if (case_change_action == "LOWER") {
case_change_action_ = LOWER;
} else if (case_change_action == "UPPER") {
case_change_action_ = UPPER;
} else if (case_change_action == "NONE") {
case_change_action_ = NONE;
} else {
ORT_ENFORCE(false, "attribute casechangeaction has invalid value");
ORT_ENFORCE(false, "attribute case_change_action has invalid value");
}
if (!is_case_sensitive_) {
// Convert stop words to a case which can help us preserve the case of filtered strings
compare_caseaction_ = (casechangeaction_ == UPPER) ? UPPER : LOWER;
compare_caseaction_ = (case_change_action_ == UPPER) ? UPPER : LOWER;
}
locale_name_ = info.GetAttrOrDefault("locale", default_locale);
@ -248,10 +246,10 @@ Status StringNormalizer::Compute(OpKernelContext* ctx) const {
++first;
}
status = CopyCaseAction(filtered_strings.cbegin(), filtered_strings.cend(), ctx, locale, converter,
N, filtered_strings.size(), casechangeaction_);
N, filtered_strings.size(), case_change_action_);
} else {
// Nothing to filter. Copy input to output and change case if needed
status = CopyCaseAction(input_data, input_data + C, ctx, locale, converter, N, C, casechangeaction_);
status = CopyCaseAction(input_data, input_data + C, ctx, locale, converter, N, C, case_change_action_);
}
} else {
if (!wstopwords_.empty()) {
@ -273,7 +271,7 @@ Status StringNormalizer::Compute(OpKernelContext* ctx) const {
}
locale.ChangeCase(compare_caseaction_, wstr);
if (0 == wstopwords_.count(wstr)) {
if (casechangeaction_ == NONE) {
if (case_change_action_ == NONE) {
filtered_orignal_strings.push_back(std::cref(s));
} else {
filtered_cased_strings.push_back(converter.to_bytes(wstr));
@ -281,7 +279,7 @@ Status StringNormalizer::Compute(OpKernelContext* ctx) const {
}
++first;
}
if (casechangeaction_ == NONE) {
if (case_change_action_ == NONE) {
status = CopyCaseAction(filtered_orignal_strings.cbegin(), filtered_orignal_strings.cend(), ctx, locale, converter,
N, filtered_orignal_strings.size(), NONE);
} else {
@ -290,10 +288,9 @@ Status StringNormalizer::Compute(OpKernelContext* ctx) const {
}
} else {
// Nothing to filter. Copy input to output and change case if needed
status = CopyCaseAction(input_data, input_data + C, ctx, locale, converter, N, C, casechangeaction_);
status = CopyCaseAction(input_data, input_data + C, ctx, locale, converter, N, C, case_change_action_);
}
}
return status;
}
} // namespace contrib
} // namespace onnxruntime

View file

@ -10,7 +10,6 @@
#include <unordered_set>
namespace onnxruntime {
namespace contrib {
class StringNormalizer : public OpKernel {
public:
@ -27,7 +26,7 @@ class StringNormalizer : public OpKernel {
private:
bool is_case_sensitive_;
CaseAction casechangeaction_;
CaseAction case_change_action_;
CaseAction compare_caseaction_; // used for case-insensitive compare
std::string locale_name_;
// Either if these are populated but not both
@ -35,5 +34,4 @@ class StringNormalizer : public OpKernel {
std::unordered_set<std::wstring> wstopwords_;
};
} // namespace contrib
} // namespace onnxruntime

View file

@ -301,18 +301,6 @@ int real_main(int argc, char* argv[], OrtEnv** p_env) {
{"atanh_example", "opset 9 not supported yet"},
{"scan_sum", "opset 9 not supported yet"},
{"shrink", "opset 9 not supported yet"},
{"strnormalizer_export_monday_casesensintive_lower", "opset 10 not supported yet"},
{"strnormalizer_export_monday_casesensintive_nochangecase", "opset 10 not supported yet"},
{"strnormalizer_export_monday_casesensintive_upper", "opset 10 not supported yet"},
{"strnormalizer_export_monday_empty_output", "opset 10 not supported yet"},
{"strnormalizer_export_monday_insensintive_upper_twodim", "opset 10 not supported yet"},
{"strnormalizer_nostopwords_nochangecase", "opset 10 not supported yet"},
{"strnorm_model_monday_casesensintive_lower", "opset 10 not supported yet"},
{"strnorm_model_monday_casesensintive_nochangecase", "opset 10 not supported yet"},
{"strnorm_model_monday_casesensintive_upper", "opset 10 not supported yet"},
{"strnorm_model_monday_empty_output", "opset 10 not supported yet"},
{"strnorm_model_monday_insensintive_upper_twodim", "opset 10 not supported yet"},
{"strnorm_model_nostopwords_nochangecase", "opset 10 not supported yet"},
{"cast_DOUBLE_to_FLOAT16", "Cast opset 9 not supported yet"},
{"cast_DOUBLE_to_FLOAT", "Cast opset 9 not supported yet"},
{"cast_FLOAT_to_DOUBLE", "Cast opset 9 not supported yet"},

View file

@ -9,8 +9,8 @@ namespace onnxruntime {
namespace test {
namespace str_normalizer_test {
constexpr const char* domain = onnxruntime::kMSDomain;
const int opset_ver = 1;
constexpr const char* domain = kOnnxDomain;
const int opset_ver = 10;
#ifdef _MSC_VER
const std::string test_locale("en-US");
@ -18,12 +18,14 @@ const std::string test_locale("en-US");
const std::string test_locale("en_US.UTF-8");
#endif
void InitTestAttr(OpTester& test, const std::string& casechangeaction,
bool iscasesensitive,
void InitTestAttr(OpTester& test, const std::string& case_change_action,
bool is_case_sensitive,
const std::vector<std::string>& stopwords,
const std::string& locale) {
test.AddAttribute("casechangeaction", casechangeaction);
test.AddAttribute("is_case_sensitive", int64_t{iscasesensitive});
if (!case_change_action.empty()) {
test.AddAttribute("case_change_action", case_change_action);
}
test.AddAttribute("is_case_sensitive", int64_t{is_case_sensitive});
if (!stopwords.empty()) {
test.AddAttribute("stopwords", stopwords);
}
@ -36,27 +38,12 @@ void InitTestAttr(OpTester& test, const std::string& casechangeaction,
using namespace str_normalizer_test;
TEST(ContribOpTest, StringNormalizerTest) {
// Test wrong 2 dimensions
// - casesensitive approach
// - no stopwords.
// - No change case action
// - No change case action, expecting default to take over
{
OpTester test("StringNormalizer", opset_ver, domain);
InitTestAttr(test, "NONE", true, {}, test_locale);
std::vector<int64_t> dims{2, 2};
std::vector<std::string> input = {std::string("monday"), std::string("tuesday"), std::string("wednesday"), std::string("thursday")};
test.AddInput<std::string>("T", dims, input);
std::vector<std::string> output(input); // do the same for now
test.AddOutput<std::string>("Y", dims, output);
test.Run(OpTester::ExpectResult::kExpectFailure, "Input dimensions are either[C > 0] or [1][C > 0] allowed");
}
// - casesensitive approach
// - no stopwords.
// - No change case action
{
OpTester test("StringNormalizer", opset_ver, domain);
InitTestAttr(test, "NONE", true, {}, test_locale);
InitTestAttr(test, "", true, {}, test_locale);
std::vector<int64_t> dims{4};
std::vector<std::string> input = {std::string("monday"), std::string("tuesday"),
std::string("wednesday"), std::string("thursday")};

View file

@ -6,29 +6,39 @@ import os
import unittest
import onnx.backend.test
import numpy as np
import onnxruntime.backend as c2
pytest_plugins = 'onnx.backend.test.report',
class OrtBackendTest(onnx.backend.test.BackendTest):
class OnnxruntimeBackendTest(onnx.backend.test.BackendTest):
def __init__(self, backend, parent_module=None):
super(OrtBackendTest, self).__init__(backend, parent_module)
def __init__(self, backend, parent_module=None):
onnx.backend.test.BackendTest.__init__(self, backend, parent_module)
@classmethod
def assert_similar_outputs(cls, ref_outputs, outputs, rtol, atol):
# type: (Sequence[Any], Sequence[Any], float, float) -> None
@classmethod
def assert_similar_outputs(cls, ref_outputs, outputs, rtol, atol):
np.testing.assert_equal(len(ref_outputs), len(outputs))
for i in range(len(outputs)):
np.testing.assert_equal(ref_outputs[i].dtype, outputs[i].dtype)
if ref_outputs[i].dtype == np.object:
np.testing.assert_array_equal(ref_outputs[i], outputs[i])
else:
np.testing.assert_allclose(
ref_outputs[i],
outputs[i],
rtol=rtol,
atol=atol)
# override the rtol and atol values to match onnx_test_runner tolerances
super(OrtBackendTest, cls).assert_similar_outputs(ref_outputs, outputs, 1e-3, 1e-5)
backend_test = OrtBackendTest(c2, __name__)
backend_test = OnnxruntimeBackendTest(c2, __name__)
# Type not supported
backend_test.exclude(r'(FLOAT16)')
backend_test.exclude(r'('
'^test_cast_DOUBLE_to_FLOAT_cpu.*'
'|^test_gru_seq_length_cpu.*'
'|^test_cast_FLOAT_to_DOUBLE_cpu.*'
'|^test_cast_FLOAT_to_STRING_cpu.*'
'|^test_cast_STRING_to_FLOAT_cpu.*'
@ -58,8 +68,6 @@ backend_test.exclude(r'('
'|^test_PReLU_3d_cpu.*'
'|^test_PReLU_3d_multiparam_cpu.*'
'|^test_PoissonNLLLLoss_no_reduce_cpu.*'
'|^test_strnormalizer_*.*'
'|^test_strnorm_*.*'
'|^test_Softsign_cpu.*'
'|^test_operator_add_broadcast_cpu.*'
'|^test_operator_add_size1_broadcast_cpu.*'