def update(self, model, cache=None): """ TODO: Handle truncated Gaussians noise for channel params """ # Keep sufficient stats for a Gaussian noise model N = 0 beta_V_hat = 0 # beta_ch_hat = 0 # Get the latent voltages for ds in model.data_sequences: latent = as_matrix(ds.latent) # The transition model is a noisy Hodgkin Huxley proposal prop = TruncatedHodgkinHuxleyProposal( model.population, ds.t, ds.input, as_matrix(np.zeros(1, dtype=model.population.latent_dtype))) dt = ds.t[1:] - ds.t[:-1] # import pdb; pdb.set_trace() pred = np.zeros((latent.shape[0], ds.T - 1)) for t in np.arange(ds.T - 1): pt, _, _ = prop.sample_next(t, latent[:, t, np.newaxis], t + 1) pred[:, t] = pt.ravel() # pred2,_ = prop.sample_next(np.arange(ds.T-1), # latent[:,:-1], # np.arange(1,ds.T)) # if not np.allclose(pred, pred2): # import pdb; pdb.set_trace() for neuron in model.population.neurons: for compartment in neuron.compartments: V = get_item_at_path( as_sarray(latent, model.population.latent_dtype), compartment.path)['V'] Vpred = get_item_at_path( as_sarray(pred, model.population.latent_dtype), compartment.path)['V'] dV = (Vpred - V[1:]) / dt # Update sufficient stats N += len(dV) beta_V_hat += (dV**2).sum() # Sample a new beta_V sig2_V = 1.0 / np.random.gamma( hypers['a_sig_V'].value + N / 2., 1.0 / (hypers['b_sig_V'].value + beta_V_hat / 2.)) hypers['sig_V'].value = np.sqrt(sig2_V)
def logp(self, X, Z): # View as the model's dtypes obs = as_sarray(X, self.model.observation.observed_dtype) latent = as_sarray(Z, self.model.population.latent_dtype) logp = self.model.observation.logp(latent, obs) # Check if any observations are out of the allowable range # oob_lb = np.any(Z < self.lb, axis=0) oob_lb = np.sum(Z < self.lb, axis=0) > 0 oob_ub = np.sum(Z > self.ub, axis=0) > 0 oob = oob_lb | oob_ub logp[oob] = -np.inf # logp += -np.inf * oob return logp
def _hh_dynamics(z_vec, ti): # Set the inputs inpt = I[ti] latent = as_sarray(z_vec, population.latent_dtype) # state = as_sarray(population.evaluate_state(latent, inpt), population.state_dtype) dzdt = population.kinetics(latent, inpt) return dzdt.view(np.float)
def _hh_dynamics(z_vec, ti): # Set the inputs inpt = I[ti] latent = as_sarray(z_vec, population.latent_dtype) # state = as_sarray(population.evaluate_state(latent, inpt), population.state_dtype) dzdt = population.kinetics(latent, inpt) return dzdt.view(np.float)
def update(self, model, cache=None): """ :param current_state: :return: """ population = model.population # Update each data sequence one at a time for data in model.data_sequences: t = data.t T = data.T latent = data.latent inpt = data.input state = data.states obs = data.observations # View the latent state as a matrix D = sz_dtype(latent.dtype) z = as_matrix(latent, D) x = as_matrix(obs) lb = population.latent_lb ub = population.latent_ub p_initial = StaticTruncatedGaussianDistribution( D, self.mu_initial, self.sig_initial, lb, ub) # The observation model gives us a noisy version of the voltage lkhd = ObservationLikelihood(model) # The transition model is a noisy Hodgkin Huxley proposal # prop = TruncatedHodgkinHuxleyProposal(population, t, inpt, self.sig_trans) prop = HodgkinHuxleyProposal(population, t, inpt, self.sig_trans) # Run the particle Gibbs step with ancestor sampling # Create a conditional particle filter with ancestor sampling pf = ParticleGibbsAncestorSampling(D, T, 0, x[:, 0], prop, lkhd, p_initial, z, Np=self.N_particles) for ind in np.arange(1, T): x_curr = x[:, ind] pf.filter(ind, x_curr) # Sample a particular weight trace given the particle weights at time T i = np.random.choice(np.arange(pf.Np), p=pf.trajectory_weights) # z_inf = pf.trajectories[:,i,:].reshape((D,T)) z_inf = pf.get_trajectory(i).reshape((D, T)) # Update the data sequence's latent and state data.latent = as_sarray(z_inf, population.latent_dtype) data.states = population.evaluate_state(data.latent, inpt)
def update(self, model, cache=None): """ TODO: Handle truncated Gaussians noise for channel params """ # Keep sufficient stats for a Gaussian noise model N = 0 beta_V_hat = 0 # beta_ch_hat = 0 # Get the latent voltages for ds in model.data_sequences: latent = as_matrix(ds.latent) # The transition model is a noisy Hodgkin Huxley proposal prop = TruncatedHodgkinHuxleyProposal(model.population, ds.t, ds.input, as_matrix(np.zeros(1, dtype=model.population.latent_dtype))) dt = ds.t[1:] - ds.t[:-1] # import pdb; pdb.set_trace() pred = np.zeros((latent.shape[0], ds.T-1)) for t in np.arange(ds.T-1): pt,_,_ = prop.sample_next(t, latent[:,t,np.newaxis], t+1) pred[:,t] = pt.ravel() # pred2,_ = prop.sample_next(np.arange(ds.T-1), # latent[:,:-1], # np.arange(1,ds.T)) # if not np.allclose(pred, pred2): # import pdb; pdb.set_trace() for neuron in model.population.neurons: for compartment in neuron.compartments: V = get_item_at_path(as_sarray(latent, model.population.latent_dtype), compartment.path)['V'] Vpred = get_item_at_path(as_sarray(pred, model.population.latent_dtype), compartment.path)['V'] dV = (Vpred - V[1:])/dt # Update sufficient stats N += len(dV) beta_V_hat += (dV**2).sum() # Sample a new beta_V sig2_V = 1.0/np.random.gamma(hypers['a_sig_V'].value + N/2., 1.0/(hypers['b_sig_V'].value + beta_V_hat/2.)) hypers['sig_V'].value = np.sqrt(sig2_V)
def _hh_kinetics(self, index, Z): D,Np = Z.shape # Get the current input and latent states current_inpt = self.inpt[index] latent = as_sarray(Z, self.population.latent_dtype) # Run the kinetics forward dxdt = self.population.kinetics(latent, current_inpt) # TODO: Wow, this is terrible. Converting to/from numpy struct array and # regular arrays, and maintaining the correct shape, is a mega pain in the ass return dxdt.view(np.float).reshape((Np,D)).T
def update(self, model, cache=None): """ :param current_state: :return: """ population = model.population # Update each data sequence one at a time for data in model.data_sequences: t = data.t T = data.T latent = data.latent inpt = data.input state = data.states obs = data.observations # View the latent state as a matrix D = sz_dtype(latent.dtype) z = as_matrix(latent, D) x = as_matrix(obs) lb = population.latent_lb ub = population.latent_ub p_initial = StaticTruncatedGaussianDistribution(D, self.mu_initial, self.sig_initial, lb, ub) # The observation model gives us a noisy version of the voltage lkhd = ObservationLikelihood(model) # The transition model is a noisy Hodgkin Huxley proposal # prop = TruncatedHodgkinHuxleyProposal(population, t, inpt, self.sig_trans) prop = HodgkinHuxleyProposal(population, t, inpt, self.sig_trans) # Run the particle Gibbs step with ancestor sampling # Create a conditional particle filter with ancestor sampling pf = ParticleGibbsAncestorSampling(D, T, 0, x[:,0], prop, lkhd, p_initial, z, Np=self.N_particles) for ind in np.arange(1,T): x_curr = x[:,ind] pf.filter(ind, x_curr) # Sample a particular weight trace given the particle weights at time T i = np.random.choice(np.arange(pf.Np), p=pf.trajectory_weights) # z_inf = pf.trajectories[:,i,:].reshape((D,T)) z_inf = pf.get_trajectory(i).reshape((D,T)) # Update the data sequence's latent and state data.latent = as_sarray(z_inf, population.latent_dtype) data.states = population.evaluate_state(data.latent, inpt)
def recreate(model, t, I): # TODO: Iterate over populations and neurons assert model.population is not None, "Models population must be instantiated" population = model.population T = len(t) # Set up the initial conditions with steady state values z0 = population.steady_state() # Create a function to implement hodgkin huxley dynamics def _hh_dynamics(z_vec, ti): # Set the inputs inpt = I[ti] latent = as_sarray(z_vec, population.latent_dtype) # state = as_sarray(population.evaluate_state(latent, inpt), population.state_dtype) dzdt = population.kinetics(latent, inpt) return dzdt.view(np.float) # Do forward euler by hand. z0 = z0.view(np.float) D = len(z0) z = np.zeros((D, T)) z[:, 0] = z0 lb = population.latent_lb ub = population.latent_ub for ti in np.arange(1, T): dt = t[ti] - t[ti - 1] z[:, ti] = z[:, ti - 1] + dt * _hh_dynamics(z[:, ti - 1], ti - 1) z[:, ti] = np.clip(z[:, ti], lb, ub) # Convert back to numpy struct array Z = as_sarray(z, population.latent_dtype) # Compute the corresponding states S = population.evaluate_state(Z, I) # sample the observation model given the latent variables of the neuron O = model.observation.sample(Z) # Package into a data sequence ds = DataSequence(name, t, stimuli, O, Z, I, S) return ds
def recreate(model, t, I): # TODO: Iterate over populations and neurons assert model.population is not None, "Models population must be instantiated" population = model.population T = len(t) # Set up the initial conditions with steady state values z0 = population.steady_state() # Create a function to implement hodgkin huxley dynamics def _hh_dynamics(z_vec, ti): # Set the inputs inpt = I[ti] latent = as_sarray(z_vec, population.latent_dtype) # state = as_sarray(population.evaluate_state(latent, inpt), population.state_dtype) dzdt = population.kinetics(latent, inpt) return dzdt.view(np.float) # Do forward euler by hand. z0 = z0.view(np.float) D = len(z0) z = np.zeros((D,T)) z[:,0] = z0 lb = population.latent_lb ub = population.latent_ub for ti in np.arange(1,T): dt = t[ti]-t[ti-1] z[:,ti] = z[:,ti-1] + dt * _hh_dynamics(z[:,ti-1], ti-1) z[:,ti] = np.clip(z[:,ti], lb, ub) # Convert back to numpy struct array Z = as_sarray(z, population.latent_dtype) # Compute the corresponding states S = population.evaluate_state(Z, I) # sample the observation model given the latent variables of the neuron O = model.observation.sample(Z) # Package into a data sequence ds = DataSequence(name, t, stimuli, O, Z, I, S) return ds
def simulate(model, t, stimuli, name=None, have_noise=True, I=None): """ Simulate a model containing a population of neurons, an observation model, and a stimulus. Right now this only is set up for a single neuron model :param model: :return: """ # TODO: Iterate over populations and neurons assert model.population is not None, "Models population must be instantiated" population = model.population #import pdb; pdb.set_trace() # Make sure stimuli is a list if isinstance(stimuli, Stimulus): stimuli = [stimuli] else: assert isinstance(stimuli, list) or I is not None T = len(t) if I is None: I = np.zeros((T, ), dtype=population.input_dtype) for stim in stimuli: stim.set_input(t, I) # Set up the initial conditions with steady state values z0 = population.steady_state() # Create a function to implement hodgkin huxley dynamics def _hh_dynamics(z_vec, ti): # Set the inputs inpt = I[ti] #import pdb; pdb.set_trace() latent = as_sarray(z_vec, population.latent_dtype) # state = as_sarray(population.evaluate_state(latent, inpt), population.state_dtype) dzdt = population.kinetics(latent, inpt) return dzdt.view(np.float) # Do forward euler by hand. z0 = z0.view(np.float) D = len(z0) z = np.zeros((D, T)) z[:, 0] = z0 lb = population.latent_lb ub = population.latent_ub if have_noise: noisedistribution = TruncatedGaussianDistribution() # TODO: Fix this hack sig_trans = np.ones(1, dtype=population.latent_dtype) sig_trans.fill(np.asscalar(hypers['sig_ch'].value)) for neuron in population.neurons: for compartment in neuron.compartments: sig_trans[neuron.name][ compartment.name]['V'] = hypers['sig_V'].value sig_trans = sig_trans.view(dtype=np.float) for ti in np.arange(1, T): dt = t[ti] - t[ti - 1] z[:, ti] = z[:, ti - 1] + dt * _hh_dynamics(z[:, ti - 1], ti - 1) z[:, ti] = np.clip(z[:, ti], lb, ub) if have_noise: # Add Gaussian noise noise_lb = lb - z[:, ti] noise_ub = ub - z[:, ti] # Scale down the noise to account for time delay # sig = sig_trans * np.sqrt(dt) sig = sig_trans * dt # TODO: Remove the zeros_like requirement noise = noisedistribution.sample(mu=np.zeros_like(z[:, ti]), sigma=sig, lb=noise_lb, ub=noise_ub) # import pdb; pdb.set_trace() z[:, ti] += noise # Convert back to numpy struct array Z = as_sarray(z, population.latent_dtype) # Compute the corresponding states S = population.evaluate_state(Z, I) # sample the observation model given the latent variables of the neuron O = model.observation.sample(Z) # Package into a data sequence ds = DataSequence(name, t, stimuli, O, Z, I, S) return ds
def simulate(model, t, stimuli, name=None, have_noise=True, I=None): """ Simulate a model containing a population of neurons, an observation model, and a stimulus. Right now this only is set up for a single neuron model :param model: :return: """ # TODO: Iterate over populations and neurons assert model.population is not None, "Models population must be instantiated" population = model.population #import pdb; pdb.set_trace() # Make sure stimuli is a list if isinstance(stimuli, Stimulus): stimuli = [stimuli] else: assert isinstance(stimuli, list) or I is not None T = len(t) if I is None: I = np.zeros((T,), dtype=population.input_dtype) for stim in stimuli: stim.set_input(t, I) # Set up the initial conditions with steady state values z0 = population.steady_state() # Create a function to implement hodgkin huxley dynamics def _hh_dynamics(z_vec, ti): # Set the inputs inpt = I[ti] #import pdb; pdb.set_trace() latent = as_sarray(z_vec, population.latent_dtype) # state = as_sarray(population.evaluate_state(latent, inpt), population.state_dtype) dzdt = population.kinetics(latent, inpt) return dzdt.view(np.float) # Do forward euler by hand. z0 = z0.view(np.float) D = len(z0) z = np.zeros((D,T)) z[:,0] = z0 lb = population.latent_lb ub = population.latent_ub if have_noise: noisedistribution = TruncatedGaussianDistribution() # TODO: Fix this hack sig_trans = np.ones(1, dtype=population.latent_dtype) sig_trans.fill(np.asscalar(hypers['sig_ch'].value)) for neuron in population.neurons: for compartment in neuron.compartments: sig_trans[neuron.name][compartment.name]['V'] = hypers['sig_V'].value sig_trans = sig_trans.view(dtype=np.float) for ti in np.arange(1,T): dt = t[ti]-t[ti-1] z[:,ti] = z[:,ti-1] + dt * _hh_dynamics(z[:,ti-1], ti-1) z[:,ti] = np.clip(z[:,ti], lb, ub) if have_noise: # Add Gaussian noise noise_lb = lb - z[:,ti] noise_ub = ub - z[:,ti] # Scale down the noise to account for time delay # sig = sig_trans * np.sqrt(dt) sig = sig_trans * dt # TODO: Remove the zeros_like requirement noise = noisedistribution.sample(mu=np.zeros_like(z[:,ti]), sigma=sig, lb=noise_lb, ub=noise_ub) # import pdb; pdb.set_trace() z[:,ti] += noise # Convert back to numpy struct array Z = as_sarray(z, population.latent_dtype) # Compute the corresponding states S = population.evaluate_state(Z, I) # sample the observation model given the latent variables of the neuron O = model.observation.sample(Z) # Package into a data sequence ds = DataSequence(name, t, stimuli, O, Z, I, S) return ds