最近在 kaggle 上學習些 keras 的使用方法,這裡總結下 AutoEncoder 使用方式
模型定義
對于
AutoEncoder
模型定義有兩種方式:
- Encoder 和 Decoder 分開定義,然後通過 Model 進行合并
- Encoder 和 Decoder 同一個 Model 進行定義,在 Encoder 最後一層設定特定名稱,然後在取出直接使用即可
分開定義
from operator import mul
from functools import reduce
def product(dset):
return reduce(mul, dset)
def encoder_model(x_shape, y_shape):
"""
定義 Encoder 部分模型,這裡将最後一層的資料次元記錄下來,作為 Decoder 輸入層後的接下來的一層大小
"""
inp = Input(shape=x_shape)
m = Conv2D(16, (3, 3), activation='relu', padding='same')(inp)
m = MaxPooling2D((2, 2), padding='same')(m)
m = Conv2D(8, (3, 3), activation='relu', padding='same')(m)
m = MaxPooling2D((2, 2), padding='same')(m)
m = Conv2D(8, (3, 3), activation='relu', padding='same')(m)
shape = m.shape
m = Flatten()(m)
outp = Dense(y_shape)(m)
return inp, outp, shape[1:]
def decoder_model(x_shape, x_shape_2d):
"""
定義 Decoder 部分模型
"""
inp = Input(shape=x_shape)
m = Dense(product(x_shape_2d))(inp)
# 資料次元的轉換 1D 轉為 2D
m = Reshape(x_shape_2d)(m)
m = Conv2D(8, (3, 3), activation='relu', padding='same')(m)
m = UpSampling2D((2, 2))(m)
m = Conv2D(8, (3, 3), activation='relu', padding='same')(m)
m = UpSampling2D((2, 2))(m)
outp = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(m)
return inp, outp
# 定義 encoder 模型
encoder_inp, encoder_outp, shape = encoder_model((28, 28, 1), 100)
encoder = Model(inputs=encoder_inp, outputs=encoder_outp)
encoder.summary()
print(shape)
# 定義 decoder 模型
decoder_inp, decoder_outp = decoder_model(encoder_outp.shape[1:], shape)
decoder = Model(inputs=decoder_inp, outputs=decoder_outp)
decoder.summary()
# 定義 autoencoder 模型
autoencoder = Model(inputs=encoder_inp, outputs=decoder(encoder(encoder_inp)), name='autoencoder')
autoencoder.compile(loss='binary_crossentropy', optimizer='adam')
autoencoder.summary()
noise = np.random.normal(loc=0.5, scale=0.5, size=x_train.shape)
x_train_noisy = x_train + noise
noise = np.random.normal(loc=0.5, scale=0.5, size=x_cv.shape)
x_cv_noisy = x_cv + noise
autoencoder.fit(x_train_noisy, x_train, validation_data=(x_cv_noisy, x_cv),
epochs=100, batch_size=128)
同時定義
input_img = Input(shape=(28, 28, 1)) # adapt this if using `channels_first` image data format
x = Conv2D(16, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same', name='encoder')(x)
# at this point the representation is (4, 4, 8) i.e. 128-dimensional
x = Conv2D(8, (3, 3), activation='relu', padding='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(16, (3, 3), activation='relu')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
autoencoder = Model(input_img, decoded)
autoencoder.compile(loss='binary_crossentropy', optimizer='adam')
autoencoder.summary()
autoencoder.fit(x_train, x_train, batch_size=64, epochs=100, verbose=1, validation_data=(x_cv, x_cv))
encoder = Model(inputs=autoencoder.input,
outputs=autoencoder.get_layer('encoder').output)
這樣通過 AutoEncoder 模型的訓練來訓練 Encoder 模型
使用 Encoder
x_encoded = encoder.predict(x_cv_noisy)
print(x_encoded[:1])
常見問題
- Loss 高居不下
可以通過如下幾個方面進行改善:
- 對輸入資料進行歸一化,輸出的資料很容易拟合
x_train = normalize(x_train).reshape(-1, 28, 28, 1).astype(float32) / 255
# 在 Decoder 輸出的内容需要展示為圖檔時候,簡單的乘以 255 即可
x_decoded = autoencoder.predict(x_cv_noisy)
imgs = np.concatenate([x_test[:num], x_cv_noisy[:num], x_decoded[:num]])
imgs = imgs.reshape((rows * 3, cols, image_size, image_size))
imgs = np.vstack(np.split(imgs, rows, axis=1))
imgs = imgs.reshape((rows * 3, -1, image_size, image_size))
imgs = np.vstack([np.hstack(i) for i in imgs])
# 将資料進行還原即可
imgs = (imgs * 255).astype(np.uint8)
- 降低學習率,歸一化之後,資料基本都是小數,學習率高了會不容易拟合
sgd = SGD(lr=1e-4, decay=1e-6, momentum=0.4, nesterov=True)
- 修改權重初始化的方式
m = Conv2D(16, 3, activation=LeakyReLU(alpha=0.2), padding='same', kernel_initializer='glorot_normal')(m)
·「參考」
Why my training and validation loss is not changing? Building Autoencoders in Keras