Skip to content

Commit

Permalink
Implement function retrieval APIs; Add documentation for functions (o…
Browse files Browse the repository at this point in the history
…nnx#1112)

* Add for test function build

* Add pybind functions for getFunction API

* Implement FC function testcase

* Lint code using clang-format

* Disable warning in covert protobuf::int64 to int

* Update doc generation scripts and functions doc

* Trimming some comments

* Fix doc generation scripts for typecheck

* Improve cmake scripts for unittest project dependencies and fix linux build issues

* Lint python code

* Update API to support functions with multiple versions

* Update line ending

* Add changelogs for functions

* Refactor and lint code

* Fix bad linebreaks in markdown files generated

* Resolve PR comments; Refine Function type check implementation

* Add checker for function version; Bump version in onnx_domain

* Update doc_string and generated md files

* Add helper function; Update documents for MVN function

* Fix a bug in MVN function definition

* Experimental: add python test case for MVN

* Update line ends

* Add attribute mvn testcase

* Update generated files on MVN function

* Rename buildnode function

* Remove node part in generated files; Reformat doc_string for MVN

* Fix changelog generation script

* Update MVN testcase to caculate expected output on the fly

* Rephrase description for MVN function

* Formatting docstring for MVN function

* Refactor helper function code; Add epsilon before division

* Move the helper functions into common folder

* Fix typo in function docstring

* Refactor model helper function; Add version check; Fix typo

* Switch to use FunctionProto class generated in python

* Remove unnecessary ignore flag

* Minor fix in c++ tests; Generated function docs for ML domain

* Refactor code to avoid hardcode domain name

* Resolve PR comments
  • Loading branch information
Raymond Yang authored and linkerzhang committed Jul 19, 2018
1 parent 5b9f9c1 commit 828d3c3
Show file tree
Hide file tree
Showing 16 changed files with 632 additions and 32 deletions.
4 changes: 2 additions & 2 deletions cmake/unittest.cmake
Expand Up @@ -19,10 +19,10 @@ set(${UT_NAME}_libs
${googletest_STATIC_LIBRARIES}
)

list(APPEND ${UT_NAME}_libs ${PROTOBUF_LIBRARIES})
list(APPEND ${UT_NAME}_libs onnx_proto)
add_whole_archive_flag(onnx tmp)
list(APPEND ${UT_NAME}_libs ${tmp})
list(APPEND ${UT_NAME}_libs onnx_proto)
list(APPEND ${UT_NAME}_libs ${PROTOBUF_LIBRARIES})

file(GLOB_RECURSE ${UT_NAME}_src
"${ONNX_ROOT}/onnx/test/c++/*.cc"
Expand Down
4 changes: 4 additions & 0 deletions docs/Functions-ml.md
@@ -0,0 +1,4 @@
## Functions
*This file is automatically generated from the
[def files](/onnx/defs) via [this script](/onnx/defs/gen_doc.py).
Do not modify directly and instead edit function definitions.*
36 changes: 36 additions & 0 deletions docs/Functions.md
@@ -0,0 +1,36 @@
## Functions
*This file is automatically generated from the
[def files](/onnx/defs) via [this script](/onnx/defs/gen_doc.py).
Do not modify directly and instead edit function definitions.*
## ai.onnx (default)
* <sub>experimental</sub><a href="#FuncMeanVarianceNormalization">FuncMeanVarianceNormalization</a>



### <sub>experimental</sub> <a name="FuncMeanVarianceNormalization"></a><a name="funcmeanvariancenormalization">**FuncMeanVarianceNormalization**</a>

A MeanVarianceNormalization Function: Perform mean variance normalization on the input tensor X using formula: <br/> ``` (X-EX)/sqrt(E(X-EX)^2) ``` <br/><br/><b>INPUT: </b>X(float/float16/double) with shape [N,C,W,H] or N-D shape <br/><br/><b>ATTRIBUTE: </b><br/>&nbsp;&nbsp;&nbsp;&nbsp;<tt>axes: </tt>will be passed to ReducedMean Ops. Use [0,2,3] (without C axis for N-D cases) for calculating means and variances along channels. Two variables with the same C-coordinate are associated with the same mean and variance. Use [0,1,2,3] (with C axis) to calculate global mean and global variance with all variables sharing the same mean/variance.<br/>&nbsp;&nbsp;&nbsp;&nbsp;(The KeepDims attribute in ReducedMean is set to true for calculation)<br/><br/><b>OUTPUT: </b>X_MVN(float/float16/double) with the same shape as input X<br/>

#### Version

This version of the function has been available since version 8 of the default ONNX operator set.

#### Inputs

<dl>
<dt>X; </dt>
<br/></dl>

#### Outputs

<dl>
<dt>X_MVN; </dt>
<br/></dl>

#### Attributes

<dl>
<dt>axes;<br/></dt>
</dl>


5 changes: 5 additions & 0 deletions docs/FunctionsChangelog-ml.md
@@ -0,0 +1,5 @@
## Function Changelog
*This file is automatically generated from the
[def files](/onnx/defs) via [this script](/onnx/defs/gen_doc.py).
Do not modify directly and instead edit function definitions.*
## ai.onnx.ml
32 changes: 32 additions & 0 deletions docs/FunctionsChangelog.md
@@ -0,0 +1,32 @@
## Function Changelog
*This file is automatically generated from the
[def files](/onnx/defs) via [this script](/onnx/defs/gen_doc.py).
Do not modify directly and instead edit function definitions.*
# ai.onnx (default)
## Version 8 of domain ai.onnx (default)
### <a name="FuncMeanVarianceNormalization-8"></a>**FuncMeanVarianceNormalization-8**</a>

A MeanVarianceNormalization Function: Perform mean variance normalization on the input tensor X using formula: <br/> ``` (X-EX)/sqrt(E(X-EX)^2) ``` <br/><br/><b>INPUT: </b>X(float/float16/double) with shape [N,C,W,H] or N-D shape <br/><br/><b>ATTRIBUTE: </b><br/>&nbsp;&nbsp;&nbsp;&nbsp;<tt>axes: </tt>will be passed to ReducedMean Ops. Use [0,2,3] (without C axis for N-D cases) for calculating means and variances along channels. Two variables with the same C-coordinate are associated with the same mean and variance. Use [0,1,2,3] (with C axis) to calculate global mean and global variance with all variables sharing the same mean/variance.<br/>&nbsp;&nbsp;&nbsp;&nbsp;(The KeepDims attribute in ReducedMean is set to true for calculation)<br/><br/><b>OUTPUT: </b>X_MVN(float/float16/double) with the same shape as input X<br/>

#### Version

This version of the function has been available since version 8 of the default ONNX operator set.

#### Inputs

<dl>
<dt>X; </dt>
<br/></dl>

#### Outputs

<dl>
<dt>X_MVN; </dt>
<br/></dl>

#### Attributes

<dl>
<dt>axes;<br/></dt>
</dl>

43 changes: 43 additions & 0 deletions onnx/backend/test/case/node/mvn.py
@@ -0,0 +1,43 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import numpy as np # type: ignore

import onnx
from ..base import Base
from . import expect


class MVN(Base):

@staticmethod
def export(): # type: () -> None
node = onnx.helper.make_node(
'FuncMeanVarianceNormalization',
inputs=['X'],
outputs=['Y'],
axes=[0, 2, 3]
)

input_data = np.array([[[[0.8439683], [0.5665144], [0.05836735]],
[[0.02916367], [0.12964272], [0.5060197]],
[[0.79538304], [0.9411346], [0.9546573]]],
[[[0.17730942], [0.46192095], [0.26480448]],
[[0.6746842], [0.01665257], [0.62473077]],
[[0.9240844], [0.9722341], [0.11965699]]],
[[[0.41356155], [0.9129373], [0.59330076]],
[[0.81929934], [0.7862604], [0.11799799]],
[[0.69248444], [0.54119414], [0.07513223]]]], dtype=np.float32)

# Calculate expected output data
data_mean = np.mean(input_data, axis=(0, 2, 3), keepdims=1)
data_mean_squared = np.power(data_mean, 2)
data_squared = np.power(input_data, 2)
data_squared_mean = np.mean(data_squared, axis=(0, 2, 3), keepdims=1)
std = np.sqrt(data_squared_mean - data_mean_squared)
expected_output = (input_data - data_mean) / (std + 1e-9)

expect(node, inputs=[input_data], outputs=[expected_output],
name='test_mvn')
39 changes: 39 additions & 0 deletions onnx/common/model_helpers.cc
@@ -0,0 +1,39 @@
// Copyright (c) Facebook Inc. and Microsoft Corporation.
// Licensed under the MIT license.

#include "onnx/common/model_helpers.h"
#include "onnx/checker.h"
#include "onnx/defs/schema.h"
#include "onnx/string_utils.h"

namespace ONNX_NAMESPACE {
using namespace Common;

Common::Status BuildNode(
const std::string& name,
const std::string& domain,
const std::string& doc_string,
const std::string& op_type,
std::vector<std::string> const& inputs,
std::vector<std::string> const& outputs,
NodeProto* node) {
if (node == NULL) {
return Status(
Common::CHECKER,
Common::INVALID_ARGUMENT,
"node_proto should not be nullptr.");
}
node->set_name(name);
node->set_domain(domain);
node->set_doc_string(doc_string);
node->set_op_type(op_type);
for (auto& input : inputs) {
node->add_input(input);
}
for (auto& output : outputs) {
node->add_output(output);
}

return Status::OK();
}
} // namespace ONNX_NAMESPACE
24 changes: 24 additions & 0 deletions onnx/common/model_helpers.h
@@ -0,0 +1,24 @@
// Copyright (c) Facebook Inc. and Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

#include <string>
#include <vector>
#include "onnx/common/status.h"
#include "onnx/onnx-operators_pb.h"

namespace ONNX_NAMESPACE {

// Helper function for register nodes in
// a FunctionProto. Attributes need to be
// registered separately.
Common::Status BuildNode(
const std::string& name,
const std::string& domain,
const std::string& doc_string,
const std::string& op_type,
std::vector<std::string> const& inputs,
std::vector<std::string> const& outputs,
/*OUT*/ NodeProto* node);
} // namespace ONNX_NAMESPACE
29 changes: 29 additions & 0 deletions onnx/cpp2py_export.cc
Expand Up @@ -5,6 +5,7 @@
#include <unordered_map>

#include "onnx/checker.h"
#include "onnx/defs/function.h"
#include "onnx/defs/schema.h"
#include "onnx/optimizer/optimize.h"
#include "onnx/py_utils.h"
Expand Down Expand Up @@ -146,6 +147,34 @@ PYBIND11_MODULE(onnx_cpp2py_export, onnx_cpp2py_export) {
return OpSchemaRegistry::get_all_schemas_with_history();
});

defs.def(
"get_all_functions",
[](const std::string& domain)
-> std::unordered_map<std::string, std::vector<py::bytes>> {
std::multimap<std::string, std::unique_ptr<FunctionProto>> temp_ptr_map;
std::unordered_map<std::string, std::vector<py::bytes>> temp_map;
FunctionBuilderRegistry& function_registry =
FunctionBuilderRegistry::OnnxInstance();

Common::Status status =
function_registry.GetFunctions(domain, &temp_ptr_map);
if (!status.IsOK()) {
throw std::runtime_error(
"Failed to retrieve function list for domain '" + domain + "'!");
}
for (auto iter = temp_ptr_map.begin(); iter != temp_ptr_map.end();
++iter) {
std::string bytes;
if (!iter->second->SerializeToString(&bytes)) {
throw std::runtime_error(
"Failed to serilize registered function for '" + iter->first +
"'!");
}
temp_map[iter->first].emplace_back(py::bytes(std::move(bytes)));
}
return temp_map;
});

// Submodule `checker`
auto checker = onnx_cpp2py_export.def_submodule("checker");
checker.doc() = "Checker submodule";
Expand Down
17 changes: 15 additions & 2 deletions onnx/defs/__init__.py
Expand Up @@ -3,12 +3,14 @@
from __future__ import print_function
from __future__ import unicode_literals

import onnx
from onnx import AttributeProto
from onnx import AttributeProto, FunctionProto
import onnx.onnx_cpp2py_export.defs as C

from collections import defaultdict
from typing import List, Dict

ONNX_DOMAIN = ""
ONNX_ML_DOMAIN = 'ai.onnx.ml'


has = C.has_schema
Expand All @@ -32,3 +34,14 @@ def _Attribute_default_value(self): # type: ignore


OpSchema.Attribute.default_value = _Attribute_default_value # type: ignore


def get_functions(domain=ONNX_DOMAIN): # type: ignore
function_map = defaultdict(list) # type: Dict[int, List[FunctionProto]]
function_byte_map = C.get_all_functions(domain) # type: ignore
for function_name, raw_functions in function_byte_map.items():
for function_bytes in raw_functions:
function_proto = FunctionProto()
function_proto.ParseFromString(function_bytes)
function_map[function_name].append(function_proto)
return function_map

0 comments on commit 828d3c3

Please sign in to comment.