Simple profiling through decorator functions. (counting and timing of functions decorated with @count and @timeIt that have a SimPEG.utils.Counter)

e.g. output:
‘’’
Counters:
  InexactGaussNewton.doEndIteration       :        6
  InexactGaussNewton.printIter            :        7
  InexactGaussNewton.scaleSearchDirection :        6

Times:                                        mean      sum
  InexactGaussNewton.findSearchDirection  : 1.55e-02, 9.29e-02,    6x
  InexactGaussNewton.minimize             : 1.10e-01, 1.10e-01,    1x
  InexactGaussNewton.modifySearchDirection: 2.89e-04, 1.73e-03,    6x
  InexactGaussNewton.projection           : 3.69e-06, 1.11e-04,   30x
  InexactGaussNewton.stoppingCriteria     : 1.16e-04, 1.51e-03,   13x
  Inversion.dataObj                       : 6.60e-05, 8.58e-04,   13x
  Inversion.dataObj2Deriv                 : 1.03e-04, 6.20e-03,   60x
  Inversion.dataObjDeriv                  : 5.06e-05, 3.54e-04,    7x
  Inversion.evalFunction                  : 7.75e-04, 1.01e-02,   13x
  Inversion.run                           : 1.10e-01, 1.10e-01,    1x
  Regularization.modelObj                 : 3.56e-04, 4.63e-03,   13x
  Regularization.modelObj2Deriv           : 1.29e-03, 7.76e-02,   60x
  Regularization.modelObjDeriv            : 5.01e-04, 3.51e-03,    7x
