code: def feed_forward_categorical(
      config, action_space, observations, unused_length, state=None):
    
    init_output_weights = tf.contrib.layers.variance_scaling_initializer(
        factor=config.init_output_factor)
    if not isinstance(action_space, gym.spaces.Discrete):
      raise ValueError('Network expects discrete actions.')
    flat_observations = tf.reshape(observations, [
        tf.shape(observations)[0], tf.shape(observations)[1],
        functools.reduce(operator.mul, observations.shape.as_list()[2:], 1)])
    with tf.variable_scope('policy'):
      x = flat_observations
      for size in config.policy_layers:
        x = tf.contrib.layers.fully_connected(x, size, tf.nn.relu)
      logits = tf.contrib.layers.fully_connected(
          x, action_space.n, None, weights_initializer=init_output_weights)
    with tf.variable_scope('value'):
      x = flat_observations
      for size in config.value_layers:
        x = tf.contrib.layers.fully_connected(x, size, tf.nn.relu)
      value = tf.contrib.layers.fully_connected(x, 1, None)[..., 0]
    policy = tfd.Categorical(logits)
    return agents.tools.AttrDict(policy=policy, value=value, state=state)
docs: Independent feed forward networks for policy and value.
  
    The policy network outputs the mean action and the log standard deviation
    is learned as independent parameter vector.
  
    Args:
      config: Configuration object.
      action_space: Action space of the environment.
      observations: Sequences of observations.
      unused_length: Batch of sequence lengths.
      state: Unused batch of initial recurrent states.
  
    Raises:
      ValueError: Unexpected action space.
  
    Returns:
      Attribute dictionary containing the policy, value, and unused state.