Skip to content

Contribution Guideline

namizzz edited this page Jul 9, 2018 · 3 revisions

Contribution Guideline

Author: namizzz


How To Add Customized Operator

Two steps are listed below:

  • Implement original framework to IR part: get the attribute from the source_node and also add IR properties to IR node in the original framework parser file. more detail
  • Implement IR to destination framework part: get IR properties and generate the target code. more detail

How To Edit Parsers

When you make some changes:

  • Start with 'rename_' to add the new funtion to convert the new type source node to IR node
def rename_Dense(self, source_node):
    IR_node = self.IR_graph.node.add()
    _copy_and_reop(source_node, IR_node, new_op = None)
    convert_inedge(self, source_node, IR_node, start_idx = 0, end_idx = None)
    # pseudo code
  • Use 'assign_IRnode_values' to save the necessary parameters of the operation (eg. kernel_shape, strides, pads)
def rename_Conv2D(self, source_node):
    ......
    kwargs = {}
    kwargs['strides'] = source_node.get_attr('strides')
    W = self.tf_graph.get_node(source_node.layer.input[1])
    W = self.tf_graph.get_node(W.layer.input[0]).layer
    kwargs['kernel_shape'] = self.tensor_shape_to_list(W.attr['shape'])
    ......
    assign_IRnode_values(IR_node, kwargs)
  • Use 'set_weight' to save the pretrained parameters of the layer (eg. kernel matrix, mean matrix, bias matrix)
def __init__(self, meta_file, checkpoint_file, frozen_file, dest_nodes = None):
    ......
    if checkpoint_file:
        self.ckpt_data = TensorflowParser._load_weights(checkpoint_file)
        self.weight_loaded = True

......

def rename_Conv2D(self, source_node):
    ......
    if self.weight_loaded:
        self.set_weight(source_node.name, 'weights', self.ckpt_data[W.name])

After you make some changes:

  • Run the related test functions to ensure correctness after your changes using
$ python -m pytest -v -s ./test/test_conversion_imagenet.py

How To Edit Emitters

When you make some changes:

  • Start with 'emit_' to add the new funtion to convert the new type IR node to model code(eg. else) or model components(eg. CoreML)
def emit_Dropout(self, IR_node):
    parent = self.IR_graph.get_parent(IR_node.name, [0])
    self.add_body(...)
  • Follow the order in 'gen_code' function of every emitter file to use 'add_body' to generate the code of the operations or add some model layers to the 'base builder'(eg. self.builder in coreml_emitter)
def add_body(self, indent, codes):
    if isinstance(codes, _string_types):
        codes = [codes]
    for code in codes:
        self.body_code += ("    " * indent) + code + '\n'

'add_body(1, codes)' means 1 Tab at the start of the line. 'add_body(0, codes)' means 0 Tab at the start of the line.For example, 'self.add_body(0, self.header_code)' in the 'gen_code()' function.

def emit_Dropout(self, IR_node):
    parent = self.IR_graph.get_parent(IR_node.name, [0])
    self.add_body(1, "{:<15} = Dropout(name = '{}', dropout_rate = {})({})".format(
        IR_node.variable_name,
        IR_node.name,
        1 - IR_node.IR_layer.attr["keep_prob"].f,
        parent.real_variable_name))
  • [Only Model Code]Use self.used_layers to save some operation types for adding the modified functions to the target model code file.
def emit_BatchNorm(self, IR_node):
    self.used_layers.add(IR_node.type)
    self.add_body(1, "{:<15} = batch_normalization(...)".format(...)) 

......

def _layer_BatchNorm(self):
    self.add_body(0, """
def batch_normalization(input, name, **kwargs):
    mean = tf.Variable(__weights_dict[name]['mean'], name = name + "_mean", trainable = is_train)
    variance = tf.Variable(__weights_dict[name]['var'], name = name + "_var", trainable = is_train)
    offset = tf.Variable(__weights_dict[name]['bias'], name = name + "_bias", trainable = is_train) if 'bias' in __weights_dict[name] else None
    scale = tf.Variable(__weights_dict[name]['scale'], name = name + "_scale", trainable = is_train) if 'scale' in __weights_dict[name] else None
    return tf.nn.batch_normalization(input, mean, variance, offset, scale, name = name, **kwargs)
""")

[Note!] You can create and test the layer of new type and the modified function in the code file of target framework. Then put them to the 'target_framework'_emitter

After you make some changes:

$ python -m pytest -v -s ./test/test_conversion_imagenet.py

Pull Request

Before you make a PR:

  • Explain your idea by making an issue on GitHub issues of each projects, especially when introducing new features.

When you make a PR:

  • Reference the issue you made for explaining your idea.

Commit Message

When you leave commit message: The most important thing is simple but needs to contain primary summary what you did. And It is also recommended to start with capitalized verb the subject line. For example:

  • Remove deprecated methods Instead of:
  • methods are removed

Coding Style

Several major rules are listed below:

  • Requires 4 spaces for indentation.
  • No trailing whitespace, blank lines should have no whitespace.
  • End of Line Sequence is 'LF' instand of 'CRLF'