Вопрос

Я пытаюсь внедрить сверточные автоэкодоры в Tensorflow, в наборе данных MNIST.

Проблема заключается в том, что автоэкодер, похоже, не учится должным образом: он всегда научится воспроизводить форму 0, но никаких других форм, на самом деле я обычно получаю среднюю потерю около 0,09, что составляет 1/10 от классов, которые он должен учиться.

Я использую ядра 2x2 с шагом 2 для входных и выходных свертков, но фильтры, кажется, изучаются должным образом. Когда я визуализирую данные, входное изображение проходит через 16 (1 -й конвей) и 32 фильтров (2 -й конв), а под проверкой изображения оно кажется нормальным (то есть, по -видимому, функции, такие как кривые, скрещивания и т. Д.).

Проблема, по -видимому, возникает в полностью подключенной части сети: независимо от того, что такое входное изображение, его кодирование будет всегда одинаковый.

Моя первая мысль: «Я, вероятно, просто кормлю его нулями во время обучения», но я не думаю, что сделал эту ошибку (см. Код ниже).

Редактировать Я понял, что набор данных не был переброшен, что ввело предвзятость и может быть причиной проблемы. После его представления средняя потеря ниже (0,06 вместо 0,09), и на самом деле выходной изображение выглядит как размытие 8, но выводы одинаковы: кодированный вход будет одинаковым, независимо от того, что такое входное изображение.

Здесь образец ввода с относительным выходом

A sample input with the relative output

Вот активация для изображения выше, с двумя полностью подключенными слоями внизу (кодирование является Bottomomost).

activations

Наконец, здесь есть активация для полностью подключенных слоев для разных входов. Каждое входное изображение соответствует линии на изображениях активации.

Как вы можете видеть, они всегда дают одну и ту же выход. Если я использую транспонированные веса вместо инициализации разных, первый слой FC (изображение в середине) выглядит более рандомизированным, но базовая картина все еще очевидна. В слое кодирования (изображение внизу) выход всегда будет одинаковым, независимо от того, что такое вход (конечно, шаблон варьируется от одного обучения и следующего).

FC layers activation

Вот соответствующий код

# 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')
Это было полезно?

Решение

Ну, проблема была в основном связана с размером ядра. Использование свертки 2x2 с шагом (2,2) стало плохой идеей. Использование размеров 5x5 и 3x3 дало приличные результаты.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с datascience.stackexchange
scroll top