docs: protected synchronized Map<String,INDArray> ffToLayerActivationsInWS(boolean train, int layerIndex, int[] excludeIdxs,
                                                              FwdPassType fwdPassType, boolean storeLastForTBPTT,
                                                              INDArray[] input, INDArray[] fMask, INDArray[] lMask, boolean clearInputs) {
          if(layerIndex != -1 && (layerIndex < 0 || layerIndex >= topologicalOrder.length)){
              throw new IllegalArgumentException("Invalid input index - index must be >= 0 and < " + topologicalOrder.length
                      + ", got index " + layerIndex);
          }
          setInputs(input);
          setLayerMaskArrays(fMask, lMask);
  
          LayerWorkspaceMgr workspaceMgr;
          WorkspaceMode wsm = (train ? configuration.getTrainingWorkspaceMode() : configuration.getInferenceWorkspaceMode());
          if(wsm == WorkspaceMode.NONE){
              //Verify that no workspace is open externally
              WorkspaceUtils.assertNoWorkspacesOpen("Expected no workspace active in ffToLayerActivationsDetached", true);
  
              workspaceMgr = LayerWorkspaceMgr.noWorkspaces();
          } else {
              WorkspaceUtils.assertOpenAndActive(WS_ALL_LAYERS_ACT, "ffToLayerActivationsInWs method requires workspace WS_ALL_LAYERS_ACT to be open");
  
              workspaceMgr = LayerWorkspaceMgr.builder()
                      .with(ArrayType.ACTIVATIONS, WS_ALL_LAYERS_ACT, WS_ALL_LAYERS_ACT_CONFIG)
                      .with(ArrayType.INPUT, WS_ALL_LAYERS_ACT, WS_ALL_LAYERS_ACT_CONFIG)
                      .with(ArrayType.FF_WORKING_MEM, WS_LAYER_WORKING_MEM, WS_LAYER_WORKING_MEM_CONFIG)
                      .with(ArrayType.RNN_FF_LOOP_WORKING_MEM, WS_RNN_LOOP_WORKING_MEM, WS_RNN_LOOP_WORKING_MEM_CONFIG)
                      .build();
  
              if(input[0].isAttached()){
                  //Don't leverage out of async DataMultiSetIterator workspaces
                  workspaceMgr.setNoLeverageOverride(input[0].data().getParentWorkspace().getId());
              }
  
              if(configuration.getCacheMode() != CacheMode.NONE){
                  //For now: store cache mode activations in activations workspace
                  workspaceMgr.setWorkspace(ArrayType.FF_CACHE, WS_ALL_LAYERS_ACT, WS_ALL_LAYERS_ACT_CONFIG);
              }
          }
          workspaceMgr.setHelperWorkspacePointers(helperWorkspaces);
  
          Map<String, INDArray> activations = new HashMap<>();
          //Do forward pass according to the topological ordering of the network
          int stopIndex;
          if (layerIndex > 0) {
              stopIndex = ArrayUtils.indexOf(topologicalOrder, layerIndex);
          } else {
              stopIndex = topologicalOrder.length -1;
          }
          for (int i = 0; i <= stopIndex; i++) {
              GraphVertex current = vertices[topologicalOrder[i]];
              String vName = current.getVertexName();
              int vIdx = current.getVertexIndex();
  
              if(excludeIdxs != null && ArrayUtils.contains(excludeIdxs, vIdx)){
                  continue;
              }
  
              try(MemoryWorkspace wsFFWorking = workspaceMgr.notifyScopeEntered(ArrayType.FF_WORKING_MEM)){
                  VertexIndices[] inputsTo = current.getOutputVertices();
  
                  INDArray out;
                  if(current.isInputVertex()){
                      out = inputs[vIdx];
                  } else {
  
                      if(fwdPassType == FwdPassType.STANDARD){
                          out = current.doForward(train, workspaceMgr);
                      } else if(fwdPassType == FwdPassType.RNN_ACTIVATE_WITH_STORED_STATE) {
                          if (current.hasLayer()) {
                              Layer l = current.getLayer();
                              if (l instanceof RecurrentLayer) {
                                  out = ((RecurrentLayer) l).rnnActivateUsingStoredState(current.getInputs()[0], train,
                                          storeLastForTBPTT, workspaceMgr);
                              } else if(l instanceof org.deeplearning4j.nn.layers.wrapper.BaseWrapperLayer && ((org.deeplearning4j.nn.layers.wrapper.BaseWrapperLayer)l).getUnderlying() instanceof RecurrentLayer) {
                                  RecurrentLayer rl = (RecurrentLayer) ((org.deeplearning4j.nn.layers.wrapper.BaseWrapperLayer)l).getUnderlying();
                                  out = rl.rnnActivateUsingStoredState(current.getInputs()[0], train,storeLastForTBPTT, workspaceMgr);
                              } else if (l instanceof MultiLayerNetwork) {
                                  List<INDArray> temp = ((MultiLayerNetwork) l).rnnActivateUsingStoredState(
                                          current.getInputs()[0], train, storeLastForTBPTT);
                                  out = temp.get(temp.size() - 1);
                              } else {
                                  //non-recurrent layer
                                  out = current.doForward(train, workspaceMgr);
                              }
                          } else {
                              out = current.doForward(train, workspaceMgr);
                          }
                      } else {
                          throw new IllegalStateException("FwdPassType not supported for this method: " + fwdPassType);
                      }
  
                      validateArrayWorkspaces(workspaceMgr, out, ArrayType.ACTIVATIONS, vName, false, "Feed forward (inference)");
                  }
                  activations.put(current.getVertexName(), out);
  
                  if(inputsTo != null) {
                      //Can be null for output layers
                      for (VertexIndices v : inputsTo) {
                          //Note that we don't have to do anything special here: the activations are always detached in
                          // this method
                          int inputToIndex = v.getVertexIndex();
                          int vIdxEdge = v.getVertexEdgeNumber();
                          vertices[inputToIndex].setInput(vIdxEdge, out, workspaceMgr);
                      }
                  }
  
                  if(clearInputs) {
                      current.clear();
                  }
              }
          }
          return activations;
      }