code: def test_dp_split_mpc(self) -> None:
      # TODO: Vary Noise Magnitude
      NOISE_MAGNITUDE = 0
      FEATURE_SRC = 0
      LABEL_SRC = 1
  
      # TODO: Fix full_jacobian protocol
      # PROTOCOLS = ["full_jacobian", "layer_estimation"]
      PROTOCOLS = ["layer_estimation"]
  
      # TODO: Run multiple batches
      # TODO: ensure this works with other rr_prob values
      for (
          model_tuple,
          protocol,
          rr_prob,
          rappor_prob,
          skip_forward,
      ) in itertools.product(
          TEST_MODELS, PROTOCOLS, RR_PROBS, RAPPOR_PROBS, [False, True]
      ):
          logging.info(f"Model: {model_tuple}; Protocol: {protocol}")
          cfg.nn.dpsmpc.protocol = protocol
          cfg.nn.dpsmpc.skip_loss_forward = skip_forward
  
          model, size = model_tuple
  
          # TODO test multiclass using CrossEntropyLoss()
          if rappor_prob is None:
              loss_pt = torch.nn.BCEWithLogitsLoss()
          else:
              loss_pt = RAPPOR_loss(rappor_prob)
  
          # Compute model gradients without DP
          features = get_random_test_tensor(size=size, is_float=True)
          features.requires_grad = True
  
          # Get reference logits from plaintext model
          logits = model(features)
  
          # TODO: Write code to generate labels for CrossEntropyLoss
          labels = get_random_test_tensor(
              2, 0, logits.size(), is_float=False
          )
          labels = labels.float()
          labels_enc = crypten.cryptensor(labels, src=LABEL_SRC)
  
          # Compute reference loss
          loss = loss_pt(logits, labels)
  
          # Run reference backward pass
          model.zero_grad()
          loss.backward()
  
          # Delete plaintext model and features and labels for parties without access
          labels = None
          if self.rank != FEATURE_SRC:
              model = None
              features = None
  
          # Run split models
          for noise_src in [None, 0, 1]:
              # Copy model so gradients do not overwrite original model for comparison
              model_ = copy.deepcopy(model)
              dp_model = DPSplitModel(
                  model_,
                  FEATURE_SRC,
                  LABEL_SRC,
                  NOISE_MAGNITUDE,
                  noise_src=noise_src,
                  randomized_response_prob=rr_prob,
                  rappor_prob=rappor_prob,
              )
  
              dp_logits = dp_model(features)
  
              # Check forward pass
              if self.rank == FEATURE_SRC:
                  self.assertTrue(
                      dp_logits.eq(logits).all(),
                      "model outputs do not match",
                  )
  
              dp_model.compute_loss(labels_enc)
  
              if skip_forward:
                  self.assertTrue(
                      isinstance(dp_model.loss, SkippedLoss)
                  )
              else:
                  # communicate loss from feature_src party since other parties will
                  # have different losses.
                  torch.distributed.broadcast(loss, src=FEATURE_SRC)
                  self._check(
                      dp_model.loss,
                      loss,
                      "DP-Model loss is incorrect",
                      tolerance=0.15,
                  )
  
              # Test zero_grad()
              dp_model.zero_grad()
              for p in dp_model.parameters():
                  self.assertIsNone(p.grad)
  
              # Test backward()
              dp_model.backward()
  
              if self.rank == FEATURE_SRC:
                  self._check_gradients_with_dp(
                      model, dp_model, NOISE_MAGNITUDE
                  )
  
imports: import copy
  import itertools
  import logging
  import crypten
  import torch
  from crypten.common.tensor_types import is_float_tensor
  from crypten.config import cfg
  from crypten.nn.privacy import DPSplitModel, SkippedLoss
  from test.multiprocess_test_case import get_random_test_tensor, MultiProcessTestCase
label_desc: Use image node_id 3 for calling the TestPrivacyModels obj's underlying member method code with example usage: obj.test_dp_split_mpc() without return types