Domanda

Sto cercando di implementare autoencoders convoluzionali in tensorflow, sul set di dati mnist.

Il problema è che l'autoencoder non sembra imparare correttamente: sarà sempre imparare a riprodurre la forma 0, ma non altre forme, in realtà io di solito ottenere una perdita media di circa 0,09, che è 1/10 del le classi che si deve imparare.

Sto usando 2x2 kernel con passo 2 per le circonvoluzioni di ingresso e uscita, ma i filtri sembra essere appreso in modo corretto. Quando visualizzo i dati immagine di ingresso viene fatto passare attraverso 16 (1 ° conv) e 32 filtri (2 CONV), e mediante ispezione immagine sembra funzionare benissimo (cioè caratteristiche apparentemente come curve, incroci, ecc sono rilevate).

Il problema sembra verificarsi nella parte completamente connessa della rete:. Non importa quale sia l'immagine in ingresso, la sua codifica sarà sempre stesso

Il mio primo pensiero è "Sto probabilmente solo alimentandola con zeri, mentre la formazione", ma non credo che ho fatto questo errore (vedi codice qui sotto).

Modifica Ho realizzato il set di dati non è stato mischiato, che ha introdotto un bias e potrebbe essere la causa del problema. Dopo l'introduzione di esso, la perdita media è più bassa (0,06 invece di 0,09), e in effetti l'aspetto di immagine in uscita come una sfocata 8, ma conclusioni sono le stesse:. L'ingresso codificato sarà lo stesso non importa quale sia l'immagine in ingresso

Qui un input di esempio con l'uscita relativa

 Un ingresso campione con l'uscita relativa

Ecco l'attivazione per l'immagine sopra, con i due strati completamente collegati in basso (codifica è in basso).

 attivazioni

Infine, qui ci sono l'attivazione degli strati completamente connessi per ingressi diversi. Ogni immagine corrisponde input ad una linea nelle immagini di attivazione.

Come si può vedere, hanno sempre producono lo stesso risultato. Se uso pesi trasposti invece di inizializzazione differenti, il primo strato FC (immagine al centro) sembra un po 'più randomizzato, ma il modello di fondo è ancora evidente. Nello strato di codifica (immagine in basso), l'uscita sarà sempre la stessa, non importa quale è l'ingresso (naturalmente, il modello varia da una formazione e la successiva).

 attivazione strati FC

Ecco il codice relativo

# A placeholder for the input data
x = tf.placeholder('float', shape=(None, mnist.data.shape[1]))

# conv2d_transpose cannot use -1 in output size so we read the value
# directly in the graph
batch_size = tf.shape(x)[0]

# Variables for weights and biases
with tf.variable_scope('encoding'):
    # After converting the input to a square image, we apply the first convolution, using 2x2 kernels
    with tf.variable_scope('conv1'):
        wec1 = tf.get_variable('w', shape=(2, 2, 1, m_c1), initializer=tf.truncated_normal_initializer())
        bec1 = tf.get_variable('b', shape=(m_c1,), initializer=tf.constant_initializer(0))
    # Second convolution
    with tf.variable_scope('conv2'):
        wec2 = tf.get_variable('w', shape=(2, 2, m_c1, m_c2), initializer=tf.truncated_normal_initializer())
        bec2 = tf.get_variable('b', shape=(m_c2,), initializer=tf.constant_initializer(0))
    # First fully connected layer
    with tf.variable_scope('fc1'):
        wef1 = tf.get_variable('w', shape=(7*7*m_c2, n_h1), initializer=tf.contrib.layers.xavier_initializer())
        bef1 = tf.get_variable('b', shape=(n_h1,), initializer=tf.constant_initializer(0))
    # Second fully connected layer
    with tf.variable_scope('fc2'):
        wef2 = tf.get_variable('w', shape=(n_h1, n_h2), initializer=tf.contrib.layers.xavier_initializer())
        bef2 = tf.get_variable('b', shape=(n_h2,), initializer=tf.constant_initializer(0))

