docs: public String summary(InputType... inputTypes) {
          StringBuilder ret = new StringBuilder();
          ret.append("\n");
  
          int frozenParams = 0;
          Map<String, InputType> vertexOutputs = new HashMap<>(); //vertex name and output types
          int currLayerIdx = -1;
  
          List<String[]> lines = new ArrayList<>();
          if(inputTypes == null){
              lines.add(new String[]{"VertexName (VertexType)", "nIn,nOut", "TotalParams", "ParamsShape", "Vertex Inputs"});
          } else {
              lines.add(new String[]{"VertexName (VertexType)", "nIn,nOut", "TotalParams", "ParamsShape", "Vertex Inputs", "InputShape", "OutputShape"});
          }
          int[] maxLength = new int[inputTypes == null || inputTypes.length == 0 ? 5 : 7];
          String[] header = lines.get(0);
          for( int i=0; i<header.length; i++ ){
              maxLength[i] = header[i].length();
          }
  
          if(topologicalOrder == null){
              GraphIndices indices = calculateIndices();
              topologicalOrder = indices.getTopologicalSortOrder();
          }
  
          for (int currVertexIdx : topologicalOrder) {
  
              GraphVertex currentVertex = vertices[currVertexIdx];
              String currentVertexName = currentVertex.getVertexName();
  
              //String vars for print
              String[] classNameArr = currentVertex.getClass().toString().split("\\.");
              String className = classNameArr[classNameArr.length - 1];
              String connections = "-";
              String inShape = "-";
              String outShape = "-";
              String paramCount = "-";
              String in = "-";
              String out = "-";
              String paramShape = "-";
              if (currentVertex.isInputVertex()) {
                  if (inputTypes != null) vertexOutputs.put(currentVertexName, inputTypes[configuration.getNetworkInputs().indexOf(currentVertexName)]); //for input vertices the outputs are just the input types (only layer vertices have preprocessing?)
              } else {
                  connections = configuration.getVertexInputs().get(currentVertexName).toString();
                  List<InputType> inputTypeList = new ArrayList<>();
                  if (currentVertex.hasLayer()) {
                      Layer currentLayer = ((LayerVertex) currentVertex).getLayer();
                      classNameArr = currentLayer.getClass().getName().split("\\.");
                      className = classNameArr[classNameArr.length - 1];
                      paramCount = String.valueOf(currentLayer.numParams());
                      //layer with params
                      if (currentLayer.numParams() > 0) {
                          paramShape = "";
                          if (currentLayer instanceof BidirectionalLayer) { // Bidirectional layer is not an FFL
                              BidirectionalLayer bi = (BidirectionalLayer) currentLayer;
                              in = String.valueOf(((Bidirectional)bi.conf().getLayer()).getNIn());
                              out = String.valueOf(((Bidirectional)bi.conf().getLayer()).getNOut());
                          } else {
                              try {
                                  in = String.valueOf(((FeedForwardLayer) currentLayer.conf().getLayer()).getNIn());
                                  out = String.valueOf(((FeedForwardLayer) currentLayer.conf().getLayer()).getNOut());
                              }
                              catch (Exception e) { // Some layers, like PReLU, are just BaseLayers (but have parameters)
                              }
                          }
                          List<String> paraNames = currentLayer.conf().variables();
                          for (String aP : paraNames) {
                              String paramS = ArrayUtils.toString(currentLayer.paramTable().get(aP).shape());
                              paramShape += aP + ":" + paramS + ", ";
                          }
                          paramShape = paramShape.subSequence(0, paramShape.lastIndexOf(",")).toString();
                      }
                      //frozen layer
                      if (currentLayer instanceof FrozenLayer) {
                          frozenParams += currentLayer.numParams();
                          classNameArr = ((FrozenLayer) currentLayer).getInsideLayer().getClass().getName().split("\\.");
                          className = "Frozen " + classNameArr[classNameArr.length - 1];
                      }
  
                      if (inputTypes != null) {
                          //get input type
                          String inputVertexName = vertices[currentVertex.getInputVertices()[0].getVertexIndex()].getVertexName();
                          InputType currentInType = vertexOutputs.get(inputVertexName);
                          inShape = currentInType.toString();
                          inputTypeList.add(currentInType);
  
                          InputPreProcessor layerVertexPreProcesor = ((org.deeplearning4j.nn.conf.graph.LayerVertex)configuration.getVertices().get(currentVertexName)).getPreProcessor();
                          if (layerVertexPreProcesor != null) {
                              inShape += "-->" + layerVertexPreProcesor.getOutputType(currentInType);
                          }
                      }
                      currLayerIdx++;
                  } else {
                      //get input type
                      if (inputTypes != null) {
                          VertexIndices[] inputVertices = currentVertex.getInputVertices();
                          if (inputVertices != null) {
                              for (int i = 0; i < inputVertices.length; i++) {
                                  GraphVertex thisInputVertex = vertices[inputVertices[i].getVertexIndex()];
                                  inputTypeList.add(vertexOutputs.get(thisInputVertex.getVertexName()));
                              }
                          }
                      }
                  }
                  if (inputTypes != null) {
                      InputType currentVertexOutputType = configuration.getVertices().get(currentVertexName).getOutputType(currLayerIdx, inputTypeList.toArray(new InputType[inputTypeList.size()]));
                      outShape = currentVertexOutputType.toString();
                      vertexOutputs.put(currentVertexName, currentVertexOutputType);
                  }
              }
  
              //Add on to summary string
              String[] line;
              if (inputTypes == null) {
                  line = new String[]{currentVertexName + " (" + className + ")", in + "," + out, paramCount, paramShape, connections};
              } else {
                  line = new String[]{currentVertexName + " (" + className + ")", in + "," + out, paramCount, paramShape, connections, inShape, outShape};
              }
              for( int i=0; i<line.length; i++ ){
                  maxLength[i] = Math.max(maxLength[i], line[i] == null ? 0 : line[i].length());
              }
              lines.add(line);
          }
  
          StringBuilder sbFormat = new StringBuilder();
          int totalLength = 0;
          int pos = 0;
          for(int length : maxLength){
              int currLength;
              if(pos++ == maxLength.length-1){
                  currLength = length;
              } else {
                  currLength = length+3;
              }
              sbFormat.append("%-").append(currLength).append("s");
              totalLength += currLength;
          }
          sbFormat.append("\n");
          String format = sbFormat.toString();
  
  
  
          ret.append(StringUtils.repeat("=", totalLength))
                  .append("\n");
  
          boolean first = true;
          for(String[] line : lines){
              String formatted = String.format(format, (Object[])line);
              ret.append(formatted);
              if(first){
                  ret.append(StringUtils.repeat("=", totalLength)).append("\n");
                  first = false;
              }
          }
  
          ret.append(StringUtils.repeat("-", totalLength))
                  .append(String.format("\n%30s %d", "Total Parameters: ", params().length()))
                  .append(String.format("\n%30s %d", "Trainable Parameters: ", params().length() - frozenParams))
                  .append(String.format("\n%30s %d", "Frozen Parameters: ", frozenParams))
                  .append("\n")
                  .append(StringUtils.repeat("=", totalLength))
                  .append("\n");
  
          return ret.toString();
      }