Задача 1
Проблема в том, что вы пытаетесь сгладить слой, который уже является плоским: ваш кодировщик состоит из одномерных слоев Desnse, которые имеют форму (batch_size, dim)
.
Слой Flatten ожидает, по крайней мере, двухмерный ввод, т. Е. Имеет трехмерную форму (batch_size, dim1, dim2)
(например, вывод слоя Conv2D), удалив его, модель будет построена правильно:
encoding_dim = 32
input_img = layers.Input(shape=(784, ))
encoded = layers.Dense(encoding_dim * 4, activation='relu')(input_img)
encoded = layers.Dense(encoding_dim * 2, activation='relu')(encoded)
encoded = layers.Dense(encoding_dim, activation='relu')(encoded)
encoder = Model(input_img, encoded)
[...]
model = Sequential()
for layer in encoder.layers:
print(layer.name)
model.add(layer)
model.add(layers.Dense(20, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(10, activation='softmax'))
model.summary()
Какие выходы:
input_1
dense_1
dense_2
dense_3
Model: "sequential_1"
________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_1 (Dense) (None, 128) 100480
_________________________________________________________________
dense_2 (Dense) (None, 64) 8256
_________________________________________________________________
dense_3 (Dense) (None, 32) 2080
_________________________________________________________________
dense_4 (Dense) (None, 20) 660
_________________________________________________________________
dropout_1 (Dropout) (None, 20) 0
_________________________________________________________________
dense_5 (Dense) (None, 10) 210
=================================================================
Total params: 111,686
Trainable params: 111,686
Non-trainable params: 0
_________________________________________________________________
___
Редактировать: объединение ответов на вопросы в комментариях
В: Как я могу быть уверен, что новая модель будет использовать те же веса, что и ранее обученный энкодер?
A: В вашем коде вы выполняете итерацию по слоям, содержащимся внутри кодировщика, а затем передаете каждый из них в model.add()
. Здесь вы передаете ссылку на каждый слой напрямую, поэтому у вас будет тот же самый слой внутри вашей новой модели. Вот подтверждение концепции с использованием имени слоя:
encoding_dim = 32
input_img = Input(shape=(784, ))
encoded = Dense(encoding_dim * 4, activation='relu')(input_img)
encoded = Dense(encoding_dim * 2, activation='relu')(encoded)
encoded = Dense(encoding_dim, activation='relu')(encoded)
decoded = Dense(encoding_dim * 2, activation='relu')(encoded)
decoded = Dense(encoding_dim * 4, activation='relu')(decoded)
decoded = Dense(784, activation='sigmoid')(decoded)
autoencoder = Model(input_img, decoded)
print("autoencoder first Dense layer reference:", autoencoder.layers[1])
encoder = Model(input_img, encoded)
print("encoder first Dense layer reference:", encoder.layers[1])
new_model = Sequential()
for i, layer in enumerate(encoder.layers):
print("Before: ", layer.name)
new_model.add(layer)
if i != 0:
new_model.layers[i-1].name = "new_model_"+layer.name
print("After: ", layer.name)
Какие выходы:
autoencoder first Dense layer reference: <keras.layers.core.Dense object at
0x7fb5f138e278>
encoder first Dense layer reference: <keras.layers.core.Dense object at
0x7fb5f138e278>
Before: input_1
Before: dense_1
After: new_model_dense_1
Before: dense_2
After: new_model_dense_2
Before: dense_3
After: new_model_dense_3
Как видите, ссылки на слои в кодировщике и в автоматическом кодере совпадают. Более того, изменяя имя слоя внутри новой модели, мы также меняем имя слоя внутри соответствующего слоя кодера. Для получения более подробной информации об аргументах Python, передаваемых по ссылке, ознакомьтесь с этим ответом .
В: мне нужно горячее кодирование для моих данных? если так, то как?
A: Вам нужно одноразовое кодирование, поскольку вы имеете дело с категориальной проблемой с несколькими метками. Кодирование просто выполняется с помощью удобной функции keras:
from keras.utils import np_utils
one_hot = np_utils.to_categorical(y_train)
Вот ссылка на документацию .
___
Задача 2
Что касается вашего второго вопроса, то не очень понятно, к чему вы стремитесь, однако мне кажется, что вы хотите построить архитектуру, которая содержит несколько параллельных авто-кодировщиков, которые специализируются на различных задачах, и затем объединить их вывод, добавив несколько финальных, общих слоев.
В любом случае, пока я могу предложить вам взглянуть на это руководство , в котором объясняется, как создавать модели с несколькими входами и несколькими выходами и использовать его в качестве основы для Начните с вашей пользовательской реализации.
___
Редактировать 2: интеграция с ответом на задачу 2
Что касается жадных тренировочных заданий, то подход состоит в том, чтобы тренировать один слой за раз, замораживая все предыдущие, когда вы добавляете новые. Вот пример для сети с 3 (+1) жадными обученными слоями, которая позже используется в качестве основы для новой модели:
(x_train, y_train), (x_test, y_test) = mnist.load_data()
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
x_train = np.reshape(x_train, (x_train.shape[0], -1))
x_test = np.reshape(x_test, (x_test.shape[0], -1))
model = Sequential()
model.add(Dense(256, activation="relu", kernel_initializer="he_uniform", input_shape=(28*28,)))
model.add(Dense(10, activation="softmax"))
model.compile(optimizer=SGD(lr=0.01, momentum=0.9), loss="categorical_crossentropy", metrics=["accuracy"])
model.fit(x_train, y_train, batch_size=64, epochs=50, verbose=1)
# Remove last layer
model.pop()
# 'Freeze' previous layers, so to single-train the new one
for layer in model.layers:
layer.trainable = False
# Append new layer + classification layer
model.add(Dense(64, activation="relu", kernel_initializer="he_uniform"))
model.add(Dense(10, activation="softmax"))
model.fit(x_train, y_train, batch_size=64, epochs=50, verbose=0)
# Remove last layer
model.pop()
# 'Freeze' previous layers, so to single-train the new one
for layer in model.layers:
layer.trainable = False
# Append new layer + classification layer
model.add(Dense(32, activation="relu", kernel_initializer="he_uniform"))
model.add(Dense(10, activation="softmax"))
model.fit(x_train, y_train, batch_size=64, epochs=50, verbose=0)
# Create new model which will use the pre-trained layers
new_model = Sequential()
# Discard the last layer from the previous model
model.pop()
# Optional: you can decide to set the pre-trained layers as trainable, in
# which case it would be like having initialized their weights, or not.
for l in model.layers:
l.trainable = True
new_model.add(model)
new_model.add(Dense(20, activation='relu'))
new_model.add(Dropout(0.5))
new_model.add(Dense(10, activation='softmax'))
new_model.compile(optimizer=SGD(lr=0.01, momentum=0.9), loss="categorical_crossentropy", metrics=["accuracy"])
new_model.fit(x_train, y_train, batch_size=64, epochs=100, verbose=1)
Это примерно так, однако я должен сказать, что обучение жадного слоя больше не может быть правильным решением: в настоящее время ReLU, Dropout и другие методы регуляризации, которые делают обучение жадного слоя устаревшей и отнимающей много времени инициализацией веса, поэтому вы можете захотеть взглянуть на другие возможности, прежде чем идти на жадные тренировки.
___