docs: public MixtureDensityComponents extractComponents(INDArray output) {
          long outputSize = output.size(1);
          if (outputSize != (mLabelWidth + 2) * mMixtures) {
              throw new IllegalArgumentException(
                              "Network output size " + outputSize + " must be (labels+2)*mixtures where labels = "
                                              + mLabelWidth + " and mixtures = " + mMixtures);
          }
  
          MixtureDensityComponents mdc = new MixtureDensityComponents();
  
          // Output is 2 dimensional (samples, labels)
          //
          // For each label vector of length 'labels', we will have
          // an output vector of length '(labels + 2) * nMixtures.
          // The first nMixtures outputs will correspond to the 'alpha' for each mixture.
          // The second nMixtures outputs will correspond to the 'sigma' and the last nMixtures*labels
          // will correspond to the 'mu' (mean) of the output.
  
          // Reorganize these.
          // alpha = samples, 0 to nMixtures
          // mu = samples, nMixtures to 2*nMixtures
          // sigma = samples, 2*nMixtures to (labels + 2)*nMixtures
          // Alpha is then sub-divided through reshape by mixtures per label and samples.
  
          mdc.alpha = output.get(NDArrayIndex.all(), NDArrayIndex.interval(0, mMixtures));
          mdc.sigma = output.get(NDArrayIndex.all(), NDArrayIndex.interval(mMixtures, 2 * mMixtures));
          mdc.mu = output.get(NDArrayIndex.all(), NDArrayIndex.interval(2 * mMixtures, (mLabelWidth + 2) * mMixtures))
                          .reshape(output.size(0), mMixtures, mLabelWidth);
  
          // Alpha is a softmax because
          // the alpha should all sum to 1 for a given gaussian mixture.
          mdc.alpha = Nd4j.getExecutioner().exec(new OldSoftMax(mdc.alpha));
  
          // Mu comes directly from the network as an unmolested value.
          // Note that this effectively means that the output layer of
          // the network should have an activation function at least as large as
          // the expected values.  It is best for the output
          // layer to be an IDENTITY activation function.
          //mdc.mu = mdc.mu;
  
          // Sigma comes from the network as an exponential in order to
          // ensure that it is positive-definite.
          mdc.sigma = Transforms.exp(mdc.sigma);
  
          return mdc;
      }