# Path: layers/hidden_layer.py
# class HiddenLayer(object):
#     def __init__(self, rng, input, n_in, n_out, training_mode, dropout_prob, activation, weights_variance):
#         self.input = input
#         if activation == 'tanh':
#             activation_function = lambda x: T.tanh(x)
#             W_values = np.asarray(rng.uniform(
#                 low=-np.sqrt(6. / (n_in + n_out)),
#                 high=np.sqrt(6. / (n_in + n_out)),
#                 size=(n_in, n_out)), dtype='float32')
#             b_values = np.zeros((n_out,), dtype='float32')
# 
#         elif activation == 'relu':
#             activation_function = lambda x: T.maximum(0.0, x)
#             W_values = np.asarray(rng.normal(0.0, weights_variance, size=(n_in, n_out)), dtype='float32')
#             b_values = np.ones((n_out,), dtype='float32') / 10.0
#         else:
#             raise ValueError('unknown activation function')
# 
#         self.W = theano.shared(value=W_values, name='W', borrow=True)
#         self.b = theano.shared(value=b_values, name='b', borrow=True)
# 
#         inv_dropout_prob = np.float32(1.0 - dropout_prob)
#         lin_output = ifelse(T.eq(training_mode, 1),
#                             T.dot(self._dropout(rng, input, dropout_prob), self.W) + self.b,
#                             T.dot(input, inv_dropout_prob * self.W) + self.b)
# 
#         self.output = activation_function(lin_output)
#         self.weights = [self.W, self.b]
# 
#     def _dropout(self, rng, layer, p):
#         srng = T.shared_randomstreams.RandomStreams(rng.randint(777777))
#         mask = srng.binomial(n=1, p=1 - p, size=layer.shape)
#         output = layer * T.cast(mask, 'float32')
#         return output
# 
# Path: layers/conv_layer.py
# class ConvPoolLayer(object):
#     def __init__(self, rng, input, filter_shape, image_shape, poolsize, activation, weights_variance, subsample):
# 
#         assert image_shape[1] == filter_shape[1]
#         self.input =input
# 
#         if activation == 'tanh':
#             activation_function = lambda x: T.tanh(x)
#             fan_in = np.prod(filter_shape[1:])
#             fan_out = (filter_shape[0] * np.prod(filter_shape[2:]) / np.prod(poolsize))
#             W_bound = np.sqrt(6. / (fan_in + fan_out))
#             W_values = np.asarray(rng.uniform(low=-W_bound, high=W_bound, size=filter_shape), dtype='float32')
#             b_values = np.zeros((filter_shape[0],), dtype='float32')
# 
#         elif activation == 'relu':
#             activation_function = lambda x: T.maximum(0.0, x)
#             W_values = np.asarray(rng.normal(0.0, weights_variance, size=filter_shape), dtype='float32')
#             b_values = np.ones((filter_shape[0],), dtype='float32') / 10.0
#         else:
#             raise ValueError('unknown activation function')
# 
#         self.W = theano.shared(value=W_values, name='W', borrow=True)
#         self.b = theano.shared(value=b_values, name='b', borrow=True)
# 
#         conv_out = conv.conv2d(input, self.W, filter_shape=filter_shape, image_shape=image_shape, subsample=subsample)
#         pooled_out = downsample.max_pool_2d(conv_out, poolsize, ignore_border=True) if poolsize[1] > 1 else conv_out
#         self.output = activation_function(pooled_out + self.b.dimshuffle('x', 0, 'x', 'x'))
#         self.weights = [self.W, self.b]


from layers.hidden_layer import HiddenLayer
from layers.conv_layer import ConvPoolLayer
from glob_pool_layer import GlobalPoolLayer


class FeatureExtractor(object):
    def __init__(self, rng, input, nkerns, recept_width, pool_width, stride, training_mode, dropout_prob, activation,
                 weights_variance, n_channels, n_timesteps, n_fbins, global_pooling):
        self.layer0 = ConvPoolLayer(rng, input=input,
                                    image_shape=(None, 1, n_channels * n_fbins, n_timesteps),
                                    filter_shape=(nkerns[0], 1, n_fbins * n_channels, recept_width[0]),
                                    poolsize=(1, pool_width[0]), activation=activation[0],
                                    weights_variance=weights_variance, subsample=(1, stride[0]))

        input_layer1_width = ((n_timesteps - recept_width[0]) / stride[0] + 1) / pool_width[0]
        self.layer1 = ConvPoolLayer(rng, input=self.layer0.output,
                                    image_shape=(None, nkerns[0], 1, input_layer1_width),
                                    filter_shape=(nkerns[1], nkerns[0], 1, recept_width[1]),
                                    poolsize=(1, pool_width[1]), activation=activation[1],
                                    weights_variance=weights_variance, subsample=(1, stride[1]))

        if global_pooling:
            self.glob_pool = GlobalPoolLayer(self.layer1.output)
            layer2_input = self.glob_pool.output.flatten(2)

            input_layer2_shape = nkerns[1] * 6

