# Creating ONNX Protobuf

In this short tutorial, we’ll make use of the following functions for the examples:

- `make_xxx()` to make different types of protobufs for attributes, nodes, graphs, etc.
- `check()` method that can check whether a protobuf in a particular type is valid.
- `print_readable()` method that can print out the human-readable representation of the proto object.

For detailed definitions of each type of ONNX protobufs, please checkout ONNX intermediate representation spec. A list of available operators, e.g. `FC` or `Relu` used in the following examples to define the nodes, can be found here.

## Create Node Protobuf

Define a node protobuf and check whether it’s valid:

    library(onnx)

    node_def <- make_node("Relu", list("X"), list("Y"))
    check(node_def)

    > node_def
    input: "X"
    output: "Y"
    op_type: "Relu"

## Create Attribute Protobuf

Define an attribute protobuf and check whether it’s valid:

    attr_def <- make_attribute("this_is_an_int", 123L)
    check(attr_def)

    > attr_def
    name: "this_is_an_int"
    i: 123
    type: INT

## Create Graph Protobuf

Define a graph protobuf and check whether it’s valid:

    graph_def <- make_graph(
      nodes = list(
        make_node("FC", list("X", "W1", "B1"), list("H1")),
        make_node("Relu", list("H1"), list("R1")),
        make_node("FC", list("R1", "W2", "B2"), list("Y"))
      ),
      name = "MLP",
      inputs = list(
        make_tensor_value_info('X' , onnx$TensorProto$FLOAT, list(1L)),
        make_tensor_value_info('W1', onnx$TensorProto$FLOAT, list(1L)),
        make_tensor_value_info('B1', onnx$TensorProto$FLOAT, list(1L)),
        make_tensor_value_info('W2', onnx$TensorProto$FLOAT, list(1L)),
        make_tensor_value_info('B2', onnx$TensorProto$FLOAT, list(1L))
      ),
      outputs = list(
        make_tensor_value_info('Y', onnx$TensorProto$FLOAT, list(1L))
      )
    )
    check(graph_def)

You can use `print_readable()` to print out the human-readable representation of the graph definition:

    > print_readable(graph_def)
    graph MLP (
      %X[FLOAT, 1]
      %W1[FLOAT, 1]
      %B1[FLOAT, 1]
      %W2[FLOAT, 1]
      %B2[FLOAT, 1]
    ) {
      %H1 = FC(%X, %W1, %B1)
      %R1 = Relu(%H1)
      %Y = FC(%R1, %W2, %B2)
      return %Y
    }

Or simply print it out to see the detailed graph definition containing nodes, inputs, and outputs:

    > graph_def
    node {
      input: "X"
      input: "W1"
      input: "B1"
      output: "H1"
      op_type: "FC"
    }
    node {
      input: "H1"
      output: "R1"
      op_type: "Relu"
    }
    node {
      input: "R1"
      input: "W2"
      input: "B2"
      output: "Y"
      op_type: "FC"
    }
    name: "MLP"
    input {
      name: "X"
      type {
        tensor_type {
          elem_type: FLOAT
          shape {
            dim {
              dim_value: 1
            }
          }
        }
      }
    }
    input {
      name: "W1"
      type {
        tensor_type {
          elem_type: FLOAT
          shape {
            dim {
              dim_value: 1
            }
          }
        }
      }
    }
    input {
      name: "B1"
      type {
        tensor_type {
          elem_type: FLOAT
          shape {
            dim {
              dim_value: 1
            }
          }
        }
      }
    }
    input {
      name: "W2"
      type {
        tensor_type {
          elem_type: FLOAT
          shape {
            dim {
              dim_value: 1
            }
          }
        }
      }
    }
    input {
      name: "B2"
      type {
        tensor_type {
          elem_type: FLOAT
          shape {
            dim {
              dim_value: 1
            }
          }
        }
      }
    }
    output {
      name: "Y"
      type {
        tensor_type {
          elem_type: FLOAT
          shape {
            dim {
              dim_value: 1
            }
          }
        }
      }
    }