stanfordnlp/CoreNLP · error · RuntimeException

Got NaN for prob in CRFLogConditionalObjectiveFunction.calcu

Error message

Got NaN for prob in CRFLogConditionalObjectiveFunction.calculate()

What it means

In the multi-threaded (batch) variant of CRFLogConditionalObjectiveFunction.calculate(), multiThreadGradient(batch, false) aggregates the per-document log-probabilities. If the aggregated prob is NaN the function throws, since a non-finite objective cannot be minimized. Unlike error 230 the message does not add the underflow hint, but the root cause is the same: NaN propagated from per-document gradient/value computation.

Solutions

  1. Validate the weight vector x for NaN/Inf at the start of each iteration and roll back or reduce the learning rate if found.
  2. Split long documents into shorter sequences to avoid underflow.
  3. Run with a single thread / smaller batch to isolate which document yields NaN.
  4. Check feature values (featureVal) for zero or negative inputs used in log/exp computations.
  5. Re-scale features and restart training from the last known-good model.

Example fix

// before
for (double w : x) { /* no check */ }
crf.calculate(x, batch, E);
// after
for (double w : x) {
  if (Double.isNaN(w) || Double.isInfinite(w)) {
    throw new IllegalStateException("bad weights; reduce learning rate");
  }
}
crf.calculate(x, batch, E);
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean finiteParams(double[] x) { for (double w : x) if (!(Math.abs(w) < 1e10)) return false; return true; }
// call before calculate: if (!finiteParams(x)) rollback();

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")) {
    batch = bisectBatch(batch); // isolate the offending document
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the batched calculate(...) overload (multi-threaded path) where one or more documents produce NaN log-probabilities or gradients (long sequences underflowing, NaN weights in x, or division by zero in feature values).

Common situations: Large-scale CRF training with multi-threading enabled, where a single bad document poisons the aggregated prob; also seen after a training step overshoots and weights become Inf/NaN.

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/c1a7586af85ec814. Report an issue: GitHub.

Appendix: source

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

    return data.length;
  }

  @Override
  public void calculateStochastic(double[] x, double [] v, int[] batch) {
    to2D(x, weights);
    setWeights(weights);

    double batchScale = ((double) batch.length)/((double) this.dataDimension());

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

    // iterate over all the documents
    double prob = multiThreadGradient(batch, false);  // 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()");
    }

    value = -prob;

    // 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++) {
        // real gradient should be empirical-expected;
        // but since we minimize -L(\theta), the gradient is -(empirical-expected)
        derivative[index++] = (E_i[j] - batchScale*Ehat_i[j]);
        if (VERBOSE) {
          log.info("deriv(" + i + "," + j + ") = " + E_i[j] + " - " + Ehat_i[j] + " = " + derivative[index - 1]);
        }
      }
    }

View on GitHub (pinned to 1b7edd19c4)