# Path: layers/hidden_layer.py
# class HiddenLayer(object):
#     def __init__(self, rng, input, n_in, n_out, training_mode, dropout_prob, activation, weights_variance):
#         self.input = input
#         if activation == 'tanh':
#             activation_function = lambda x: T.tanh(x)
#             W_values = np.asarray(rng.uniform(
#                 low=-np.sqrt(6. / (n_in + n_out)),
#                 high=np.sqrt(6. / (n_in + n_out)),
#                 size=(n_in, n_out)), dtype='float32')
#             b_values = np.zeros((n_out,), dtype='float32')
# 
#         elif activation == 'relu':
#             activation_function = lambda x: T.maximum(0.0, x)
#             W_values = np.asarray(rng.normal(0.0, weights_variance, size=(n_in, n_out)), dtype='float32')
#             b_values = np.ones((n_out,), dtype='float32') / 10.0
#         else:
#             raise ValueError('unknown activation function')
# 
#         self.W = theano.shared(value=W_values, name='W', borrow=True)
#         self.b = theano.shared(value=b_values, name='b', borrow=True)
# 
#         inv_dropout_prob = np.float32(1.0 - dropout_prob)
#         lin_output = ifelse(T.eq(training_mode, 1),
#                             T.dot(self._dropout(rng, input, dropout_prob), self.W) + self.b,
#                             T.dot(input, inv_dropout_prob * self.W) + self.b)
# 
#         self.output = activation_function(lin_output)
#         self.weights = [self.W, self.b]
# 
#     def _dropout(self, rng, layer, p):
#         srng = T.shared_randomstreams.RandomStreams(rng.randint(777777))
#         mask = srng.binomial(n=1, p=1 - p, size=layer.shape)
#         output = layer * T.cast(mask, 'float32')
#         return output
# 
# Path: layers/conv_layer.py
# class ConvPoolLayer(object):
#     def __init__(self, rng, input, filter_shape, image_shape, poolsize, activation, weights_variance, subsample):
# 
#         assert image_shape[1] == filter_shape[1]
#         self.input =input
# 
#         if activation == 'tanh':
#             activation_function = lambda x: T.tanh(x)
#             fan_in = np.prod(filter_shape[1:])
#             fan_out = (filter_shape[0] * np.prod(filter_shape[2:]) / np.prod(poolsize))
#             W_bound = np.sqrt(6. / (fan_in + fan_out))
#             W_values = np.asarray(rng.uniform(low=-W_bound, high=W_bound, size=filter_shape), dtype='float32')
#             b_values = np.zeros((filter_shape[0],), dtype='float32')
# 
#         elif activation == 'relu':
#             activation_function = lambda x: T.maximum(0.0, x)
#             W_values = np.asarray(rng.normal(0.0, weights_variance, size=filter_shape), dtype='float32')
#             b_values = np.ones((filter_shape[0],), dtype='float32') / 10.0
#         else:
#             raise ValueError('unknown activation function')
# 
#         self.W = theano.shared(value=W_values, name='W', borrow=True)
#         self.b = theano.shared(value=b_values, name='b', borrow=True)
# 
#         conv_out = conv.conv2d(input, self.W, filter_shape=filter_shape, image_shape=image_shape, subsample=subsample)
#         pooled_out = downsample.max_pool_2d(conv_out, poolsize, ignore_border=True) if poolsize[1] > 1 else conv_out
#         self.output = activation_function(pooled_out + self.b.dimshuffle('x', 0, 'x', 'x'))
#         self.weights = [self.W, self.b]


# Path: layers/feature_extractor.py
from layers.hidden_layer import HiddenLayer
from layers.conv_layer import ConvPoolLayer
from glob_pool_layer import GlobalPoolLayer



class FeatureExtractor(object):
    def __init__(self, rng, input, nkerns, recept_width, pool_width, stride, training_mode, dropout_prob, activation,
                 weights_variance, n_channels, n_timesteps, n_fbins, global_pooling):
        self.layer0 = ConvPoolLayer(rng, input=input,
                                    image_shape=(None, 1, n_channels * n_fbins, n_timesteps),
                                    filter_shape=(nkerns[0], 1, n_fbins * n_channels, recept_width[0]),
                                    poolsize=(1, pool_width[0]), activation=activation[0],
                                    weights_variance=weights_variance, subsample=(1, stride[0]))

        input_layer1_width = ((n_timesteps - recept_width[0]) / stride[0] + 1) / pool_width[0]
        self.layer1 = ConvPoolLayer(rng, input=self.layer0.output,
                                    image_shape=(None, nkerns[0], 1, input_layer1_width),
                                    filter_shape=(nkerns[1], nkerns[0], 1, recept_width[1]),
                                    poolsize=(1, pool_width[1]), activation=activation[1],
                                    weights_variance=weights_variance, subsample=(1, stride[1]))

        if global_pooling:
            self.glob_pool = GlobalPoolLayer(self.layer1.output)
            layer2_input = self.glob_pool.output.flatten(2)

            input_layer2_shape = nkerns[1] * 6

            self.layer2 = HiddenLayer(rng=rng, input=layer2_input,