stanfordnlp/CoreNLP · error · RuntimeException

Got NaN for prob in…

Error message

Got NaN for prob in CRFLogConditionalObjectiveFunction.calculate() - this may well indicate numeric underflow due to overly long documents.

What it means

CRFLogConditionalObjectiveFunction.calculate() computes the log-probability of the labeled sequences given the model. If that value comes back as NaN, the function throws a RuntimeException because training cannot proceed on a non-finite objective. The message explicitly warns that overly long documents can cause numeric underflow (log of 0) in the forward/backward computations.

Solutions

  1. Shorten training documents (split into sentences/segments) so sequence probabilities do not underflow.
  2. Inspect the parameter vector x for NaN/Inf before training (print/validate weights; reduce learning rate or use a more stable optimizer like L-BFGS with line search).
  3. Scale/normalize feature values so log-linear scores stay in a sane range.
  4. Enable VERBOSE and log intermediate values to find the offending document, then fix or drop it.
  5. As a last resort, catch the RuntimeException and skip/re-initialize the offending training batch.

Example fix

// before: one huge training document
DocumentReader dr = new DocumentReader("longdoc.txt");
// after: split into sentence-level windows
List<List<CoreLabel>> sentences = DocumentPreprocessor.split("longdoc.txt");
// train on sentences instead of the full document
Defensive patterns

Strategy: try-catch

Validate before calling

for (double w : x) { if (Double.isNaN(w) || Double.isInfinite(w)) throw new IllegalArgumentException("NaN/Inf weight before CRF calculate"); }
if (docLength > MAX_SEQUENCE_LENGTH) doc = chunk(doc, MAX_SEQUENCE_LENGTH);

Type guard

static boolean isFinite(double[] v) { for (double d : v) if (Double.isNaN(d) || Double.isInfinite(d)) return false; return true; }

Try / catch

try {
  crf.calculate(x, batch, E);
} catch (RuntimeException e) {
  if (e.getMessage().contains("NaN for prob")) {
    // shrink documents, reduce learning rate, restore checkpoint
    x = lastGoodCheckpoint;
    learningRate *= 0.5;
  } else throw e;
}

Prevention

When it happens

Trigger: Calling calculate(double[] x, double[] batch, double[] E) in the single-threaded path when regularGradientAndValue() returns NaN — typically when the log-probability of a sequence underflows (very long documents, extreme feature weights, or weights x containing NaN/Inf).

Common situations: Training a CRF on very long documents (underflow in the log-sum of sequence probabilities), a learning-rate blowup producing Inf/NaN weights, or pathological feature scaling before calling CRFClassifier training.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/e2574e752f5e7de9. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/ie/crf/CRFLogConditionalObjectiveFunction.java:425

  /**
   * Calculates both value and partial derivatives at the point x, and save them internally.
   */
  @Override
  public void calculate(double[] x) {

    // final double[][] weights = to2D(x);
    to2D(x, weights);
    setWeights(weights);

    // the expectations over counts
    // first index is feature index, second index is of possible labeling
    // double[][] E = empty2D();
    clear2D(E);

    double prob = regularGradientAndValue(); // the log prob of the sequence given the model, which is the negation of value at this point

    if (Double.isNaN(prob)) { // shouldn't be the case
      throw new RuntimeException("Got NaN for prob in CRFLogConditionalObjectiveFunction.calculate()" +
              " - this may well indicate numeric underflow due to overly long documents.");
    }

    // because we minimize -L(\theta)
    value = -prob;
    if (VERBOSE) {
      log.info("value is " + Math.exp(-value));
    }

    // compute the partial derivative for each feature by comparing expected counts to empirical counts
    int index = 0;
    for (int i = 0; i < E.length; i++) {
      double[] E_i = E[i], Ehat_i = Ehat[i];
      for (int j = 0; j < E_i.length; j++) {
        // because we minimize -L(\theta)
        derivative[index] = (E_i[j] - Ehat_i[j]);
        if (VERBOSE) {
          log.info("deriv(" + i + "," + j + ") = " + E_i[j] + " - " + Ehat_i[j] + " = " + derivative[index]);

View on GitHub (pinned to 1b7edd19c4)