code: def cnn_model_fn(features, labels, mode):
      """Model function for a CNN."""
  
      # Define CNN architecture using tf.keras.layers.
      input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])
      y = tf.keras.layers.Conv2D(
          16, 8, strides=2, padding="same", activation="relu"
      )(input_layer)
      y = tf.keras.layers.MaxPool2D(2, 1)(y)
      y = tf.keras.layers.Conv2D(
          32, 4, strides=2, padding="valid", activation="relu"
      )(y)
      y = tf.keras.layers.MaxPool2D(2, 1)(y)
      y = tf.keras.layers.Flatten()(y)
      y = tf.keras.layers.Dense(32, activation="relu")(y)
      logits = tf.keras.layers.Dense(10)(y)
  
      # Calculate loss as a vector (to support microbatches in DP-SGD).
      vector_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(
          labels=labels, logits=logits
      )
      # Define mean of loss across minibatch (for reporting through tf.Estimator).
      scalar_loss = tf.reduce_mean(input_tensor=vector_loss)
  
      # Configure the training op (for TRAIN mode).
      if mode == tf_estimator.ModeKeys.TRAIN:
          if FLAGS.dpsgd:
              # Use DP version of GradientDescentOptimizer. Other optimizers are
              # available in dp_optimizer. Most optimizers inheriting from
              # tf.compat.v1.train.Optimizer should be wrappable in differentially
              # private counterparts by calling dp_optimizer.optimizer_from_args().
              optimizer = dp_optimizer_vectorized.VectorizedDPSGD(
                  l2_norm_clip=FLAGS.l2_norm_clip,
                  noise_multiplier=FLAGS.noise_multiplier,
                  num_microbatches=FLAGS.microbatches,
                  learning_rate=FLAGS.learning_rate,
              )
              opt_loss = vector_loss
          else:
              optimizer = GradientDescentOptimizer(
                  learning_rate=FLAGS.learning_rate
              )
              opt_loss = scalar_loss
          global_step = tf.compat.v1.train.get_global_step()
          train_op = optimizer.minimize(
              loss=opt_loss, global_step=global_step
          )
          # In the following, we pass the mean of the loss (scalar_loss) rather than
          # the vector_loss because tf.estimator requires a scalar loss. This is only
          # used for evaluation and debugging by tf.estimator. The actual loss being
          # minimized is opt_loss defined above and passed to optimizer.minimize().
          return tf_estimator.EstimatorSpec(
              mode=mode, loss=scalar_loss, train_op=train_op
          )
  
      # Add evaluation metrics (for EVAL mode).
      elif mode == tf_estimator.ModeKeys.EVAL:
          eval_metric_ops = {
              "accuracy": tf.compat.v1.metrics.accuracy(
                  labels=labels,
                  predictions=tf.argmax(input=logits, axis=1),
              )
          }
  
          return tf_estimator.EstimatorSpec(
              mode=mode,
              loss=scalar_loss,
              eval_metric_ops=eval_metric_ops,
          )
  
file_path: privacy/tutorials/mnist_dpsgd_tutorial_vectorized.py
imports: from absl import app
  from absl import flags
  from absl import logging
  import dp_accounting
  import numpy
  import tensorflow
  from tensorflow import estimator
  from tensorflow.compat.v1 import estimator
  from tensorflow_privacy.privacy.optimizers import dp_optimizer_vectorized
label_desc: Use image node_id 2 for calling a global function with example usage: cnn_model_fn(features, labels, mode) and returns: tf_estimator, tf_estimator