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
- Validate the weight vector x for NaN/Inf at the start of each iteration and roll back or reduce the learning rate if found.
- Split long documents into shorter sequences to avoid underflow.
- Run with a single thread / smaller batch to isolate which document yields NaN.
- Check feature values (featureVal) for zero or negative inputs used in log/exp computations.
- 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
- Pre-screen training documents for extreme length and split them.
- Sanitize feature values (no NaN/Inf/negative where log/exp is used).
- Checkpoint weights each iteration so you can roll back on NaN.
- Run a smoke test on a small batch with multiple threads before the full run.
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
- Got NaN for prob in CRFLogConditionalObjectiveFunction.calcu
- Got NaN for prob in CRFLogConditionalObjectiveFunctionForLOP
- Got NaN for prob in CRFNonLinearLogConditionalObjectiveFunct
- Got NaN for prob in CRFNonLinearSecondOrderLogConditionalObj
- gradient check failed
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)