def front(self):
		# Front-End

		# x : [ Btot , 1, L , 1]
		# Equivalent to B_tot batches of image of height = 1, width = L and 1 channel -> for Conv1D with Conv2D
		input_front =  tf.reshape(self.x, [self.B_tot, 1, self.L, 1])

		# Filter [filter_height, filter_width, input_channels, output_channels] = [1, W, 1, N]
		# self.window_filter = get_scope_variable('window', 'w', shape=[self.window], initializer=tf.contrib.layers.xavier_initializer_conv2d())
		# self.bases = get_scope_variable('bases', 'bases', shape=[self.window, self.N], initializer=tf.contrib.layers.xavier_initializer_conv2d())
		# self.conv_filter = tf.reshape(tf.expand_dims(self.window_filter,1)*self.bases , [1, self.window, 1, self.N])
		self.conv_filter = get_scope_variable('filters_front','filters_front', shape=[1, self.window, 1, self.N], initializer=tf.contrib.layers.xavier_initializer_conv2d())

		# 1 Dimensional convolution along T axis with a window length = self.window
		# And N = 256 filters -> Create a [Btot, 1, T, N]
		self.X = tf.nn.conv2d(input_front, self.conv_filter, strides=[1, 1, 1, 1], padding="SAME", name='Conv_STFT')
		
		# Reshape to Btot batches of T x N images with 1 channel
		self.X = tf.reshape(self.X, [self.B_tot, -1, self.N, 1])

		self.T = tf.shape(self.X)[1]

		# Max Pooling with argmax for unpooling later in the back-end layer
		# Along the T axis (time)
		self.y, argmax = tf.nn.max_pool_with_argmax(self.X, (1, self.max_pool_value, 1, 1),
													strides=[1, self.max_pool_value, 1, 1], padding="SAME", name='output')

		y_shape = tf.shape(self.y)
		y = tf.reshape(self.y, [self.B_tot, y_shape[1]*y_shape[2]])
		self.p_hat = tf.reduce_mean(tf.abs(y), 0)
		self.sparse_constraint = tf.reduce_sum(kl_div(self.p, self.p_hat))

		return self.y, argmax
    def front(self):
        # Front-End

        # x : [ Btot , 1, L , 1]
        # Equivalent to B_tot batches of image of height = 1, width = L and 1 channel -> for Conv1D with Conv2D
        input_front = tf.reshape(self.x, [self.B_tot, 1, self.L, 1])

        # Filter [filter_height, filter_width, input_channels, output_channels] = [1, W, 1, N]
        self.window_filter = get_scope_variable(
            'window',
            'w',
            shape=[self.window],
            initializer=tf.contrib.layers.xavier_initializer_conv2d())
        self.bases = get_scope_variable(
            'bases',
            'bases',
            shape=[self.window, self.N],
            initializer=tf.contrib.layers.xavier_initializer_conv2d())
        self.conv_filter = tf.reshape(
            tf.abs(tf.expand_dims(self.window_filter, 1)) * self.bases,
            [1, self.window, 1, self.N])
        # self.conv_filter = get_scope_variable('filters_front','filters_front', shape=[1, self.window, 1, self.N])
        variable_summaries(self.conv_filter)

        # 1 Dimensional convolution along T axis with a window length = self.window
        # And N = 256 filters -> Create a [Btot, 1, T, N]
        self.T = tf.shape(input_front)[2]

        if self.with_max_pool:
            self.X = tf.nn.conv2d(input_front,
                                  self.conv_filter,
                                  strides=[1, 1, 1, 1],
                                  padding="SAME",
                                  name='Conv_STFT')
            self.y, self.argmax = tf.nn.max_pool_with_argmax(
                self.X, [1, 1, self.max_pool_value, 1],
                strides=[1, 1, self.max_pool_value, 1],
                padding="SAME",
                name='output')
            print self.argmax
        elif self.with_average_pool:
            self.X = tf.nn.conv2d(input_front,
                                  self.conv_filter,
                                  strides=[1, 1, 1, 1],
                                  padding="SAME",
                                  name='Conv_STFT')
            # self.y = tf.nn.avg_pool(self.X, [1, 1, self.max_pool_value, 1], [1, 1, self.max_pool_value, 1], padding="SAME")
            self.y = tf.layers.average_pooling2d(self.X,
                                                 (1, self.max_pool_value),
                                                 strides=(1,
                                                          self.max_pool_value),
                                                 name='output')
        else:
            self.y = tf.nn.conv2d(input_front,
                                  self.conv_filter,
                                  strides=[1, 1, self.max_pool_value, 1],
                                  padding="SAME",
                                  name='Conv_STFT')

        # Reshape to Btot batches of T x N images with 1 channel
        # [Btot, 1, T_pool, N] -> [Btot, T-pool, N, 1]
        self.y = tf.transpose(self.y, [0, 2, 3, 1], name='output')

        tf.summary.image('front/output', self.y, max_outputs=3)
        y_shape = tf.shape(self.y)
        y = tf.reshape(self.y, [self.B_tot, y_shape[1] * y_shape[2]])
        self.p_hat = tf.reduce_sum(tf.abs(y), 0)
        self.sparse_constraint = tf.reduce_sum(kl_div(self.p, self.p_hat))

        return self.y
    def back(self):

        input_tensor = self.separator

        if self.with_max_pool:

            argmax_mix = self.argmax[:self.B]

            repeats = [self.S, 1, 1, 1]
            shape = tf.shape(argmax_mix)
            argmax_mix = tf.expand_dims(argmax_mix, 1)
            argmax_mix = tf.tile(argmax_mix, [1, self.S, 1, 1, 1])
            argmax_mix = tf.reshape(argmax_mix, shape * repeats)

            output_shape = [self.B * self.S, 1, self.T, self.N]

            output = unpool(input_tensor,
                            argmax_mix,
                            ksize=[1, 1, self.max_pool_value, 1],
                            output_shape=output_shape,
                            scope='unpool')
            output = tf.reshape(output, [self.B * self.S, 1, self.T, self.N])

        elif self.with_average_pool:
            input_tensor = tf.reshape(
                input_tensor, [self.B * self.S, 1, self.T_max_pooled, self.N])
            output = tf.keras.layers.UpSampling2D(
                (1, self.max_pool_value))(input_tensor)
            output = tf.reshape(output, [self.B * self.S, 1, self.T, self.N])
        else:
            output = tf.reshape(
                input_tensor, [self.B * self.S, 1, self.T_max_pooled, self.N])

        self.window_filter_2 = get_scope_variable(
            'window',
            'value',
            shape=[self.window],
            initializer=tf.contrib.layers.xavier_initializer_conv2d())
        self.bases_2 = get_scope_variable(
            'bases',
            'value',
            shape=[self.window, self.N],
            initializer=tf.contrib.layers.xavier_initializer_conv2d())
        self.conv_filter_2 = tf.reshape(
            tf.abs(tf.expand_dims(self.window_filter_2, 1)) * self.bases_2,
            [1, self.window, 1, self.N],
            name='filters'
        )  # self.conv_filter_2 = tf.Variable(self.conv_filter.initialized_value(), name="filters_back")

        if not (self.with_max_pool or self.with_average_pool):
            strides = [1, 1, self.max_pool_value, 1]
        else:
            strides = [1, 1, 1, 1]

        output = tf.nn.conv2d_transpose(
            output,
            filter=self.conv_filter_2,
            output_shape=[self.B * self.S, 1, self.L, 1],
            strides=strides,
            padding='SAME')

        output = tf.reshape(output, [self.B, self.S, self.L],
                            name='back_output')
        self.output = output

        return output