---
title: "Creating ONNX Protobuf"
output: 
  rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Creating ONNX Protobuf}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
type: docs
repo: https://github.com/onnx/onnx-r
---


```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
knitr::opts_chunk$set(eval = FALSE)
```

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](https://github.com/onnx/onnx/blob/master/docs/IR.md). A list of available operators, e.g. `FC` or `Relu` used in the following examples to define the nodes, can be found [here](https://github.com/onnx/onnx/blob/master/docs/Operators.md).

## Create Node Protobuf

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

```{r eval=FALSE}
library(onnx)

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

```{r eval=FALSE}
> node_def
input: "X"
output: "Y"
op_type: "Relu"
```

## Create Attribute Protobuf

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

```{r eval=FALSE}
attr_def <- make_attribute("this_is_an_int", 123L)
check(attr_def)
```

```{r eval=FALSE}
> attr_def
name: "this_is_an_int"
i: 123
type: INT
```

## Create Graph Protobuf

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

```{r eval=FALSE}
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:

```{r eval=FALSE}
> 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:

```{r eval=FALSE}
> 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
        }
      }
    }
  }
}
```
