protected void nextLambda(final GLMIterationTask glmt, GLMValidation val) { currentLambdaIter = 0; boolean improved = _model.setAndTestValidation(_lambdaIdx, val); _model.clone().update(self()); boolean done = false; // _iter < max_iter && (improved || _runAllLambdas) && _lambdaIdx < // (lambda.length-1); if (_iter == max_iter) { Log.info("GLM2 reached max #iterations."); done = true; } else if (!improved && !_runAllLambdas) { Log.info("GLM2 converged as solution stopped improving with decreasing lambda."); done = true; } else if (_lambdaIdx == lambda.length - 1) { Log.info("GLM2 done with all given lambdas."); done = true; } else if (_activeCols != null && _activeCols.length + 1 >= MAX_PREDICTORS) { Log.info( "GLM2 reached maximum allowed number of predictors at lambda = " + lambda[_lambdaIdx]); done = true; } if (!done) { // continue with next lambda value? ++_lambdaIdx; glmt._val = null; if (glmt._gram == null) { // assume we had lambda search with strong rules // we use strong rules so we can't really used this gram for the next lambda computation // (different sets of coefficients) // I expect that: // 1) beta has been expanded to match current set of active cols // 2) it is new GLMIteration ready to be launched // caller (nextLambda(glmt,beta)) is expected to ensure this... assert _activeCols == null || (glmt._beta.length == _activeCols.length + 1); assert !glmt.isDone(); glmt.asyncExec(_activeData._adaptedFrame); } else // we have the right gram, just solve with with next lambda new Iteration().callback(glmt); } else // nope, we're done GLM2.this.complete(); // signal we're done to anyone waiting for the job }
@Override public void callback(final GLMIterationTask glmt) { _model.stop_training(); Log.info( "GLM2 iteration(" + _iter + ") done in " + (System.currentTimeMillis() - _iterationStartTime) + "ms"); if (!isRunning(self())) throw new JobCancelledException(); currentLambdaIter++; if (glmt._val != null) { if (!(glmt._val.residual_deviance < glmt._val .null_deviance)) { // complete fail, look if we can restart with higher_accuracy on if (!highAccuracy()) { Log.info( "GLM2 reached negative explained deviance without line-search, rerunning with high accuracy settings."); setHighAccuracy(); if (_lastResult != null) new GLMIterationTask( GLM2.this, _activeData, glmt._glm, true, true, true, _lastResult._glmt._beta, _ymu, _reg, new Iteration()) .asyncExec(_activeData._adaptedFrame); else if (_lambdaIdx > 2) // > 2 because 0 is null model, we don't wan to run with that new GLMIterationTask( GLM2.this, _activeData, glmt._glm, true, true, true, _model.submodels[_lambdaIdx - 1].norm_beta, _ymu, _reg, new Iteration()) .asyncExec(_activeData._adaptedFrame); else // no sane solution to go back to, start from scratch! new GLMIterationTask( GLM2.this, _activeData, glmt._glm, true, false, false, null, _ymu, _reg, new Iteration()) .asyncExec(_activeData._adaptedFrame); _lastResult = null; return; } } _model.setAndTestValidation(_lambdaIdx, glmt._val); _model.clone().update(self()); } if (glmt._val != null && glmt._computeGradient) { // check gradient final double[] grad = glmt.gradient(l2pen()); ADMMSolver.subgrad(alpha[0], lambda[_lambdaIdx], glmt._beta, grad); double err = 0; for (double d : grad) if (d > err) err = d; else if (d < -err) err = -d; Log.info("GLM2 gradient after " + _iter + " iterations = " + err); if (err <= GLM_GRAD_EPS) { Log.info( "GLM2 converged by reaching small enough gradient, with max |subgradient| = " + err); setNewBeta(glmt._beta); nextLambda(glmt, glmt._beta); return; } } if (glmt._beta != null && glmt._val != null && glmt._computeGradient && _glm.family != Family.tweedie) { if (_lastResult != null && needLineSearch(glmt._beta, objval(glmt), 1)) { if (!highAccuracy()) { setHighAccuracy(); if (_lastResult._iter < (_iter - 2)) { // there is a gap form last result...return to it and start again final double[] prevBeta = _lastResult._activeCols != _activeCols ? resizeVec(_lastResult._glmt._beta, _activeCols, _lastResult._activeCols) : _lastResult._glmt._beta; new GLMIterationTask( GLM2.this, _activeData, glmt._glm, true, true, true, prevBeta, _ymu, _reg, new Iteration()) .asyncExec(_activeData._adaptedFrame); return; } } final double[] b = resizeVec(_lastResult._glmt._beta, _activeCols, _lastResult._activeCols); assert (b.length == glmt._beta.length) : b.length + " != " + glmt._beta.length + ", activeCols = " + _activeCols.length; new GLMTask.GLMLineSearchTask( GLM2.this, _activeData, _glm, resizeVec(_lastResult._glmt._beta, _activeCols, _lastResult._activeCols), glmt._beta, 1e-4, glmt._nobs, alpha[0], lambda[_lambdaIdx], new LineSearchIteration()) .asyncExec(_activeData._adaptedFrame); return; } _lastResult = new IterationInfo(GLM2.this._iter - 1, glmt, _activeCols); } final double[] newBeta = MemoryManager.malloc8d(glmt._xy.length); ADMMSolver slvr = new ADMMSolver(lambda[_lambdaIdx], alpha[0], ADMM_GRAD_EPS, _addedL2); slvr.solve(glmt._gram, glmt._xy, glmt._yy, newBeta); _addedL2 = slvr._addedL2; if (Utils.hasNaNsOrInfs(newBeta)) { Log.info("GLM2 forcibly converged by getting NaNs and/or Infs in beta"); nextLambda(glmt, glmt._beta); } else { setNewBeta(newBeta); final double bdiff = beta_diff(glmt._beta, newBeta); if (_glm.family == Family.gaussian || bdiff < beta_epsilon || _iter == max_iter) { // Gaussian is non-iterative and gradient is ADMMSolver's gradient => // just validate and move on to the next lambda int diff = (int) Math.log10(bdiff); int nzs = 0; for (int i = 0; i < newBeta.length; ++i) if (newBeta[i] != 0) ++nzs; if (newBeta.length < 20) System.out.println("beta = " + Arrays.toString(newBeta)); Log.info( "GLM2 (lambda_" + _lambdaIdx + "=" + lambda[_lambdaIdx] + ") converged (reached a fixed point with ~ 1e" + diff + " precision) after " + _iter + "iterations, got " + nzs + " nzs"); nextLambda(glmt, newBeta); } else { // not done yet, launch next iteration final boolean validate = higher_accuracy || (currentLambdaIter % 5) == 0; ++_iter; System.out.println("Iter = " + _iter); new GLMIterationTask( GLM2.this, _activeData, glmt._glm, true, validate, validate, newBeta, _ymu, _reg, new Iteration()) .asyncExec(_activeData._adaptedFrame); } } }
public IterationInfo(int i, GLMIterationTask glmt, final int[] activeCols) { _iter = i; _glmt = glmt.clone(); _activeCols = activeCols; assert _glmt._beta != null && _glmt._val != null; }