docs: @Override
      public void setWeights(Map<String, INDArray> weights) throws InvalidKerasConfigurationException {
          this.weights = new HashMap<>();
          /* Keras stores LSTM parameters in distinct arrays (e.g., the recurrent weights
           * are stored in four matrices: U_c, U_f, U_i, U_o) while DL4J stores them
           * concatenated into one matrix (e.g., U = [ U_c U_f U_o U_i ]). Thus we have
           * to map the Keras weight matrix to its corresponding DL4J weight submatrix.
           */
          INDArray W_i;
          INDArray W_f;
          INDArray W_c;
          INDArray W_o;
          INDArray U_i;
          INDArray U_f;
          INDArray U_c;
          INDArray U_o;
          INDArray b_i;
          INDArray b_f;
          INDArray b_c;
          INDArray b_o;
  
  
          if (kerasMajorVersion == 2) {
              INDArray W;
              if (weights.containsKey(conf.getKERAS_PARAM_NAME_W()))
                  W = weights.get(conf.getKERAS_PARAM_NAME_W());
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + conf.getKERAS_PARAM_NAME_W());
              INDArray U;
              if (weights.containsKey(conf.getKERAS_PARAM_NAME_RW()))
                  U = weights.get(conf.getKERAS_PARAM_NAME_RW());
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + conf.getKERAS_PARAM_NAME_RW());
              INDArray b;
              if (weights.containsKey(conf.getKERAS_PARAM_NAME_B()))
                  b = weights.get(conf.getKERAS_PARAM_NAME_B());
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + conf.getKERAS_PARAM_NAME_B());
  
              val sliceInterval = b.length() / 4;
              W_i = W.get(NDArrayIndex.all(), NDArrayIndex.interval(0, sliceInterval));
              W_f = W.get(NDArrayIndex.all(), NDArrayIndex.interval(sliceInterval, 2 * sliceInterval));
              W_c = W.get(NDArrayIndex.all(), NDArrayIndex.interval(2 * sliceInterval, 3 * sliceInterval));
              W_o = W.get(NDArrayIndex.all(), NDArrayIndex.interval(3 * sliceInterval, 4 * sliceInterval));
              U_i = U.get(NDArrayIndex.all(), NDArrayIndex.interval(0, sliceInterval));
              U_f = U.get(NDArrayIndex.all(), NDArrayIndex.interval(sliceInterval, 2 * sliceInterval));
              U_c = U.get(NDArrayIndex.all(), NDArrayIndex.interval(2 * sliceInterval, 3 * sliceInterval));
              U_o = U.get(NDArrayIndex.all(), NDArrayIndex.interval(3 * sliceInterval, 4 * sliceInterval));
              b_i = b.get(NDArrayIndex.interval(0, sliceInterval));
              b_f = b.get(NDArrayIndex.interval(sliceInterval, 2 * sliceInterval));
              b_c = b.get(NDArrayIndex.interval(2 * sliceInterval, 3 * sliceInterval));
              b_o = b.get(NDArrayIndex.interval(3 * sliceInterval, 4 * sliceInterval));
          } else {
              if (weights.containsKey(KERAS_PARAM_NAME_W_C))
                  W_c = weights.get(KERAS_PARAM_NAME_W_C);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_C);
              if (weights.containsKey(KERAS_PARAM_NAME_W_F))
                  W_f = weights.get(KERAS_PARAM_NAME_W_F);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_F);
              if (weights.containsKey(KERAS_PARAM_NAME_W_O))
                  W_o = weights.get(KERAS_PARAM_NAME_W_O);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_O);
              if (weights.containsKey(KERAS_PARAM_NAME_W_I))
                  W_i = weights.get(KERAS_PARAM_NAME_W_I);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_W_I);
              if (weights.containsKey(KERAS_PARAM_NAME_U_C))
                  U_c = weights.get(KERAS_PARAM_NAME_U_C);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_C);
              if (weights.containsKey(KERAS_PARAM_NAME_U_F))
                  U_f = weights.get(KERAS_PARAM_NAME_U_F);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_F);
              if (weights.containsKey(KERAS_PARAM_NAME_U_O))
                  U_o = weights.get(KERAS_PARAM_NAME_U_O);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_O);
              if (weights.containsKey(KERAS_PARAM_NAME_U_I))
                  U_i = weights.get(KERAS_PARAM_NAME_U_I);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_U_I);
              if (weights.containsKey(KERAS_PARAM_NAME_B_C))
                  b_c = weights.get(KERAS_PARAM_NAME_B_C);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_C);
              if (weights.containsKey(KERAS_PARAM_NAME_B_F))
                  b_f = weights.get(KERAS_PARAM_NAME_B_F);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_F);
              if (weights.containsKey(KERAS_PARAM_NAME_B_O))
                  b_o = weights.get(KERAS_PARAM_NAME_B_O);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_O);
              if (weights.containsKey(KERAS_PARAM_NAME_B_I))
                  b_i = weights.get(KERAS_PARAM_NAME_B_I);
              else
                  throw new InvalidKerasConfigurationException(
                          "Keras LSTM layer does not contain parameter " + KERAS_PARAM_NAME_B_I);
  
          }
  
          // Need to convert from IFCO to CFOI order
          int wCols = W_c.columns();
          int wRows = W_c.rows();
  
          INDArray W = Nd4j.zeros(wRows, 4 * wCols);
          W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(0, wCols)}, W_c);
          W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(wCols, 2 * wCols)}, W_f);
          W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(2 * wCols, 3 * wCols)}, W_o);
          W.put(new INDArrayIndex[]{NDArrayIndex.interval(0, wRows), NDArrayIndex.interval(3 * wCols, 4 * wCols)}, W_i);
          this.weights.put(LSTMParamInitializer.INPUT_WEIGHT_KEY, W);
  
          int uCols = U_c.columns();
          int uRows = U_c.rows();
          INDArray U = Nd4j.zeros(uRows, 4 * uCols);
          U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(0, uCols)}, U_c);
          U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(uCols, 2 * uCols)}, U_f);
          U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(2 * uCols, 3 * uCols)}, U_o);
          U.put(new INDArrayIndex[]{NDArrayIndex.interval(0, U.rows()), NDArrayIndex.interval(3 * uCols, 4 * uCols)}, U_i);
          this.weights.put(LSTMParamInitializer.RECURRENT_WEIGHT_KEY, U);
  
  
          int bCols = b_c.columns();
          int bRows = b_c.rows();
          INDArray b = Nd4j.zeros(bRows, 4 * bCols);
          b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(0, bCols)}, b_c);
          b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(bCols, 2 * bCols)}, b_f);
          b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(2 * bCols, 3 * bCols)}, b_o);
          b.put(new INDArrayIndex[]{NDArrayIndex.interval(0, b.rows()), NDArrayIndex.interval(3 * bCols, 4 * bCols)}, b_i);
          this.weights.put(LSTMParamInitializer.BIAS_KEY, b);
  
          if (weights.size() > NUM_WEIGHTS_IN_KERAS_LSTM) {
              Set<String> paramNames = weights.keySet();
              paramNames.remove(KERAS_PARAM_NAME_W_C);
              paramNames.remove(KERAS_PARAM_NAME_W_F);
              paramNames.remove(KERAS_PARAM_NAME_W_I);
              paramNames.remove(KERAS_PARAM_NAME_W_O);
              paramNames.remove(KERAS_PARAM_NAME_U_C);
              paramNames.remove(KERAS_PARAM_NAME_U_F);
              paramNames.remove(KERAS_PARAM_NAME_U_I);
              paramNames.remove(KERAS_PARAM_NAME_U_O);
              paramNames.remove(KERAS_PARAM_NAME_B_C);
              paramNames.remove(KERAS_PARAM_NAME_B_F);
              paramNames.remove(KERAS_PARAM_NAME_B_I);
              paramNames.remove(KERAS_PARAM_NAME_B_O);
              String unknownParamNames = paramNames.toString();
              log.warn("Attemping to set weights for unknown parameters: "
                      + unknownParamNames.substring(1, unknownParamNames.length() - 1));
          }
      }