docs: public static String generateMemoryStatus(Model net, int minibatch, InputType... inputTypes){
          MultiLayerNetwork mln = null;
          ComputationGraph cg = null;
          boolean isMLN;
          if(net instanceof MultiLayerNetwork){
              mln = (MultiLayerNetwork)net;
              isMLN = true;
          } else {
              cg = (ComputationGraph)net;
              isMLN = false;
          }
  
          StringBuilder sb = genericMemoryStatus();
  
          int bytesPerElement;
          switch (Nd4j.dataType()){
              case DOUBLE:
                  bytesPerElement = 8;
                  break;
              case FLOAT:
                  bytesPerElement = 4;
                  break;
              case HALF:
                  bytesPerElement = 2;
                  break;
              default:
                  bytesPerElement = 0;    //TODO
          }
  
          sb.append("\n----- Workspace Information -----\n");
          List<MemoryWorkspace> allWs = Nd4j.getWorkspaceManager().getAllWorkspacesForCurrentThread();
          sb.append(f("Workspaces: # for current thread", (allWs == null ? 0 : allWs.size())));
          //sb.append(f("Workspaces: # for all threads", allWs.size()));      //TODO
          long totalWsSize = 0;
          if(allWs != null && allWs.size() > 0) {
              sb.append("Current thread workspaces:\n");
              //Name, open, size, currently allocated
              String wsFormat = "  %-26s%-12s%-30s%-20s";
              sb.append(String.format(wsFormat, "Name", "State", "Size", "# Cycles")).append("\n");
              for (MemoryWorkspace ws : allWs) {
                  totalWsSize += ws.getCurrentSize();
                  long numCycles = ws.getGenerationId();
                  sb.append(String.format(wsFormat, ws.getId(),
                          (ws.isScopeActive() ? "OPEN" : "CLOSED"),
                          fBytes(ws.getCurrentSize()),
                          String.valueOf(numCycles))).append("\n");
              }
          }
          sb.append(fBytes("Workspaces total size", totalWsSize));
          Map<String,Pointer> helperWorkspaces;
          if(isMLN){
              helperWorkspaces = mln.getHelperWorkspaces();
          } else {
              helperWorkspaces = cg.getHelperWorkspaces();
          }
          if(helperWorkspaces != null && !helperWorkspaces.isEmpty()){
              boolean header = false;
              for(Map.Entry<String,Pointer> e : helperWorkspaces.entrySet()){
                  Pointer p = e.getValue();
                  if(p == null){
                      continue;
                  }
                  if(!header){
                      sb.append("Helper Workspaces\n");
                      header = true;
                  }
                  sb.append("  ").append(fBytes(e.getKey(), p.capacity()));
              }
          }
  
          long sumMem = 0;
          long nParams = net.params().length();
          sb.append("\n----- Network Information -----\n")
                  .append(f("Network # Parameters", nParams))
                  .append(fBytes("Parameter Memory", bytesPerElement * nParams));
          INDArray flattenedGradients;
          if(isMLN){
              flattenedGradients = mln.getFlattenedGradients();
          } else {
              flattenedGradients = cg.getFlattenedGradients();
          }
          if(flattenedGradients == null){
              sb.append(f("Parameter Gradients Memory", "<not allocated>"));
          } else {
              sumMem += (flattenedGradients.length() * bytesPerElement);
              sb.append(fBytes("Parameter Gradients Memory", bytesPerElement * flattenedGradients.length()));
          }
              //Updater info
          BaseMultiLayerUpdater u;
          if(isMLN){
              u = (BaseMultiLayerUpdater)mln.getUpdater(false);
          } else {
              u = cg.getUpdater(false);
          }
          Set<String> updaterClasses = new HashSet<>();
          if(u == null){
              sb.append(f("Updater","<not initialized>"));
          } else {
              INDArray stateArr = u.getStateViewArray();
              long stateArrLength = (stateArr == null ? 0 : stateArr.length());
              sb.append(f("Updater Number of Elements", stateArrLength));
              sb.append(fBytes("Updater Memory", stateArrLength * bytesPerElement));
              sumMem += stateArrLength * bytesPerElement;
  
              List<UpdaterBlock> blocks = u.getUpdaterBlocks();
              for(UpdaterBlock ub : blocks){
                  updaterClasses.add(ub.getGradientUpdater().getClass().getName());
              }
  
              sb.append("Updater Classes:").append("\n");
              for(String s : updaterClasses ){
                  sb.append("  ").append(s).append("\n");
              }
          }
          sb.append(fBytes("Params + Gradient + Updater Memory", sumMem));
              //Iter/epoch
          sb.append(f("Iteration Count", BaseOptimizer.getIterationCount(net)));
          sb.append(f("Epoch Count", BaseOptimizer.getEpochCount(net)));
  
              //Workspaces, backprop type, layer info, activation info, helper info
          if(isMLN) {
              sb.append(f("Backprop Type", mln.getLayerWiseConfigurations().getBackpropType()));
              if(mln.getLayerWiseConfigurations().getBackpropType() == BackpropType.TruncatedBPTT){
                  sb.append(f("TBPTT Length", mln.getLayerWiseConfigurations().getTbpttFwdLength() + "/" + mln.getLayerWiseConfigurations().getTbpttBackLength()));
              }
              sb.append(f("Workspace Mode: Training", mln.getLayerWiseConfigurations().getTrainingWorkspaceMode()));
              sb.append(f("Workspace Mode: Inference", mln.getLayerWiseConfigurations().getInferenceWorkspaceMode()));
              appendLayerInformation(sb, mln.getLayers(), bytesPerElement);
              appendHelperInformation(sb, mln.getLayers());
              appendActivationShapes(mln, (inputTypes == null || inputTypes.length == 0 ? null : inputTypes[0]), minibatch, sb, bytesPerElement);
          } else {
              sb.append(f("Backprop Type", cg.getConfiguration().getBackpropType()));
              if(cg.getConfiguration().getBackpropType() == BackpropType.TruncatedBPTT){
                  sb.append(f("TBPTT Length", cg.getConfiguration().getTbpttFwdLength() + "/" + cg.getConfiguration().getTbpttBackLength()));
              }
              sb.append(f("Workspace Mode: Training", cg.getConfiguration().getTrainingWorkspaceMode()));
              sb.append(f("Workspace Mode: Inference", cg.getConfiguration().getInferenceWorkspaceMode()));
              appendLayerInformation(sb, cg.getLayers(), bytesPerElement);
              appendHelperInformation(sb, cg.getLayers());
              appendActivationShapes(cg, sb, bytesPerElement);
          }
  
          //Listener info:
          Collection<TrainingListener> listeners;
          if(isMLN){
              listeners = mln.getListeners();
          } else {
              listeners = cg.getListeners();
          }
  
          sb.append("\n----- Network Training Listeners -----\n");
          sb.append(f("Number of Listeners", (listeners == null ? 0 : listeners.size())));
          int lCount = 0;
          if(listeners != null && !listeners.isEmpty()){
              for(TrainingListener tl : listeners) {
                  sb.append(f("Listener " + (lCount++), tl));
              }
          }
          
          return sb.toString();
      }