docstr: This function should build the model which takes the input variables (defined above)
  and return cost at the end.
code: def build_graph(self, image, label):
      """This function should build the model which takes the input variables (defined above)
      and return cost at the end."""
  
      # In tensorflow, inputs to convolution function are assumed to be
      # NHWC. Add a single channel here.
      image = tf.expand_dims(image, 3)
  
      image = image * 2 - 1  # center the pixels values at zero
      # The context manager `argscope` sets the default option for all the layers under
      # this context. Here we use 32 channel convolution with shape 3x3
      # See tutorial at https://tensorpack.readthedocs.io/tutorial/symbolic.html
      with argscope(
          Conv2D, kernel_size=3, activation=tf.nn.relu, filters=32
      ):
          # LinearWrap is just a syntax sugar.
          # See tutorial at https://tensorpack.readthedocs.io/tutorial/symbolic.html
          logits = (
              LinearWrap(image)
              .Conv2D("conv0")
              .MaxPooling("pool0", 2)
              .Conv2D("conv1")
              .Conv2D("conv2")
              .MaxPooling("pool1", 2)
              .Conv2D("conv3")
              .FullyConnected("fc0", 512, activation=tf.nn.relu)
              .Dropout("dropout", rate=0.5)
              .FullyConnected("fc1", 10, activation=tf.identity)()
          )
  
      # a vector of length B with loss of each sample
      cost = tf.nn.sparse_softmax_cross_entropy_with_logits(
          logits=logits, labels=label
      )
      cost = tf.reduce_mean(
          cost, name="cross_entropy_loss"
      )  # the average cross-entropy loss
  
      correct = tf.cast(
          tf.nn.in_top_k(predictions=logits, targets=label, k=1),
          tf.float32,
          name="correct",
      )
      accuracy = tf.reduce_mean(correct, name="accuracy")
  
      # This will monitor training error & accuracy (in a moving average fashion). The value will be automatically
      # 1. written to tensosrboard
      # 2. written to stat.json
      # 3. printed after each epoch
      # You can also just call `tf.summary.scalar`. But moving summary has some other benefits.
      # See tutorial at https://tensorpack.readthedocs.io/tutorial/summary.html
      train_error = tf.reduce_mean(1 - correct, name="train_error")
      summary.add_moving_summary(train_error, accuracy)
  
      # Use a regex to find parameters to apply weight decay.
      # Here we apply a weight decay on all W (weight matrix) of all fc layers
      # If you don't like regex, you can certainly define the cost in any other methods.
      wd_cost = tf.multiply(
          1e-5,
          regularize_cost("fc.*/W", tf.nn.l2_loss),
          name="regularize_loss",
      )
      total_cost = tf.add_n([wd_cost, cost], name="total_cost")
      summary.add_moving_summary(cost, wd_cost, total_cost)
  
      # monitor histogram of all weight (of conv and fc layers) in tensorboard
      summary.add_param_summary((".*/W", ["histogram", "rms"]))
      # the function should return the total cost to be optimized
      return total_cost
  
file_path: tensorpack/examples/basics/mnist-convnet.py
imports: from tensorpack import tfv1
  from tensorpack import *
  from tensorpack.dataflow import dataset
  from tensorpack.tfutils import summary
label_desc: Use image node_id 2 for calling the Model obj's underlying member method code with example usage: obj.build_graph(image, label) and returns: total_cost