Я пытаюсь создать свою первую нейронную сеть Autoencoder, используя TensorFlow. Размеры слоев в кодировщике и декодере одинаковые, только наоборот. Автоэнкодер учится сжимать и восстанавливать данные изображения в соответствии с разумным стандартом, но я хотел бы попытаться улучшить его производительность, вместо этого используя декодер в качестве точного транспонирования кодировщика.
Я не понимаю, как это сделать в TensorFlow.
Вот фрагмент построения моей сети:
imgW, imgH = 28, 28
encoderDims = [
imgW * imgH,
(imgW // 2) * (imgH // 2),
(imgW // 3) * (imgH // 3),
(imgW // 4) * (imgH // 4)
]
decoderDims = list(reversed(encoderDims))
encoderWeights, encoderBiases = [], []
decoderWeights, decoderBiases = [], []
for layer in range(len(encoderDims) - 1):
encoderWeights.append(
tf.Variable(tf.random_normal([encoderDims[layer], encoderDims[layer + 1]]))
)
encoderBiases.append(
tf.Variable(tf.random_normal([encoderDims[layer + 1]]))
)
decoderWeights.append(
tf.Variable(tf.random_normal([decoderDims[layer], decoderDims[layer + 1]]))
)
decoderBiases.append(
tf.Variable(tf.random_normal([decoderDims[layer + 1]]))
)
input = tf.placeholder(tf.float32, [None, imgW * imgH])
encoded = input
for layer in range(len(encoderDims) - 1):
encoded = tf.add(tf.matmul(encoded, encoderWeights[layer]), encoderBiases[layer])
encoded = tf.nn.sigmoid(encoded)
decoded = encoded
for layer in range(len(decoderDims) - 1):
decoded = tf.add(tf.matmul(decoded, decoderWeights[layer]), decoderBiases[layer])
if layer != len(decoderDims) - 2:
decoded = tf.nn.sigmoid(decoded)
loss = tf.losses.mean_squared_error(labels=input, predictions=decoded)
train = tf.train.AdamOptimizer(learningRate).minimize(loss)
Я не знаю, как преодолеть две проблемы:






Сомневаюсь, что это превзойдет обычные автоэнкодеры. Но если вы добьетесь удивительно хороших результатов, сообщите об этом сообществу. По поводу ваших вопросов:
1.) Поскольку вы должны использовать некоторую ошибку реконструкции между вводом и выводом, единственный вариант - тренироваться со всей сетью (например, кодировщиком и декодером в целом). Но вы можете установить флаг для переменных декодера, который предотвращает их изменение алгоритмом после инициализации. Установите их на trainable=False. После обучения для эпохи вы можете установить их вручную на транспонированные веса кодировщика.
2.) Здесь я не уверен, как вы интерпретируете «транспонировать». Если вы имеете в виду, что веса уровня 1 кодера должны совпадать с весами последнего уровня декодера, вы можете попробовать следующее:
for layer in range(len(encoderWeights)):
decoderWeights[-layer-1] = tf.transpose(encoderWeights[layer])
Если вы хотите транспонировать матрицы слоев по отдельности, вы можете использовать упомянутый tf.tranpose(). С математической точки зрения правильной обратной операцией умножения матриц будет обратная матрица, если она определена. TensorFlow предоставляет для этого tf.matrix_inverse(). Однако будьте очень осторожны при использовании, поскольку разумный результат не гарантируется.
Что касается вашего второго пункта: да, это просто простое математическое транспонирование матрицы, которое необходимо, поскольку первая матрица весов кодирования будет иметь размер, например, 728x400, и, следовательно, последняя матрица весов декодера теперь будет нужно транспонировать это, 400x728.
И по вашему 1-му пункту, я думаю, что можно использовать подход, подобный этому. Прочитав вашу точку зрения, я думаю, что мог бы просто использовать кодировщик на каждой итерации, вычислить потери, затем перенести каждую матрицу весов кодирования и, следовательно, смоделировать процесс декодирования, из которого можно вычислить потери. Затем, из-за этой потери, я мог бы тренировать только веса кодировщика, как вы обрисовали. Это будет повторяться до тех пор, пока потери не станут достаточно низкими, и я смогу затем построить постоянный декодер, транспонировав веса обученного кодера, и сохранить всю модель.
Что касается первого утверждения, это было основано исключительно на моей интуиции. Я еще не читал газет, но обязательно сделаю это. Спасибо, что сообщили мне об этом. Что касается вашего ответа на пункт 1.): это хорошее подробное описание того, как я подхожу к этому. Я просто не знаю, что вы имеете в виду под итерацией. Планируете ли вы копировать веса кодировщика после обучения с каждой партией или после окончания эпохи? Что касается пункта 2.): Я обновил свой ответ, поскольку вы указали желаемую операцию.
Да, извините, под итерацией я просто имел в виду каждый прямой проход пакета. Текущий входной сигнал будет пропущен через кодер, а затем я умножу кодированный слой на транспозиции весовых матриц кодировщика (имитируя декодер), чтобы иметь возможность вычислить потери, а затем соответствующим образом скорректировать веса кодера перед обработкой следующего партия. У меня он работает, но, похоже, он не работает без предвзятости, и теперь я не думаю, что вообще возможно добиться такого «зеркального отображения» кодировщика на декодер, когда присутствуют смещения.
Например, если весовые коэффициенты первого уровня кодера были матрицей 784x400, то смещение здесь было бы списком из 400 весовых значений. Однако в декодере последний уровень будет иметь веса 400x784, и поэтому это окончательное смещение должно быть размером 784, чего нет в кодере.
«Я сомневаюсь, что это превзойдет обычные автоэнкодеры». В этой статье (arxiv.org/pdf/1708.01715.pdf), в которой описываются успешные результаты использования модели глубокого автокодера для рекомендательной системы (что я тоже пытаюсь сделать), говорится, что это то, что они сделали в последнем параграфе страницы 1. Также в оригинальной статье Джеффри Хинтона В предложении автокодеров (cs.toronto.edu/~hinton/science.pdf) также использовалась эта перестановка весовых матриц из кодера в декодер с последующей тонкой настройкой весов кодера и декодера независимо друг от друга.