from keras import backend as K
from keras.engine.topology import Layer
from keras.models import Sequential
import numpy as np
class EchoLayer(Layer):
# This (differentiably) tries to pick out one element from an feature vector and adds
# (a multiple of) it to the 0'th feature
# Designed to take an input of shape (batch_size, 1, window_length) ...where window_length is the
# number of features.... and output (batch_size, 1)
#
# The question we're investigating is, for modeling an echo, whether this approach is faster/more
# efficient than training an LSTM with an entire matrix of weights that all end up needing to be
# zero except for one element.
def __init__(self, output_dim, **kwargs):
assert (1 == output_dim)
self.output_dim = output_dim
super(EchoLayer, self).__init__(**kwargs)
def build(self, input_shape):
# we want to define two trainable single-value (scalar) variables: index and ratio
# we don't want these to be an entire matrix of weights
#self.index = K.variable(np.zeros(1).astype(np.float32),trainable=True) # Didn't work; variables aren't "trainable"?
#self.ratio = K.variable(np.ones(1).astype(np.float32),trainable=True)
self.index = self.add_weight(shape=(input_shape[1], self.output_dim), initializer='uniform', trainable=True)
self.ratio = self.add_weight(shape=(input_shape[1], self.output_dim), initializer='uniform', trainable=True)
super(EchoLayer, self).build(input_shape)
def call(self, x):
# for each member of batch...
batch_output = np.zeros([x.shape[0],1])
for batch_i in range(x.shape[0]):
# How to get the value of the variables (self.index and self.ratio)? K.eval...()?
ival = self.index[batch_i,0]
rval = self.ratio[batch_i,0]
xp = range(x.shape[-1])
fp = x[batch_i, 0, :]
print(" call: x.shape = ",x.shape)
print(" ival = ",ival)
print(" rval = ",rval)
print(" xp = ",xp)
print(" fp = ",fp)
batch_output[batch_i,0] = x[batch_i,0,0] + self.ratio * np.interp( ival, xp, fp)
return batch_output
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_dim)
def EchoNet(batch_size=1000, tsteps=1, window_length=5000):
model = Sequential()
model.add(EchoLayer(1, batch_input_shape=(batch_size, tsteps, window_length)))
model.compile(loss='mae', optimizer='nadam')
return model
model = EchoNet()
class EchoLayer(Layer):
# This (differentiably) tries to pick out one element from an feature vector and adds
# (a multiple of) it to the 0'th feature
# Designed to take an input of shape (batch_size, 1, window_length) and output (batch_size, 1)
#
# The question we're investigating is, for model an echo, whether this approach is faster/more
# efficient than training an LSTM with an entire matrix of weights to all be zero except for one element.
def __init__(self, output_dim, **kwargs):
assert (1 == output_dim)
self.output_dim = output_dim
super(EchoLayer, self).__init__(**kwargs)
def build(self, input_shape):
# we want to define two trainable single-value (scalar) variables: index and ratio
# we don't want these to be an entire matrix of weights
#self.index = K.variable(np.zeros(1).astype(np.float32),trainable=True) # Didn't work; variables aren't "trainable"?
#self.ratio = K.variable(np.ones(1).astype(np.float32),trainable=True)
self.index = self.add_weight(shape=(input_shape[0], self.output_dim), initializer='zeros', trainable=True)
self.ratio = self.add_weight(shape=(input_shape[0], self.output_dim), initializer='uniform', trainable=True)
super(EchoLayer, self).build(input_shape)
def call(self, x):
xshape = K.int_shape(x)
ival = K.batch_get_value(self.index)
rval = K.batch_get_value(self.ratio)
ilo = np.floor(ival).astype(np.int32)
ihi = np.ceil(ival).astype(np.int32)
picker_arr = np.zeros([xshape[0], 1])
# really need to add some kind of interpolation here...
picker_arr[ilo] = rval[ilo]
picker_arr[ihi] = rval[ihi]
picker = K.variable(picker_arr)
return K.dot(picker, x)
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_dim)
Is there another place where they need to be specified? I was under the impression that such things were automatic in Keras 2.
class EchoLayer(Layer):
# This (differentiably) tries to pick out one element from an feature vector and adds
# (a multiple of) it to the 0'th feature
# Designed to take an input of shape (batch_size, 1, window_length) and output (batch_size, 1)
#
# The question we're investigating is, for model an echo, whether this approach is faster/more
# efficient than training an LSTM with an entire matrix of weights to all be zero except for one element.
def __init__(self, output_dim, **kwargs):
assert (1 == output_dim)
self.output_dim = output_dim
super(EchoLayer, self).__init__(**kwargs)
def build(self, input_shape):
# we want to define two trainable single-value (scalar) variables: index and ratio
# we don't want these to be an entire matrix of weights
print(" input_shape = ",input_shape)
self.delay = self.add_weight(shape=(input_shape[1], self.output_dim), initializer='zeros', trainable=True)
self.ratio = self.add_weight(shape=(input_shape[1], self.output_dim), initializer='uniform', trainable=True)
# Which one of these 'self.indices='' to use? Really just want K.range()
#self.indices = K.variable(value=np.arange(0,input_shape[-1])) # list of indices of feature vec
if ('tensorflow' == backend.backend()):
self.indices = tf.range(0,limit=input_shape[-1], name='indices', dtype=tf.float32)
else:
self.indices = theano.tensor.arange(input_shape[-1], dtype='float32')
print(" delay shape = ",K.int_shape(self.delay))
#print(" indices shape = ",K.int_shape(self.indices)) # "TypeError: Not a Keras tensor"
super(EchoLayer, self).build(input_shape)
def call(self, x):
# "kernel" is a gaussian over indices, centered at delay
kernel = self.ratio * K.exp( K.pow((self.indices-self.delay)/.6,2) )
print(" kernel shape = ",K.int_shape(kernel))
return K.batch_dot(x, kernel, axes=[2,1])
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_dim)
kernel = self.ratio * K.exp( K.pow((self.indices-self.delay)/.6,2) ) class EchoLayer(Layer):
# This (differentiably) tries to pick out one element from an feature vector and adds
# (a multiple of) it to the 0'th feature
# Designed to take an input of shape (batch_size, 1, window_length) and output (batch_size, 1)
#
# The question we're investigating is, for model an echo, whether this approach is faster/more
# efficient than training an LSTM with an entire matrix of weights to all be zero except for one element.
def __init__(self, output_dim, **kwargs):
self.output_dim = output_dim
assert (1 == output_dim)
super(EchoLayer, self).__init__(**kwargs)
def build(self, input_shape):
# we want to define two trainable single-value (scalar) variables: index and ratio
# we don't want these to be an entire matrix of weights
print(" input_shape = ",input_shape)
self.delay = self.add_weight(shape=(input_shape[1], self.output_dim), initializer='ones', trainable=True)
self.ratio = self.add_weight(shape=(input_shape[1], self.output_dim), initializer='ones', trainable=True)
# indices is just a list of indices of feature vec; constant; does not need to be trainable
np_indices = np.arange(0,input_shape[-1])
np2 = np.tile(np_indices,(input_shape[0],1) ) # apprently we need batch_size copies of all indices
self.indices = K.variable(value=np2)
# this is the array simply to hold the index for the value at the "current time"; constant, non-trainable
np_idx2 = np.zeros((input_shape[0],input_shape[2],1))
np_idx2[:,0,0] = 1.0
self.curr_val = K.variable(value=np_idx2)
print(" delay shape = ",K.int_shape(self.delay))
print(" indices shape = ",K.int_shape(self.indices)) # "TypeError: Not a Keras tensor"
print(" curr_val.shape = ",K.int_shape(self.curr_val))
super(EchoLayer, self).build(input_shape)
def call(self, x):
# "kernel" is a gaussian over indices, centered at delay
print(" self.delay, self.ratio = ",self.delay,self.ratio)
kernel = self.ratio * K.exp( -1*K.pow((self.indices-self.delay)/.6, 2) )
kdim = K.int_shape(kernel)
kernel = K.reshape( kernel,(kdim[0],kdim[1],1)) # because of bug in K.batch_dot for Tensorflow backend
print(" kernel shape = ",K.int_shape(kernel))
print(" curr_val.shape = ",K.int_shape(self.curr_val))
kernel = kernel + self.curr_val
#kernel[:,0,0] = 1.0
#output = K.batch_dot(x, kernel, axes=[2,2])
output = K.batch_dot(x, kernel)
#print(" output shape = ",K.int_shape(output))
return output
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_dim)