Commit b6c98de1 authored by Matthew Brookhart's avatar Matthew Brookhart Committed by Robert Kimball

Numerically stable sum so we can pass mxnet unit tests (#381)

* Numerically stable sum so we can pass mxnet unit tests

* Add a small initial residual
parent c5549682
......@@ -303,12 +303,15 @@ void ngraph::runtime::cpu::kernel::emit_sum(codegen::CodeWriter& writer,
if (out_shape.size() == 0)
{
writer << dest_nd_name << " = 0;\n";
writer << element_type << " residual = 0;\n";
}
else
{
writer << element_type << " residual" << emit_bracketed_string(out_shape) << ";\n";
auto output_vars = open_for_loops(writer, out_shape);
writer << dest_nd_name << emit_bracketed_string(output_vars) << " = 0;\n";
writer << "residual" << emit_bracketed_string(output_vars) << " = 1e-8;\n";
close_for_loops(writer, output_vars);
}
......@@ -357,10 +360,13 @@ void ngraph::runtime::cpu::kernel::emit_sum(codegen::CodeWriter& writer,
writer.indent++;
}
}
writer << dest_nd_name << emit_bracketed_string(out_indexes) << " += " << source_nd_name
<< emit_bracketed_string(index_vars) << ";\n";
auto out_brackets = emit_bracketed_string(out_indexes);
auto dst = dest_nd_name + out_brackets;
auto src = source_nd_name + emit_bracketed_string(index_vars);
writer << element_type << " y = " << src << " - residual" << out_brackets << ";\n";
writer << element_type << " t = " << dst << " + y;\n";
writer << "residual" << out_brackets << " = (t - " << dst << ") - y;\n";
writer << dst << " = t;\n";
close_for_loops(writer, index_vars);
}
}
......
......@@ -3257,6 +3257,50 @@ TEST(${BACKEND_NAME}, sum_3d_eliminate_zero_dim)
EXPECT_EQ((vector<float>{0, 0, 0, 0, 0, 0}), result->get_vector<float>());
}
TEST(${BACKEND_NAME}, sum_to_scalar_stable)
{
auto shape = Shape{2, 2};
auto A = make_shared<op::Parameter>(element::f32, shape);
auto f = make_shared<Function>(make_shared<op::Sum>(A, AxisSet{0, 1}), op::Parameters{A});
auto manager = runtime::Manager::get("${BACKEND_NAME}");
auto external = manager->compile(f);
auto backend = manager->allocate_backend();
auto cf = backend->make_call_frame(external);
// Create some tensors for input/output
auto a = backend->make_primary_tensor_view(element::f32, shape);
copy_data(a, vector<float>{1e-6, -1, 0, 1});
auto result = backend->make_primary_tensor_view(element::f32, Shape{});
cf->call({a}, {result});
EXPECT_TRUE(test::all_close(result->get_vector<float>(), vector<float>{1e-6}, 5e-2f));
// EXPECT_EQ(vector<float>{1e-6}, result->get_vector<float>());
}
TEST(${BACKEND_NAME}, sum_3d_to_vector_stable)
{
auto shape_a = Shape{3, 3, 3};
auto A = make_shared<op::Parameter>(element::f32, shape_a);
auto shape_rt = Shape{3};
auto f = make_shared<Function>(make_shared<op::Sum>(A, AxisSet{0, 1}), op::Parameters{A});
auto manager = runtime::Manager::get("${BACKEND_NAME}");
auto external = manager->compile(f);
auto backend = manager->allocate_backend();
auto cf = backend->make_call_frame(external);
// Create some tensors for input/output
auto a = backend->make_primary_tensor_view(element::f32, shape_a);
copy_data(a, vector<float>{1, 1, 1, 1, 1, 1, 1e-4, 1e-5, 1e-6, 1, 1, 1, 1, 1,
1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1});
auto result = backend->make_primary_tensor_view(element::f32, shape_rt);
cf->call({a}, {result});
EXPECT_TRUE(
test::all_close(result->get_vector<float>(), vector<float>{1e-4, 1e-5, 1e-6}, 5e-2f));
}
TEST(${BACKEND_NAME}, sign)
{
auto shape = Shape{2, 3};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment