Guest User

Untitled

a guest
Dec 16th, 2017
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.01 KB | None | 0 0
  1. """Sampling parameters of a lorenz attractor.
  2.  
  3. The forward pass integrates the lorenz attractor ODE system using
  4. tt.scan with a Runge-Kutta integrator. The predicted high-resolution
  5. timecourse is interpolated down so it can be compared to low-density
  6. observations.
  7. """
  8. import abc
  9. import numpy
  10. import pymc3
  11. from matplotlib import pyplot
  12. import theano
  13. import theano.tensor as tt
  14. import scipy.integrate
  15.  
  16. def interpolation_weights(x_predicted, x_interpolated):
  17. """Computes weights for use in left-handed dot product with y_fix.
  18.  
  19. Args:
  20. x_predicted (numpy.ndarray): x-values at which Y is predicted
  21. x_interpolated (numpy.ndarray): x-values for which Y is desired
  22.  
  23. Returns:
  24. weights (numpy.ndarray): weights for Y_desired = dot(weights, Y_predicted)
  25. """
  26. x_repeat = numpy.tile(x_interpolated[:,None], (len(x_predicted),))
  27. distances = numpy.abs(x_repeat - x_predicted)
  28.  
  29. x_indices = numpy.searchsorted(x_predicted, x_interpolated)
  30.  
  31. weights = numpy.zeros_like(distances)
  32. idx = numpy.arange(len(x_indices))
  33. weights[idx,x_indices] = distances[idx,x_indices-1]
  34. weights[idx,x_indices-1] = distances[idx,x_indices]
  35. weights /= numpy.sum(weights, axis=1)[:,None]
  36. return weights
  37.  
  38.  
  39. class Integrator(object):
  40. """Abstract class of an ODE solver to be used with Theano scan."""
  41. __metaclass__ = abc.ABCMeta
  42.  
  43. def step(self, t, dt, y, dydt, theta):
  44. """Symbolic integration step.
  45.  
  46. Args:
  47. t (TensorVariable): timepoint to be passed to [dydt]
  48. dt (TensorVariable): stepsize
  49. y (TensorVariable): vector of current states
  50. dydt (callable): dydt function of the model like dydt(y, t, theta)
  51. theta (TensorVariable): system parameters
  52.  
  53. Returns:
  54. TensorVariable: yprime
  55. """
  56. raise NotImplementedError()
  57.  
  58.  
  59. class RungeKutta(Integrator):
  60. def step(self, t, dt, y, dydt, theta):
  61. k1 = dt*dydt(y, t, theta)
  62. k2 = dt*dydt(y + 0.5*k1, t, theta)
  63. k3 = dt*dydt(y + 0.5*k2, t, theta)
  64. k4 = dt*dydt(y + k3, t, theta)
  65. y_np1 = y + (1./6.)*k1 + (1./3.)*k2 + (1./3.)*k3 + (1./6.)*k4
  66. return y_np1
  67.  
  68.  
  69. class TheanoIntegrationOps(object):
  70. """This is not actually a real Op, but it can be used as if.
  71. It does differentiable solving of a dynamic system using the provided 'step_theano' method.
  72.  
  73. When called, it essentially creates all the steps in the computation graph to get from y0/theta
  74. to Y_hat.
  75. """
  76. def __init__(self, dydt_theano, integrator:Integrator):
  77. """Creates an Op that uses the [integrator] to solve [dydt].
  78.  
  79. Args:
  80. dydt_theano (callable): function that computes the first derivative of the system
  81. integrator (Integrator): integrator to use for solving
  82. """
  83. self.dydt_theano = dydt_theano
  84. self.integrator = integrator
  85. return super().__init__()
  86.  
  87. def __step_theano(self, t, y_t, dt_t, t_theta):
  88. """Step method that will be used in tt.scan.
  89.  
  90. Uses the integrator to give a better approximation than dydt alone.
  91.  
  92. Args:
  93. t (TensorVariable): time since intial state
  94. y_t (TensorVariable): current state of the system
  95. dt_t (TensorVariable): stepsize
  96. t_theta (TensorVariable): system parameters
  97.  
  98. Returns:
  99. TensorVariable: change in y at time t
  100. """
  101. return self.integrator.step(t, dt_t, y_t, self.dydt_theano, t_theta)
  102.  
  103. def __call__(self, y0, theta, dt, n):
  104. """Creates the computation graph for solving the ODE system.
  105.  
  106. Args:
  107. y0 (TensorVariable or array): initial system state
  108. theta (TensorVariable or array): system parameters
  109. dt (float): fixed stepsize for solving
  110. n (int): number of solving iterations
  111.  
  112. Returns:
  113. TensorVariable: system state y for all t in numpy.arange(0, dt*n) with shape (len(y0),n)
  114. """
  115. # TODO: check dtypes, stack and raise warnings
  116. t_y0 = tt.as_tensor_variable(y0)
  117. t_theta = tt.as_tensor_variable(theta)
  118.  
  119. Y_hat, updates = theano.scan(fn=self.__step_theano,
  120. outputs_info =[{'initial':t_y0}],
  121. sequences=[theano.tensor.arange(dt, dt*n, dt)],
  122. non_sequences=[dt, t_theta],
  123. n_steps=n-1)
  124.  
  125. # scan does not return y0, so it must be concatenated
  126. Y_hat = tt.concatenate((t_y0[None,:], Y_hat))
  127. # return as (len(y0),n)
  128. Y_hat = tt.transpose(Y_hat)
  129. return Y_hat
  130.  
  131.  
  132. class InterpolationOps(object):
  133. """Linearly interpolates the entries in a tensor according to vectors of
  134. predicted and desired coordinates.
  135. """
  136. def __init__(self, x_predicted, x_interpolated):
  137. """Prepare an interpolation subgraph.
  138.  
  139. Args:
  140. x_predicted (ndarray): x-coordinates for which Y will be predicted (T_pred,)
  141. x_interpolated (ndarray): x-coordinates for which Y is desired (T_data,)
  142. """
  143. assert x_interpolated[-1] <= x_predicted[-1], "x_predicted[-1]={} but " \
  144. "x_interpolated[-1]={}".format(x_predicted[-1], x_interpolated[-1])
  145. self.x_predicted = x_predicted
  146. self.x_interpolated = x_interpolated
  147. self.weights = tt.as_tensor_variable(
  148. interpolation_weights(x_predicted, x_interpolated))
  149. return super().__init__()
  150.  
  151. def __call__(self, Y_predicted):
  152. """Symbolically apply interpolation.
  153.  
  154. Args:
  155. Y_predicted (ndarray or TensorVariable): predictions at x_pred with shape (N_Y,T_pred)
  156.  
  157. Returns:
  158. Y_interpolated (TensorVariable): interpolated predictions at x_data with shape (N_Y,T_data)
  159. """
  160. Y_predicted = tt.as_tensor_variable(Y_predicted)
  161. Y_interpolated = tt.dot(self.weights, tt.transpose(Y_predicted))
  162. return tt.transpose(Y_interpolated)
  163.  
  164. def dydt(y, t, theta):
  165. sigma, rho, beta = theta
  166. yprime = [
  167. sigma*(y[1] - y[0]),
  168. y[0]*(rho - y[2]) - y[1],
  169. y[0]*y[1] - beta*y[2]
  170. ]
  171. return yprime
  172.  
  173. def dydt_theano(y, t, theta):
  174. # get parameters
  175. sigma = theta[0]
  176. rho = theta[1]
  177. beta = theta[2]
  178. # set up differential equations
  179. yprime = tt.zeros_like(y)
  180. yprime = tt.set_subtensor(yprime[0], sigma*(y[1] - y[0]) )
  181. yprime = tt.set_subtensor(yprime[1], y[0]*(rho - y[2]) - y[1])
  182. yprime = tt.set_subtensor(yprime[2], y[0]*y[1] - beta*y[2] )
  183. return yprime
  184.  
  185. def run():
  186. # x, y, z, a, b, c
  187. truth = numpy.array([2.2, 5.3, 7.4, 9.5, 27, 9/3])
  188. x = numpy.linspace(0, 1, 20)
  189. y = y = scipy.integrate.odeint(dydt, truth[:3], x, (truth[3:],))
  190.  
  191. #pyplot.plot(x,y)
  192. #pyplot.show()
  193.  
  194. dt = 0.001
  195.  
  196. integrator = RungeKutta()
  197.  
  198. pmodel = pymc3.Model()
  199.  
  200. with pmodel:
  201. # Priors
  202. x0 = pymc3.Uniform('x0', -5.01, 10.01, testval=2.0)
  203. y0 = pymc3.Uniform('y0', -2.01, 13.01, testval=5.0)
  204. z0 = pymc3.Uniform('z0', 0.01, 15.01, testval=7.0)
  205. a = pymc3.Normal('a', mu=10.0, sd=1.1)
  206. b = pymc3.Normal('b', mu=28.0, sd=1.2)
  207. c = pymc3.Normal('c', mu=8/3 , sd=0.3)
  208.  
  209. T_y0 = [x0, y0, z0]
  210. T_theta = [a, b, c]
  211.  
  212. # Prediction
  213. x_max = x[-1]
  214. x_any = x
  215. n_any = len(x_any)
  216. n_pred = int(numpy.ceil(x_max / dt)+1)
  217.  
  218. Y_hat_TV = TheanoIntegrationOps(dydt_theano, integrator)(T_y0, T_theta, dt, n_pred)
  219. # theano implementations only predicts in these regular intervals:
  220. x_pred = numpy.linspace(0, dt*n_pred, n_pred)
  221. # and usually they must be interpolated to the observation timepoints
  222. if not numpy.array_equal(x_pred, x_any):
  223. Y_hat_TV = InterpolationOps(x_pred, x_any)(Y_hat_TV)
  224.  
  225. # loglikelihood
  226. for i, label in enumerate(['x', 'y', 'z']):
  227. L = pymc3.Normal(label + '_obs', mu=Y_hat_TV[i], sd=0.1, observed=y.T[i])
  228.  
  229.  
  230. with pmodel:
  231. nutstrace = pymc3.sample(chains=1, njobs=1)
  232.  
  233.  
  234. if __name__ == '__main__':
  235. print('pymc3 version {}'.format(pymc3.__version__))
  236. run()
Add Comment
Please, Sign In to add comment