'Computes the entire model and produces sharded logits and losses.
Args:
features: A dictionary of feature name to tensor.
skip: a boolean, if we\'re just dummy-calling and actually skip this model
(but we need to create variables to not confuse distributed training).
last_position_only: a boolean, compute logits for only the last position.
Returns:
sharded_logits: a list of `Tensor`s, one per datashard.
losses: a dictionary: {loss-name (string): floating point `Scalar`}.'

def model_fn(self, features, skip=False, last_position_only=False):

    start_time = time.time()
    dp = self._data_parallelism
    sharded_features = self._shard_features(features)
    transformed_features = {}
    all_previous_modalities = []
    for (key, input_modality) in six.iteritems(self._problem_hparams.input_modality):
        previous_modalities = [self._hparams.problems[i].input_modality[key].name for i in xrange(self._problem_idx)]
        all_previous_modalities.extend(previous_modalities)
        do_reuse = (input_modality.name in all_previous_modalities)
        with tf.variable_scope(input_modality.name, reuse=do_reuse):
            transformed_features[key] = input_modality.bottom_sharded(sharded_features[key], dp)
        all_previous_modalities.append(input_modality.name)
    if ('target_space_id' in features):
        transformed_features['target_space_id'] = ([features['target_space_id']] * self._num_datashards)
    previous_tgt_modalities = [self._hparams.problems[i].target_modality.name for i in xrange(self._problem_idx)]
    all_previous_modalities.extend(previous_tgt_modalities)
    target_modality = self._problem_hparams.target_modality
    target_reuse = (target_modality.name in previous_tgt_modalities)
    with tf.variable_scope(target_modality.name, reuse=target_reuse):
        transformed_features['targets'] = target_modality.targets_bottom_sharded(sharded_features['targets'], dp)
    with tf.variable_scope('body', reuse=(self._problem_idx > 0)):
        if skip:
            body_outputs = transformed_features['targets']
            losses = {'extra': 0.0}
        else:
            (body_outputs, losses) = self.model_fn_body_sharded(transformed_features)
            if (not isinstance(losses, dict)):
                losses = {'extra': losses}
    with tf.variable_scope(target_modality.name, reuse=target_reuse):
        if (not last_position_only):
            sharded_logits = target_modality.top_sharded(body_outputs, sharded_features['targets'], self._data_parallelism)
            training_loss = target_modality.loss_sharded(sharded_logits, sharded_features['targets'], self._data_parallelism)
            training_loss *= self._problem_hparams.loss_multiplier
        else:
            last_position_body_outputs = [tf.expand_dims(body_shard[:, (-1), :, :], axis=[1]) for body_shard in body_outputs]
            last_position_targets = [tf.expand_dims(target_shard[:, (-1):, :, :], axis=[1]) for target_shard in sharded_features['targets']]
            sharded_logits = target_modality.top_sharded(last_position_body_outputs, last_position_targets, self._data_parallelism)
            training_loss = None
    tf.logging.info(('This    model_fn    took    %.3f    sec.' % (time.time() - start_time)))
    losses['training'] = training_loss
    return (sharded_logits, losses)
