class_docstr: A task for training primal model and dual models jointly.
  It takes:
      - unlabelled source (aka source monolingual data for translation task),
      - unlabelled target (aka target monolingual data for translation task),
      - labelled (source, target) (aka parallel data for translation task),
class_docstr_tok: ["A","task","for","training","primal","model","and","dual","models","jointly",".","It","takes",":","-","unlabelled","source","(","aka","source","monolingual","data","for","translation","task",")",",","-","unlabelled","target","(","aka","target","monolingual","data","for","translation","task",")",",","-","labelled","(","source",",","target",")","(","aka","parallel","data","for","translation","task",")",","]
code: def aggregate_logging_outputs(self, logging_outputs, criterion):
      parallel_keys = [
          "primal_parallel",
          "dual_parallel",
          "primal_source",
          "dual_source",
      ]
      agg_logging_outputs = {}
      for lang_pair in parallel_keys:
          agg_output = []
          for logging_output in logging_outputs:
              if lang_pair in logging_output.keys():
                  agg_output.append(logging_output[lang_pair])
          if len(agg_output) > 0:
              agg_logging_outputs[
                  lang_pair
              ] = criterion.__class__.aggregate_logging_outputs(
                  agg_output
              )
  
      def sum_over_languages(key):
          return sum(
              logging_output[key]
              for logging_output in agg_logging_outputs.values()
          )
  
      # flatten logging outputs
      flat_logging_output = {
          "{}:{}".format(lang_pair, k): v
          for lang_pair, agg_logging_output in agg_logging_outputs.items()
          for k, v in agg_logging_output.items()
      }
      flat_logging_output["loss"] = sum_over_languages("loss")
      flat_logging_output["nll_loss"] = sum_over_languages("nll_loss")
      flat_logging_output["sample_size"] = sum_over_languages(
          "sample_size"
      )
      flat_logging_output["nsentences"] = sum_over_languages(
          "nsentences"
      )
      flat_logging_output["ntokens"] = sum_over_languages("ntokens")
      return flat_logging_output
  
imports: from collections import OrderedDict
  import torch
  from fairseq import optim, utils
  from fairseq.criterions import CRITERION_REGISTRY
  from fairseq.data import LanguagePairDataset, RoundRobinZipDatasets
  from fairseq.tasks import LegacyFairseqTask, register_task
  from pytorch_translate.data import dictionary, utils
  from pytorch_translate.dual_learning import dual_learning_models
  from pytorch_translate.dual_learning.dual_learning_criterion import UnsupervisedCriterion
  from pytorch_translate.tasks.pytorch_translate_task import PytorchTranslateTask
  from pytorch_translate.weighted_criterions import WeightedLabelSmoothedCrossEntropyCriterion
label_desc: Use image node_id 16 for calling the DualLearningTask obj's underlying member method code with example usage: obj.aggregate_logging_outputs(logging_outputs, criterion) and returns: flat_logging_output, sum