docs: def dropout_pred(model, ref, ref_rc, alt, alt_rc, mutation_positions, out_annotation_all_outputs,
                   output_filter_mask=None, out_annotation=None, dropout_iterations=30):
      """Dropout-based variant effect prediction
  
          This method is based on the ideas in [Gal et al.](https://arxiv.org/pdf/1506.02142.pdf) where dropout
          layers are also actived in the model prediction phase in order to estimate model uncertainty. The
          advantage of this method is that instead of a point estimate of the model output the distribution of
          the model output is estimated.
  
          # Arguments
              model: Keras model
              ref: Input sequence with the reference genotype in the mutation position
              ref_rc: Reverse complement of the 'ref' argument
              alt: Input sequence with the alternative genotype in the mutation position
              alt_rc: Reverse complement of the 'alt' argument
              mutation_positions: Position on which the mutation was placed in the forward sequences
              out_annotation_all_outputs: Output labels of the model.
              output_filter_mask: Mask of boolean values indicating which model outputs should be used.
                  Use this or 'out_annotation'
              out_annotation: List of outputs labels for which of the outputs (in case of a multi-task model) the
                  predictions should be calculated.
              dropout_iterations: Number of prediction iterations to be performed in order to estimate the
                  output distribution. Values greater than 30 are recommended to get a reliable p-value.
  
          # Returns
  
              Dictionary with a set of measures of the model uncertainty in the variant position. The ones of interest are:
  
              - do_{ref, alt}_mean: Mean of the model predictions given the respective input sequence and dropout.
                  - Forward or reverse-complement sequences are chosen as for 'do_pv'.
              - do_{ref, alt}_var: Variance of the model predictions given the respective input sequence and dropout.
                  - Forward or reverse-complement sequences are chosen as for 'do_pv'.
              - do_diff: 'do_alt_mean' - 'do_alt_mean', which is an estimate similar to ISM using diff_type "diff".
              - do_pv: P-value of a paired t-test, comparing the predictions of ref with the ones of alt. Forward or
                  - reverse-complement sequences are chosen based on which pair has the lower p-value.
          """
      prefix = "do"
  
      seqs = {"ref": ref, "ref_rc": ref_rc, "alt": alt, "alt_rc": alt_rc}
  
      assert np.all([np.array(get_seq_len(ref)) == np.array(get_seq_len(seqs[k])) for k in seqs.keys() if k != "ref"])
      assert get_seq_len(ref)[0] == mutation_positions.shape[0]
      assert len(mutation_positions.shape) == 1
  
      # determine which outputs should be selected
      if output_filter_mask is None:
          if out_annotation is None:
              output_filter_mask = np.arange(out_annotation_all_outputs.shape[0])
          else:
              output_filter_mask = np.where(np.in1d(out_annotation_all_outputs, out_annotation))[0]
  
      # make sure the labels are assigned correctly
      out_annotation = out_annotation_all_outputs[output_filter_mask]
  
      # Instead of loading the model from a json file I will transfer the model architecture + weights in memory
      model_config = model._updated_config()
      alt_config = replace_dict_values(model_config, u"Dropout", u"BiDropout")
  
      # Custom objects have to be added before correctly!
      alt_model = keras.layers.deserialize(alt_config)
  
      # Transfer weights and biases
      alt_model.set_weights(model.get_weights())
  
      # ANALOGOUS TO ISM:
      # predict
      preds = {}
      for k in seqs:
          preds[k] = pred_do(alt_model, seqs[k], output_filter_mask=output_filter_mask, dropout_iterations=dropout_iterations)
  
      t, prob = ttest_ind(preds["ref"], preds["alt"], axis=0)
      t_rc, prob_rc = ttest_ind(preds["ref_rc"], preds["alt_rc"], axis=0)
  
      logit_prob = None
      logit_prob_rc = None
      pred_range = get_range(preds)
      # In case the predictions are bound to [0,1] it might make sense to use logit on the data, as the model output
      # could be probalilities
      if np.all([(pred_range[k] >= 0) and (pred_range[k] <= 1) for k in pred_range]):
          logit_preds = apply_over_single(preds, logit)
          logit_prob = apply_over_double(logit_preds["ref"], logit_preds["alt"], apply_func=ttest_ind,
                                         select_return_elm=1, axis=0)
          logit_prob_rc = apply_over_double(logit_preds["ref_rc"], logit_preds["alt_rc"], apply_func=ttest_ind,
                                         select_return_elm=1, axis=0)
      # fwd and rc are independent here... so this can be done differently here...
  
      sel = (np.abs(prob) > np.abs(prob_rc)).astype(np.int)  # Select the LOWER p-value among fwd and rc
  
      out_dict = {}
  
      out_dict["%s_pv" % prefix] = pd.DataFrame(overwite_by(prob, prob_rc, sel), columns=out_annotation)
  
      if logit_prob is not None:
          logit_sel = (np.abs(logit_prob) > np.abs(logit_prob_rc)).astype(np.int)
          out_dict["%s_logit_pv" % prefix] = pd.DataFrame(overwite_by(logit_prob, logit_prob_rc, logit_sel), columns=out_annotation)
  
      pred_means = {}
      pred_vars = {}
      pred_cvar2 = {}
      for k in preds:
          pred_means[k] = np.mean(preds[k], axis=0)
          pred_vars[k] = np.var(preds[k], axis=0)
          pred_cvar2[k] = pred_vars[k] / (pred_means[k] ** 2)
  
      mean_cvar = np.sqrt((pred_cvar2["ref"] + pred_cvar2["alt"]) / 2)
      mean_cvar_rc = np.sqrt((pred_cvar2["ref_rc"] + pred_cvar2["alt_rc"]) / 2)
  
      mean_cvar = overwite_by(mean_cvar, mean_cvar_rc, sel)
      ref_mean = overwite_by(pred_means["ref"], pred_means["ref_rc"], sel)
      alt_mean = overwite_by(pred_means["alt"], pred_means["alt_rc"], sel)
      ref_var = overwite_by(pred_vars["ref"], pred_vars["ref_rc"], sel)
      alt_var = overwite_by(pred_vars["alt"], pred_vars["alt_rc"], sel)
  
      out_dict["%s_ref_mean" % prefix] = pd.DataFrame(ref_mean, columns=out_annotation)
      out_dict["%s_alt_mean" % prefix] = pd.DataFrame(alt_mean, columns=out_annotation)
  
      out_dict["%s_ref_var" % prefix] = pd.DataFrame(ref_var, columns=out_annotation)
      out_dict["%s_alt_var" % prefix] = pd.DataFrame(alt_var, columns=out_annotation)
  
      out_dict["%s_cvar" % prefix] = pd.DataFrame(mean_cvar, columns=out_annotation)
  
      out_dict["%s_diff" % prefix] = out_dict["%s_alt_mean" % prefix] - out_dict["%s_ref_mean" % prefix]
  
      return out_dict