keras-team / keras

Deep Learning for humans
http://keras.io/
Apache License 2.0
62.05k stars 19.48k forks source link

Why the outcome of max-pooling function is the same as ave-pooling? #1534

Closed dalstonChen closed 7 years ago

dalstonChen commented 8 years ago

Hi,

I am confused by the MaxPooling1D() function, why the output of it is the same as ave-pooling? I pass the parameter just as the document says.

graph.add_node(MaxPooling1D(2), name = 'pooling', input = 'conv')

I have tried to read the source code of keras, but it's an implementation using TensorFlow which I am not quiet familiar with.

plus, this code will get error if I use keras 0.3.1, while 0.3.0 seems to be OK.

Could anyone who is familiar with max-pooling can help me ?

Here's my code: (sorry for the messy)

from keras.preprocessing import sequence
from keras.utils import np_utils
from keras.models import Sequential, Graph
from keras.layers.core import Dense, Dropout, Activation, Reshape, TimeDistributedDense, Merge, Lambda
from keras.layers.embeddings import Embedding
from embeddings3D import Embedding3D
from keras.layers.recurrent import LSTM, SimpleRNN
from keras.layers.convolutional import Convolution2D, Convolution1D, UpSampling1D, MaxPooling1D
from numpy import random
import numpy as np
import theano
from keras import backend as K
from theano.tensor.signal import downsample
np.random.seed(4321)  # for reproducibility

def fun(X):
    X = K.expand_dims(X, -1)
    X = K.permute_dimensions(X, (0, 2, 1, 3))
def pool(X):
    X = K.expand_dims(X, -1)
    maxpool_shape = (2,1)
    return theano.tensor.signal.downsample.max_pool_2d(X,maxpool_shape, ignore_border=True)

graph = Graph()
graph.add_input('input', input_shape = (10,8))
#graph.add_node(Lambda(fun),name = 'reform', input = 'input')
graph.add_node(Convolution1D(nb_filter=4,filter_length=3,border_mode='same'), name = 'conv', input = 'input')
graph.add_output(name='conv_out',input = 'conv')
graph.add_node(MaxPooling1D(2), name = 'pooling', input = 'conv')
#graph.add_node(Convolution2D(nb_filter=1,nb_row=3,nb_col=1), name = 'conv', input = 'reform')
graph.add_output(name = 'pooling_out', input = 'pooling')
graph.add_node(UpSampling1D(2), name = 'upsampling', input = 'pooling')
graph.add_output(name = 'upsampling_out', input = 'upsampling')
graph.compile('adam', {'conv_out': 'binary_crossentropy','pooling_out': 'binary_crossentropy', 'upsampling_out': 'binary_crossentropy'})

X = random.randint(0,2,size = (1,10,8))
out = graph.predict({'input': X})
print out['conv_out']
print out['pooling_out']
print out['upsampling_out']

'''
print (X)
X = np.expand_dims(X, -1)
print (X.shape)
print (X)
X = np.transpose(X, (0, 2, 1, 3))
print (X.shape)
print (X)

print (graph.predict({'input': X})['output'].shape)
print (X)
print (graph.predict({'input': X})['output'])
print (graph.nodes['conv'].params[0].get_value(),graph.nodes['conv'].params[1].get_value())
'''

#>>> graph.outputs['output'].input.get_value()
#>>> graph.nodes['conv'].params[0].get_value()

and it's the result(according to the code above):

result

it shows that the pooling_out tensor is the same as the output of average-pooling.

Thanks!

ymcui commented 8 years ago

Hi, I didn't see any code related to AveragePooling. Perhaps you mistook UpSampling with AveragePooling? The UpSampling1D is just repeating each timestep length times along the time axis.(see Keras documentation) So what you see in print out['upsampling_out'] is just a doubled tensor in each timestep of print out['pooling_out']

BTW: There two backends for Keras, so you can check backend/theano_backend.py for further code support. The AveragePooling1D is defined in layers/convolutional.py, and it will call pool2d() in backend/theano_backend.py

dalstonChen commented 8 years ago

Hi, I checked the source code of keras in my system (version==0.3.0), and found it goes wrong. I am not sure if someone rewrite the code or the code had bugs. When I update the keras to the lasted version, the result comes to be right. Thank you very much!

class UpSampling1D(Layer):
    input_ndim = 3

    def __init__(self, length=2, **kwargs):
        super(UpSampling1D, self).__init__(**kwargs)
        self.length = length
        self.input = K.placeholder(ndim=3)

    @property
    def output_shape(self):
        input_shape = self.input_shape
        return (input_shape[0], self.length * input_shape[1], input_shape[2])

    def get_output(self, train=False):
        X = self.get_input(train)
        output = K.concatenate([X] * self.length, axis=1)
        return output

    def get_config(self):
        config = {"name": self.__class__.__name__,
                  "length": self.length}
        base_config = super(UpSampling1D, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

Above is the code of Upsampling function from the version 0.3.0, which might be wrong.

stale[bot] commented 7 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 30 days if no further activity occurs, but feel free to re-open a closed issue if needed.