class_docstr: This class is a wrapper of tensorboardX summary writer,
      which enable nn.Variable can be visualized as a graph by tensorboard.
  
      Prerequisite:
         Install tensorflow and tensorboardX, simply by the following commands:
  
         .. code-block:: plaintext
  
             pip install tensorflow
             pip install tensorboardX
  
      Please refer to the following example to use this class:
  
      Example:
  
      .. code-block:: python
  
          import numpy as np
          import nnabla as nn
          import nnabla.functions as F
          import nnabla.parametric_functions as PF
  
          def show_a_graph():
              try:
                  from nnabla.experimental.tb_graph_writer import TBGraphWriter
              except Exception as e:
                  print("please install tensorflow and tensorboardX at first.")
                  raise e
  
              nn.clear_parameters()
              x = nn.Variable((2, 3, 4, 4))
              with nn.parameter_scope('c1'):
                  h = PF.convolution(x, 8, (3, 3), pad=(1, 1))
                  h = F.relu(PF.batch_normalization(h))
              with nn.parameter_scope('f1'):
                  y = PF.affine(h, 10)
  
              with TBGraphWriter(log_dir='log_out') as tb:
                  tb.from_variable(y, output_name="y")
  
      The corresponding graph can be visualized as the following:
  
      .. image:: ./tb_graph_writer_files/graph.PNG
         :height: 561px
         :width: 233px
         :scale: 50%
  
      Or, you may show scalar value or histogram of values along the increasing of iteration number
      as the following:
  
      .. code-block:: python
  
          with TBGraphWriter(log_dir='log_out') as tb:
              values = []
              for i in range(360):
                  s = np.sin(i / 180.0 * np.pi)
                  tb.add_scalar("show_curve/sin", s, i)
                  values.append(s)
  
              nd_values = np.array(values)
              for i in range(10):
                  tb.add_histogram("histogram", nd_values, i)
                  nd_values += 0.05
  
      It looks like:
  
      .. image:: ./tb_graph_writer_files/scalar.PNG
         :height: 418px
         :width: 522px
         :scale: 50%
  
  d
      .. image:: ./tb_graph_writer_files/histogram.PNG
         :height: 328px
         :width: 387px
         :scale: 50%
  
  
      This class writes a protobuf file to `log_dir` specified folder, thus, user should launch tensorboard
      to specify this folder:
  
      .. code-block:: plaintext
  
         tensorboard --logdir=log_out
  
      Then, user may check graph in a web browser, by typing the address:
         http://localhost:6006
  
      See Also:
          https://tensorboardx.readthedocs.io/en/latest/tensorboard.html
  
      
code: def from_graph_def(self, graph_def):
      variables = graph_def.variables
      parameters = graph_def.parameters
      functions = graph_def.functions
      inputs = graph_def.inputs
      nodes = []
      scope = {}
  
      for n, v in parameters.items():
          shape_proto = TensorShapeProto(
              dim=[TensorShapeProto.Dim(size=d) for d in v.shape]
          )
          node = NodeDef(
              name=n.encode(encoding="utf-8"),
              op="Parameter",
              input=[],
              attr={
                  "shape": AttrValue(shape=shape_proto),
                  "dtype": AttrValue(type=DT_FLOAT),
              },
          )
          nodes.append(node)
          scope[n] = node
  
      for n, v in inputs.items():
          shape_proto = TensorShapeProto(
              dim=[TensorShapeProto.Dim(size=d) for d in v.shape]
          )
          nodes.append(
              NodeDef(
                  name=n.encode(encoding="utf-8"),
                  op="Variable",
                  input=[],
                  attr={
                      "shape": AttrValue(shape=shape_proto),
                      "dtype": AttrValue(type=DT_FLOAT),
                  },
              )
          )
  
      for func_name, func in functions.items():
          for o in func["outputs"]:
              if o in scope:
                  node = scope[o]
                  node.input.extend([func_name])
              else:
                  if o in variables:
                      v = variables[o]
                      shape_proto = TensorShapeProto(
                          dim=[
                              TensorShapeProto.Dim(size=d)
                              for d in v.shape
                          ]
                      )
                      node = NodeDef(
                          name=o.encode(encoding="utf-8"),
                          op="Variable",
                          input=[func_name],
                          attr={
                              "shape": AttrValue(shape=shape_proto),
                              "dtype": AttrValue(type=DT_FLOAT),
                          },
                      )
                      nodes.append(node)
          for i in func["inputs"]:
              if i in variables:
                  v = variables[i]
                  shape_proto = TensorShapeProto(
                      dim=[
                          TensorShapeProto.Dim(size=d) for d in v.shape
                      ]
                  )
                  node = NodeDef(
                      name=o.encode(encoding="utf-8"),
                      op="Variable",
                      input=[],
                      attr={
                          "shape": AttrValue(shape=shape_proto),
                          "dtype": AttrValue(type=DT_FLOAT),
                      },
                  )
                  nodes.append(node)
                  scope[o] = node
          nodes.append(
              NodeDef(
                  name=func_name,
                  op=func["type"],
                  input=func["inputs"],
                  attr={
                      "arguments": AttrValue(
                          s="a=1".encode(encoding="utf-8")
                      )
                  },
              )
          )
  
      current_graph = GraphDef(
          node=nodes, versions=VersionDef(producer=22)
      )
      event = event_pb2.Event(
          graph_def=current_graph.SerializeToString()
      )
      self.file_writer.add_event(event)
  
file_path: nnabla/python/src/nnabla/experimental/tb_graph_writer.py
imports: import tensorboardX.proto.event_pb2
  from nnabla.parameter import get_parameters
  from tensorboardX import SummaryWriter
  from tensorboardX.proto.attr_value_pb2 import AttrValue
  from tensorboardX.proto.graph_pb2 import GraphDef
  from tensorboardX.proto.node_def_pb2 import NodeDef
  from tensorboardX.proto.tensor_shape_pb2 import TensorShapeProto
  from tensorboardX.proto.types_pb2 import DT_FLOAT
  from tensorboardX.proto.versions_pb2 import VersionDef
label_desc: Use image node_id 3 for calling the TBGraphWriter obj's underlying member method code with example usage: obj.from_graph_def(graph_def) without return types