0

When I try to train the autoencoder described below, I receive an error that ' A target array with shape (256, 28, 28, 1) was passed for an output of shape (None, 0, 28, 1) while using as loss `binary_crossentropy. This loss expects targets to have the same shape as the output.' The input and output dimensions should both be (28,28,1) with 256 being the batch size. Running .summary() confirms the output of the decoder model is the correct (28,28,1) but this seemingly changes when the encoder and decoder are compiled together. Any idea what's happening here? The three functions are called in succession when the network is generated.

def buildEncoder():
    input1 = Input(shape=(28,28,1))
    input2 = Input(shape=(28,28,1))
    merge = concatenate([input1,input2])
    convEncode1 = Conv2D(16, (3,3), activation = 'relu', padding = 'same')(merge)
    maxPoolEncode1 = MaxPooling2D(pool_size=(2, 1))(convEncode1)
    convEncode2 = Conv2D(16, (3,3), activation = 'sigmoid', padding = 'same')(maxPoolEncode1)
    convEncode3 = Conv2D(1, (3,3), activation = 'sigmoid', padding = 'same')(convEncode2)
    model = Model(inputs = [input1,input2], outputs = convEncode3)
    model.compile(loss='binary_crossentropy', optimizer=adam)
    return model

def buildDecoder():
    input1 = Input(shape=(28,28,1))
    upsample1 = UpSampling2D((2,1))(input1)
    convDecode1 = Conv2D(16, (3,3), activation = 'relu', padding = 'same')(upsample1)
    crop1 = Cropping2D(cropping = ((0,28),(0,0)))(convDecode1)
    crop2 = Cropping2D(cropping = ((28,0),(0,0)))(convDecode1)
    convDecode2_1 = Conv2D(16, (3,3), activation = 'relu', padding = 'same')(crop1)
    convDecode3_1 = Conv2D(16, (3,3), activation = 'relu', padding = 'same')(crop2)
    convDecode2_2 = Conv2D(1, (3,3), activation = 'sigmoid', padding = 'same')(convDecode2_1)
    convDecode3_2 = Conv2D(1, (3,3), activation = 'sigmoid', padding = 'same')(convDecode3_1)
    model = Model(inputs=input1, outputs=[convDecode2_2,convDecode3_2])
    model.compile(loss='binary_crossentropy', optimizer=adam)
    return model

def buildAutoencoder():   
    autoInput1 = Input(shape=(28,28,1))
    autoInput2 = Input(shape=(28,28,1))
    encode = encoder([autoInput1,autoInput2])
    decode = decoder(encode)
    model = Model(inputs=[autoInput1,autoInput2], outputs=[decode[0],decode[1]])
    model.compile(loss='binary_crossentropy', optimizer=adam)
    return model

Running the model.summary() function confirms that the final output dimensions of this

Harrison Rose
  • 57
  • 1
  • 3
  • I don't think you should compile intermediate models, just the final one for training. Can you try removing compilation of encoder and decoder models? – nuric May 12 '18 at 12:28
  • I tried commenting out the two lines but I receive the same errors. I think the compile is needed so that I can run the intermediates on their own for encoding and decoding operations. – Harrison Rose May 12 '18 at 12:31
  • You don't need to compile intermediate models unless you want to train them separately. – nuric May 12 '18 at 12:37

1 Answers1

1

It looks like you have shape mis-calculation in your encoder. You assume the decoder will get (None, 28, 28, 1) but your encoder actually outputs (None, 14, 28, 28, 1).

print(encoder) # Tensor("model_1/conv2d_3/Sigmoid:0", shape=(?, 14, 28, 1), dtype=float32)

Now in your decoder you are cropping etc assuming you have (28, 28, 1) which presumably chops it to 0. The models work on their own, the mis-match happens when you connect them.

nuric
  • 11,027
  • 3
  • 27
  • 42
  • Thanks a lot dude. Turns out the concatenate layer was joining the two inputs at the last axis by default, rather than the first. As you pointed out this meant when I split across that first axis I ended up with the wrong shape. – Harrison Rose May 12 '18 at 13:08