Answers.Body: <p>For me, this worked perfectly. I encoded with conv2d and dense and then I flatten I and reshape in the decoder after the dense layer so the encoder and decoder are symmetrical. The only difference is that in my case I use images (224,224,1)</p>
  <pre><code># create encoder
  # 28,28 -&gt; 1st conv2d (filter 3x3,relu activation, padding, strides == 'jumps')
  self.encoder = tf.keras.Sequential([layers.Input(shape=(224,224,1)),
                                      layers.Conv2D(16,kernel_size=3,activation='relu',padding='same',strides=2),                
                                      layers.Conv2D(8,kernel_size=3,activation='relu',padding='same',strides=2),
                                      layers.Conv2D(4,kernel_size=3,activation='relu',padding='same',strides=2),
                                      layers.Flatten(),
                                      layers.Dense(units=3136,activation='sigmoid')]) # (28,28,4)
  
  # deconvolution -&gt; decoding 
  self.decoder = tf.keras.Sequential([layers.Input(shape=(3136)),
                                      layers.Dense(units=3136,activation='sigmoid'),
                                      layers.Reshape((28,28,4)),
                                      layers.Conv2DTranspose(4,kernel_size=3,activation='relu',padding='same',strides=2),
                                      layers.Conv2DTranspose(8,kernel_size=3,strides=2,activation='relu',padding='same'),
                                      layers.Conv2DTranspose(16,kernel_size=3,strides=2,activation='relu',padding='same'),
                                      layers.Conv2D(1,kernel_size=(3,3),activation='sigmoid',padding='same')])
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-11-07T05:53:43.690Z
Answers.LastActivityDate: 2021-12-02T10:31:33.790Z
Answers.LastEditDate: 2021-12-02T10:31:33.790Z
Answers.UserDisplayName: Maciek Woźniak
Body: <p>I am trying to implement a convolutional autoencoder with a dense layer at the bottleneck to do some dimensional reduction. I have seen two approaches for this, which aren't particularly scalable. The first was to introduce 2 dense layers (one at the bottleneck and one before &amp; after that has the same number of nodes as the conv2d layer that precedes the dense layer in the encoder section:</p>
  <pre><code>input_image_shape=(200,200,3)
  encoding_dims = 20
  
  encoder = Sequential()
  encoder.add(InputLayer(input_image_shape))
  encoder.add(Conv2D(32, (3,3), activation=&quot;relu, padding=&quot;same&quot;))
  encoder.add(MaxPooling2D((2), padding=&quot;same&quot;))
  encoder.add(Flatten())
  encoder.add(Dense(32*100*100, activation=&quot;relu&quot;))
  encoder.add(Dense(encoding_dims, activation=&quot;relu&quot;))
  
  #The decoder
  decoder = Sequential()
  decoder.add(InputLayer((encoding_dims,)))
  decoder.add(Dense(32*100*100, activation=&quot;relu&quot;))
  decoder.add(Reshape((100, 100, 32)))
  decoder.add(UpSampling2D(2))
  decoder.add(Conv2D(3, (3,3), activation=&quot;sigmoid&quot;, padding=&quot;same&quot;))
  </code></pre>
  <p>It's easy to see why this approach blows up as there are two densely connected layers with (32<em>100</em>100) nodes each or more or in that ballpark which is nuts.</p>
  <p>Another approach I have found which makes sense for b/w images such as the MNIST stuff is to introduce an arbitrary number of encoding dimensions and reshape it (<a href="https://medium.com/analytics-vidhya/building-a-convolutional-autoencoder-using-keras-using-conv2dtranspose-ca403c8d144e" rel="nofollow noreferrer">https://medium.com/analytics-vidhya/building-a-convolutional-autoencoder-using-keras-using-conv2dtranspose-ca403c8d144e</a>). The following chunk of code is copied from the link, I claim no credit for it:</p>
  <pre><code>#ENCODER
  inp = Input((28, 28,1))
  e = Conv2D(32, (3, 3), activation='relu')(inp)
  e = MaxPooling2D((2, 2))(e)
  e = Conv2D(64, (3, 3), activation='relu')(e)
  e = MaxPooling2D((2, 2))(e)
  e = Conv2D(64, (3, 3), activation='relu')(e)
  l = Flatten()(e)
  l = Dense(49, activation='softmax')(l)
  #DECODER
  d = Reshape((7,7,1))(l)
  d = Conv2DTranspose(64,(3, 3), strides=2, activation='relu', padding='same')(d)
  d = BatchNormalization()(d)
  d = Conv2DTranspose(64,(3, 3), strides=2, activation='relu', padding='same')(d)
  d = BatchNormalization()(d)
  d = Conv2DTranspose(32,(3, 3), activation='relu', padding='same')(d)
  decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(d)
  </code></pre>
  <p>So, is there a more rigorous way of adding a dense layer after a 2d convolutional layer?</p>
  
Tags: <convolutional-neural-networks><keras><autoencoders><convolutional-layers><dense-layers>
Title: How to add a dense layer after a 2d convolutional layer in a convolutional autoencoder?
UserDisplayName: Pavan Inguva
ThreadText: # How to add a dense layer after a 2d convolutional layer in a convolutional autoencoder?
  
  (Asked by: username_0 on 2020-03-31)
  
  I am trying to implement a convolutional autoencoder with a dense layer at the bottleneck to do some dimensional reduction. I have seen two approaches for this, which aren't particularly scalable. The first was to introduce 2 dense layers (one at the bottleneck and one before & after that has the same number of nodes as the conv2d layer that precedes the dense layer in the encoder section:
  
  ```
  input_image_shape=(200,200,3)
  encoding_dims = 20
  
  encoder = Sequential()
  encoder.add(InputLayer(input_image_shape))
  encoder.add(Conv2D(32, (3,3), activation="relu, padding="same"))
  encoder.add(MaxPooling2D((2), padding="same"))
  encoder.add(Flatten())
  encoder.add(Dense(32*100*100, activation="relu"))
  encoder.add(Dense(encoding_dims, activation="relu"))
  
  #The decoder
  decoder = Sequential()
  decoder.add(InputLayer((encoding_dims,)))
  decoder.add(Dense(32*100*100, activation="relu"))
  decoder.add(Reshape((100, 100, 32)))
  decoder.add(UpSampling2D(2))
  decoder.add(Conv2D(3, (3,3), activation="sigmoid", padding="same"))
  
  ```
  
  It's easy to see why this approach blows up as there are two densely connected layers with (32*100*100) nodes each or more or in that ballpark which is nuts.
  
  Another approach I have found which makes sense for b/w images such as the MNIST stuff is to introduce an arbitrary number of encoding dimensions and reshape it (<https://medium.com/analytics-vidhya/building-a-convolutional-autoencoder-using-keras-using-conv2dtranspose-ca403c8d144e>). The following chunk of code is copied from the link, I claim no credit for it:
  
  ```
  #ENCODER
  inp = Input((28, 28,1))
  e = Conv2D(32, (3, 3), activation='relu')(inp)
  e = MaxPooling2D((2, 2))(e)
  e = Conv2D(64, (3, 3), activation='relu')(e)
  e = MaxPooling2D((2, 2))(e)
  e = Conv2D(64, (3, 3), activation='relu')(e)
  l = Flatten()(e)
  l = Dense(49, activation='softmax')(l)
  #DECODER
  d = Reshape((7,7,1))(l)
  d = Conv2DTranspose(64,(3, 3), strides=2, activation='relu', padding='same')(d)
  d = BatchNormalization()(d)
  d = Conv2DTranspose(64,(3, 3), strides=2, activation='relu', padding='same')(d)
  d = BatchNormalization()(d)
  d = Conv2DTranspose(32,(3, 3), activation='relu', padding='same')(d)
  decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(d)
  
  ```
  
  So, is there a more rigorous way of adding a dense layer after a 2d convolutional layer?
  
  **Tags:** convolutional-neural-networks, keras, autoencoders, convolutional-layers, dense-layers
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-11-07. Score: 1
  
  For me, this worked perfectly. I encoded with conv2d and dense and then I flatten I and reshape in the decoder after the dense layer so the encoder and decoder are symmetrical. The only difference is that in my case I use images (224,224,1)
  
  ```
  # create encoder
  # 28,28 -> 1st conv2d (filter 3x3,relu activation, padding, strides == 'jumps')
  self.encoder = tf.keras.Sequential([layers.Input(shape=(224,224,1)),
                                      layers.Conv2D(16,kernel_size=3,activation='relu',padding='same',strides=2),                
                                      layers.Conv2D(8,kernel_size=3,activation='relu',padding='same',strides=2),
                                      layers.Conv2D(4,kernel_size=3,activation='relu',padding='same',strides=2),
                                      layers.Flatten(),
                                      layers.Dense(units=3136,activation='sigmoid')]) # (28,28,4)
  
  # deconvolution -> decoding 
  self.decoder = tf.keras.Sequential([layers.Input(shape=(3136)),
                                      layers.Dense(units=3136,activation='sigmoid'),
                                      layers.Reshape((28,28,4)),
                                      layers.Conv2DTranspose(4,kernel_size=3,activation='relu',padding='same',strides=2),
                                      layers.Conv2DTranspose(8,kernel_size=3,strides=2,activation='relu',padding='same'),
                                      layers.Conv2DTranspose(16,kernel_size=3,strides=2,activation='relu',padding='same'),
                                      layers.Conv2D(1,kernel_size=(3,3),activation='sigmoid',padding='same')])
  
  ```
  
  
  ---
  
  