def train_loop(args, dataloader, model, loss_fn, optimizer):
    """Run one epoch of training in neural network.

    :param args: (Namespace) Object generated by an input arguments parser (ConfigArgParse or ArgParse).
    :param dataloader: (torch.utils.data.DataLoader) Dataloader for training dataset.
    :param model: (torch.nn.Module) PyTorch neural network.
    :param loss_fn: (torch.nn.modules.Loss) PyTorch loss function.
    :param optimizer: (torch.optim.Optimizer) PyTorch optimizer function.
    :return:
    * metrics: (dict)
      - 'mean_loss': (float) Mean loss per image.
    """

    data_size = len(dataloader.sampler)
    num_batches = len(dataloader)
    mean_loss = 0.0

    for batch, (x, y) in enumerate(dataloader):
        # if necessary, move batch to GPU memory (or whatever device we are using)
        x, y = x.to(args.device), y.to(args.device)

        # compute prediction and loss
        model.train()
        score = model(x)
        loss = loss_fn(score, y)
        mean_loss += loss.item()

        # backpropagation
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if args.verbose and batch % 100 == 0:
            loss, current = loss.item(), batch * len(x)
            print(f'train mean loss: {loss:>.4f}  [{current:>6d}/{data_size:>6d}]')

    # this translates to mean loss per image
    mean_loss /= num_batches

    metrics = {'mean_loss': mean_loss}
    return metrics