You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: train.m
    path of file: ./repos/pix2pix/code/+p2p
    
    the code of the file until where you have to start completion: function p2pModel = train(inData, outData, options)
% train     Train a pix2pix model.
%
%   A pix2pix model that attempts to learn how to convert images from
%   inData to outData is trained, following the approach described in
%   'Isola et al. Image-to-Image Translation with Conditional Adversarial 
%   Nets'.
%
% Args:
%   inData  - Training data input images
%   outData - Training data target images
%   options - Training options as a struct generated by p2p.trainingOptions
%
% Returns:
%   p2pModel - A struct containing trained newtorks and optimisiers
%
% See also: p2p.trainingOptions

% Copyright 2020 The MathWorks, Inc.
    
    if nargin < 3
        options = p2p.getDefaultOptions();
    end
    
    if (options.ExecutionEnvironment == "auto" && canUseGPU) || ...
            options.Execu
    
function [g, gLoss, d, dLoss, lossL1, ganLoss, images] = stepBoth(g, d, gOpt, dOpt, inputImage, targetImage, options)
    
    % Make a fake image
    fakeImage = tanh(g.forward(inputImage));
    
    %% D update
    % Apply the discriminator
    realPredictions = sigmoid(d.forward(...
        cat(3, targetImage, inputImage) ...
        ));
    fakePredictions = sigmoid(d.forward(...
        cat(3, fakeImage, inputImage)...
        ));
    
    % calculate D losses
    labels = ones(size(fakePredictions), 'single');
    % crossentropy divides by nBatch, so we need to divide further
    dLoss = options.DRelLearnRate*(crossentropy(realPredictions, labels)/numel(fakePredictions(:,:,1,1)) + ...
        crossentropy(1-fakePredictions, labels)/numel(fakePredictions(:,:,1,1)));
    
    % get d gradients
    dGrads = dlgradient(dLoss, d.Learnables, "RetainData", true);
    dLoss = extractdata(dLoss);
    
    %% G update
    % to save time I just use the existing result from d
    
    % calculate g Losses
    ganLoss = crossentropy(fakePredictions, labels)/numel(fakePredictions(:,:,1,1));
    lossL1 = mean(abs(fakeImage - targetImage), 'all');
    gLoss = options.Lambda*lossL1 + ganLoss;
    
    % get g grads
    gGrads = dlgradient(gLoss, g.Learnables);
    
    % update g
    g.Learnables = dOpt.update(g.Learnables, gGrads);
    % update d
    d.Learnables = gOpt.update(d.Learnables, dGrads);
    % things for plotting
    gLoss = extractdata(gLoss);
    lossL1 = extractdata(lossL1);
    ganLoss = extractdata(ganLoss);
    
    images = {fakeImage, inputImage, targetImage};
end