def __init__(self, V, rank, t_win, alphaWf=0, alphaWt=0, betaWf=0, betaWt=0, betaHf=0, betaHt=0): # Find out if other H parameters are necessary? # TODO: incremental V self.V = V / V.sum() self.f_steps, self.t_steps = self.V.shape self.t_win = t_win self.rank = rank H = np.concatenate([self.V]*rank, axis=1) Hflat = H.flatten()[newaxis,:] Vflat = self.V.flatten()[newaxis,:] # Make the time-independent frequency analyzer self.freq_analyzer = SIPLCA2(H, rank, (self.f_steps, 1), alphaW=alphaWf[...,newaxis], betaW=betaWf, betaH=betaHf) self.meta_freq_analyzer = SIPLCA2(self.V, rank, (self.f_steps, 1), alphaW=alphaWf[...,newaxis], betaW=betaWf, betaH=0) # Make the frequency-independent time-envelope analyzer self.time_analyzer = SIPLCA(Hflat, rank, self.t_win, alphaW=alphaWt[newaxis,...], betaW=betaWt, betaH=betaHt) self.meta_time_analyzer = SIPLCA(Vflat, rank, self.t_win, alphaW=alphaWt[newaxis,...], betaW=betaWt, betaH=0)
class Basilica(object): def __init__(self, V, rank, t_win, alphaWf=0, alphaWt=0, betaWf=0, betaWt=0, betaHf=0, betaHt=0): # Find out if other H parameters are necessary? # TODO: incremental V self.V = V / V.sum() self.f_steps, self.t_steps = self.V.shape self.t_win = t_win self.rank = rank H = np.concatenate([self.V]*rank, axis=1) Hflat = H.flatten()[newaxis,:] Vflat = self.V.flatten()[newaxis,:] # Make the time-independent frequency analyzer self.freq_analyzer = SIPLCA2(H, rank, (self.f_steps, 1), alphaW=alphaWf[...,newaxis], betaW=betaWf, betaH=betaHf) self.meta_freq_analyzer = SIPLCA2(self.V, rank, (self.f_steps, 1), alphaW=alphaWf[...,newaxis], betaW=betaWf, betaH=0) # Make the frequency-independent time-envelope analyzer self.time_analyzer = SIPLCA(Hflat, rank, self.t_win, alphaW=alphaWt[newaxis,...], betaW=betaWt, betaH=betaHt) self.meta_time_analyzer = SIPLCA(Vflat, rank, self.t_win, alphaW=alphaWt[newaxis,...], betaW=betaWt, betaH=0) def run_freq(self, Vf, Wf=None, Zf=None, Hf=None, niter=5): self.freq_analyzer.V = Vf if Wf is None or Zf is None or Hf is None: initW, initZ, initH = self.freq_analyzer.initialize() if Wf is None: Wf = initW if Zf is None: Zf = initZ if Hf is None: Hf = initH for iter in xrange(niter): logprob, WZH = self.freq_analyzer.do_estep(Wf, Zf, Hf) logger.info('Iteration f%d: logprob = %f', iter, logprob) Wf, Zf, Hf = self.freq_analyzer.do_mstep(iter) plt.clf() plt.plot(Wf[...,0]) plt.draw() # Hf : (rank, F, rank*T) # Hf_sum : (rank, F, T) meta_Hf = self.sum_pieces(Hf) meta_logprob, meta_WZH = self.meta_freq_analyzer.do_estep( Wf, Zf, meta_Hf) logger.info('Meta f%d: logprob = %f', iter, logprob) meta_Wf, meta_Zf, meta_Hf = self.meta_freq_analyzer.do_mstep(0) return Wf, Zf, Hf, meta_Hf # now do the same for run_time def run_time(self, Vt, Wt=None, Zt=None, Ht=None, niter=5): self.time_analyzer.V = Vt if Wt is None or Zt is None or Ht is None: initW, initZ, initH = self.time_analyzer.initialize() if Wt is None: Wt = initW if Zt is None: Zt = initZ if Ht is None: Ht = initH for iter in xrange(niter): logprob, WZH = self.time_analyzer.do_estep(Wt, Zt, Ht) logger.info('Iteration t%d: logprob = %f', iter, logprob) Wt, Zt, Ht = self.time_analyzer.do_mstep(iter) assert Wt.ndim == 3 assert Zt.ndim == 1 assert Ht.ndim == 2 # Ht : (rank, rank*F*T) # Ht_sum : (rank, F*T) meta_Ht = self.sum_pieces(Ht) Htt = meta_Ht.reshape(self.rank, self.f_steps, self.t_steps) Hmax = np.max(Htt) plt.clf() plt.imshow(np.rollaxis(Htt[0:3]/Hmax*2, 0, 3), origin='lower', aspect='auto', interpolation='nearest') plt.draw() meta_logprob, meta_WZH = self.meta_time_analyzer.do_estep(Wt, Zt, meta_Ht) logger.info('Meta t%d: logprob = %f', iter, logprob) meta_Wt, meta_Zt, meta_Ht = self.meta_time_analyzer.do_mstep(0) return Wt, Zt, Ht, meta_Ht def run(self, V, niter=5, nsubiter=10, Wf=None, Zf=None, Hf=None, Wt=None, Zt=None, Ht=None, play_func=None): meta_Hf = np.dstack([self.V] * self.rank).transpose(2,0,1) for iter in xrange(niter): # run_freq returns Hf : (rank, F, T) # flatten to get (1, rank*F*T) Vt = meta_Hf.flatten()[newaxis,:] Wt, Zt, Ht, meta_Ht =\ self.run_time(Vt, Wt, Zt, Ht, nsubiter) # run_time returns Ht : (rank, F*T) # reshape to get (rank, F, T) temp = meta_Ht.reshape(self.rank, self.f_steps, self.t_steps) # transpose to get (F, rank, T) temp = temp.transpose(1,0,2) # reshape to get (F, rank*T) Vf = np.reshape(temp, (self.f_steps, self.rank*self.t_steps)) Wf, Zf, Hf, meta_Hf =\ self.run_freq(Vf, Wf, Zf, Hf, nsubiter) rec = self.reconstruct(Wf, Zf, Wt, Zt, Ht**2) if play_func: play_func(rec) return Wf, Zf, Hf, Wt, Zt, Ht, meta_Hf, meta_Ht, rec def reconstruct(self, Wf, Zf, Wt, Zt, Ht): # V = convolve(Wf * Zf, meta_Hf) # meta_Hf = Vt = convolve(Wt * Zt, Ht) # V = convolve(Wf * Zf, Wt * Zt, Ht) Hf = self.time_analyzer.reconstruct(Wt, Zt, Ht).reshape(self.rank, self.f_steps, self.t_steps) rec = self.freq_analyzer.reconstruct(Wf, Zf, Hf) return rec def sum_pieces(self, array): """ Given an array made of `r` equal-sized pieces that are concatenated along the array's last axis, return the smaller array that results from summing these pieces. `r` is defined to be `self.rank`. """ assert array.shape[-1] % self.rank == 0 width = array.shape[-1] // self.rank shape = list(array.shape) shape[-1] = width result = np.zeros(tuple(shape)) for i in xrange(self.rank): result += array[..., i*width : (i+1)*width] return result