def METHOD_NAME(self, train_data, device, args):
    trainer = gluon.Trainer(self.model.get_layer_params(), args.client_optimizer, {"learning_rate": args.learning_rate})
    accuracy_metric = mx.gluon.metric.Accuracy()
    loss_metric = mx.gluon.metric.CrossEntropy()
    metrics = mx.gluon.metric.CompositeEvalMetric()
    for child_metric in [accuracy_metric, loss_metric]:
        metrics.add(child_metric)
    loss_func = gluon.loss.SoftmaxCrossEntropyLoss()
    for epoch in range(args.epochs):
        num_examples = 0
        for batch_idx, (x, labels) in enumerate(train_data):
            data = gluon.utils.split_and_load(
                x, ctx_list=[device], batch_axis=0
            )
            label = gluon.utils.split_and_load(
                labels, ctx_list=[device], batch_axis=0
            )
            outputs = []
            with autograd.record():
                for x_item, y_item in zip(data, label):
                    z = self.model(x_item)
                    loss = loss_func(z, y_item)
                    loss.backward()
                    outputs.append(npx.softmax(z))
                    num_examples += len(x_item)
            metrics.update(label, outputs)
            trainer.step(x.shape[0])
        trainings_metric = metrics.get_name_value()
        acc_val, loss_val = trainings_metric
        logging.info(
            "Client Index = {}\tEpoch: {}\tLoss: {:.6f}\tAccuracy: {:.6f}".format(
                self.id, epoch, loss_val[1], acc_val[1]
            )
        )