‘’’
This commit is contained in:
Rowan Cockett
2013-11-20 21:59:53 -08:00
parent 514b709270
commit 2782a6fcfb
5 changed files with 160 additions and 15 deletions
+8 -3
View File
@@ -1,7 +1,7 @@
import numpy as np
import scipy.sparse as sp
import SimPEG
from SimPEG.utils import sdiag, mkvc, setKwargs, checkStoppers, printStoppers
from SimPEG.utils import sdiag, mkvc, setKwargs, checkStoppers, printStoppers, count, timeIt
from Optimize import Remember
from BetaSchedule import Cooling
@@ -13,6 +13,8 @@ class BaseInversion(object):
debug = False
beta0 = 1e4
counter = None
def __init__(self, prob, reg, opt, **kwargs):
setKwargs(self, **kwargs)
self.prob = prob
@@ -56,6 +58,7 @@ class BaseInversion(object):
def phi_d_target(self, value):
self._phi_d_target = value
@timeIt
def run(self, m0):
self.startup(m0)
while True:
@@ -131,7 +134,7 @@ class BaseInversion(object):
"""
printStoppers(self, self.stoppers)
@timeIt
def evalFunction(self, m, return_g=True, return_H=True):
u = self.prob.field(m)
@@ -162,7 +165,7 @@ class BaseInversion(object):
out += (operator,)
return out if len(out) > 1 else out[0]
@timeIt
def dataObj(self, m, u=None):
"""
:param numpy.array m: geophysical model
@@ -184,6 +187,7 @@ class BaseInversion(object):
R = mkvc(R)
return 0.5*np.vdot(R, R)
@timeIt
def dataObjDeriv(self, m, u=None):
"""
:param numpy.array m: geophysical model
@@ -224,6 +228,7 @@ class BaseInversion(object):
return dmisfit
@timeIt
def dataObj2Deriv(self, m, v, u=None):
"""
:param numpy.array m: geophysical model
+23 -3
View File
@@ -1,6 +1,6 @@
import numpy as np
import matplotlib.pyplot as plt
from SimPEG.utils import mkvc, sdiag, setKwargs, printTitles, printLine, printStoppers, checkStoppers
from SimPEG.utils import mkvc, sdiag, setKwargs, printTitles, printLine, printStoppers, checkStoppers, count, timeIt
norm = np.linalg.norm
import scipy.sparse as sp
from SimPEG import Solver
@@ -106,6 +106,8 @@ class Minimize(object):
debug = False
debugLS = False
counter = None
def __init__(self, **kwargs):
self._id = int(np.random.rand()*1e6) # create a unique identifier to this program to be used in pubsub
self.stoppers = [StoppingCriteria.tolerance_f, StoppingCriteria.moving_x, StoppingCriteria.tolerance_g, StoppingCriteria.norm_g, StoppingCriteria.iteration]
@@ -116,6 +118,7 @@ class Minimize(object):
setKwargs(self, **kwargs)
@timeIt
def minimize(self, evalFunction, x0):
"""
Minimizes the function (evalFunction) starting at the location x0.
@@ -263,6 +266,7 @@ class Minimize(object):
name = self.name if not inLS else self.nameLS
printTitles(self, self.printers if not inLS else self.printersLS, name, pad)
@count
def printIter(self, inLS=False):
"""
**printIter** is called directly after function evaluations.
@@ -289,14 +293,14 @@ class Minimize(object):
stoppers = self.stoppers if not inLS else self.stoppersLS
printStoppers(self, stoppers, pad='', stop=stop, done=done)
@timeIt
def stoppingCriteria(self, inLS=False):
if self._iter == 0:
self.f0 = self.f
self.g0 = self.g
return checkStoppers(self, self.stoppers if not inLS else self.stoppersLS)
@timeIt
def projection(self, p):
"""
projects the search direction.
@@ -309,6 +313,7 @@ class Minimize(object):
"""
return p
@timeIt
def findSearchDirection(self):
"""
**findSearchDirection** should return an approximation of:
@@ -338,6 +343,7 @@ class Minimize(object):
"""
return -self.g
@count
def scaleSearchDirection(self, p):
"""
**scaleSearchDirection** should scale the search direction if appropriate.
@@ -355,6 +361,7 @@ class Minimize(object):
nameLS = "Armijo linesearch"
@timeIt
def modifySearchDirection(self, p):
"""
**modifySearchDirection** changes the search direction based on some sort of linesearch or trust-region criteria.
@@ -391,6 +398,7 @@ class Minimize(object):
return self._LS_xt, self._iterLS < self.maxIterLS
@count
def modifySearchDirectionBreak(self, p):
"""
Code is called if modifySearchDirection fails
@@ -411,6 +419,7 @@ class Minimize(object):
print 'The linesearch got broken. Boo.'
return p, False
@count
def doEndIteration(self, xt):
"""
**doEndIteration** is called at the end of each minimize iteration.
@@ -529,18 +538,22 @@ class ProjectedGradient(Minimize, Remember):
self.aSet_prev = self.activeSet(x0)
@count
def projection(self, x):
"""Make sure we are feasible."""
return np.median(np.c_[self.lower,x,self.upper],axis=1)
@count
def activeSet(self, x):
"""If we are on a bound"""
return np.logical_or(x == self.lower, x == self.upper)
@count
def inactiveSet(self, x):
"""The free variables."""
return np.logical_not(self.activeSet(x))
@count
def bindingSet(self, x):
"""
If we are on a bound and the negative gradient points away from the feasible set.
@@ -552,6 +565,7 @@ class ProjectedGradient(Minimize, Remember):
bind_low = np.logical_and(x == self.upper, self.g <= 0)
return np.logical_or(bind_up, bind_low)
@timeIt
def findSearchDirection(self):
self.aSet_prev = self.activeSet(self.xc)
allBoundsAreActive = sum(self.aSet_prev) == self.xc.size
@@ -592,6 +606,7 @@ class ProjectedGradient(Minimize, Remember):
# aSet_after = self.activeSet(self.xc+p)
return p
@timeIt
def _doEndIteration_ProjectedGradient(self, xt):
aSet = self.activeSet(xt)
bSet = self.bindingSet(xt)
@@ -622,6 +637,8 @@ class ProjectedGradient(Minimize, Remember):
class GaussNewton(Minimize, Remember):
name = 'Gauss Newton'
@timeIt
def findSearchDirection(self):
return Solver(self.H).solve(-self.g)
@@ -632,6 +649,7 @@ class InexactGaussNewton(Minimize, Remember):
maxIterCG = 10
tolCG = 1e-5
@timeIt
def findSearchDirection(self):
# TODO: use BFGS as a preconditioner or gauss sidel of the WtW or solve WtW directly
p, info = sp.linalg.cg(self.H, -self.g, tol=self.tolCG, maxiter=self.maxIterCG)
@@ -640,6 +658,8 @@ class InexactGaussNewton(Minimize, Remember):
class SteepestDescent(Minimize, Remember):
name = 'Steepest Descent'
@timeIt
def findSearchDirection(self):
return -self.g