reshaped_x = tf.reshape(x, (-1, 28, 28, 1))
y1 = tf.nn.conv2d(reshaped_x, wec1, strides=(1, 2, 2, 1), padding='VALID')
y2 = tf.nn.sigmoid(y1 + bec1)
y3 = tf.nn.conv2d(y2, wec2, strides=(1, 2, 2, 1), padding='VALID')
y4 = tf.nn.sigmoid(y3 + bec2)
y5 = tf.reshape(y4, (-1, 7*7*m_c2))
y6 = tf.nn.sigmoid(tf.matmul(y5, wef1) + bef1)
encode = tf.nn.sigmoid(tf.matmul(y6, wef2) + bef2)

with tf.variable_scope('decoding'):
    # for the transposed convolutions, we use the same weights defined above
    with tf.variable_scope('fc1'):
        #wdf1 = tf.transpose(wef2)
        wdf1 = tf.get_variable('w', shape=(n_h2, n_h1), initializer=tf.contrib.layers.xavier_initializer())
        bdf1 = tf.get_variable('b', shape=(n_h1,), initializer=tf.constant_initializer(0))
    with tf.variable_scope('fc2'):
        #wdf2 = tf.transpose(wef1)
        wdf2 = tf.get_variable('w', shape=(n_h1, 7*7*m_c2), initializer=tf.contrib.layers.xavier_initializer())
        bdf2 = tf.get_variable('b', shape=(7*7*m_c2,), initializer=tf.constant_initializer(0))
    with tf.variable_scope('deconv1'):
        wdd1 = tf.get_variable('w', shape=(2, 2, m_c1, m_c2), initializer=tf.contrib.layers.xavier_initializer())
        bdd1 = tf.get_variable('b', shape=(m_c1,), initializer=tf.constant_initializer(0))
    with tf.variable_scope('deconv2'):
        wdd2 = tf.get_variable('w', shape=(2, 2, 1, m_c1), initializer=tf.contrib.layers.xavier_initializer())
        bdd2 = tf.get_variable('b', shape=(1,), initializer=tf.constant_initializer(0))

u1 = tf.nn.sigmoid(tf.matmul(encode, wdf1) + bdf1)
u2 = tf.nn.sigmoid(tf.matmul(u1, wdf2) + bdf2)
u3 = tf.reshape(u2, (-1, 7, 7, m_c2))
u4 = tf.nn.conv2d_transpose(u3, wdd1, output_shape=(batch_size, 14, 14, m_c1), strides=(1, 2, 2, 1), padding='VALID')
u5 = tf.nn.sigmoid(u4 + bdd1)
u6 = tf.nn.conv2d_transpose(u5, wdd2, output_shape=(batch_size, 28, 28, 1), strides=(1, 2, 2, 1), padding='VALID')
u7 = tf.nn.sigmoid(u6 + bdd2)
decode = tf.reshape(u7, (-1, 784))

loss = tf.reduce_mean(tf.square(x - decode))
opt = tf.train.AdamOptimizer(0.0001).minimize(loss)

try:
    tf.global_variables_initializer().run()
except AttributeError:
    tf.initialize_all_variables().run() # Deprecated after r0.11

print('Starting training...')
bs = 1000 # Batch size
for i in range(501): # Reasonable results around this epoch 
    # Apply permutation of data at each epoch, should improve convergence time
    train_data = np.random.permutation(mnist.data)
    if i % 100 == 0:
        print('Iteration:', i, 'Loss:', loss.eval(feed_dict={x: train_data}))
    for j in range(0, train_data.shape[0], bs):
        batch = train_data[j*bs:(j+1)*bs]
        sess.run(opt, feed_dict={x: batch})
        # TODO introduce noise
print('Training done')
È stato utile?

Soluzione

Bene, il problema era principalmente correlata alla dimensione del kernel. Uso 2x2 convoluzione con passo di (2,2) si è rivelato essere una cattiva idea. Utilizzando 5x5 e 3x3 dimensioni dato risultati decenti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
scroll top