1

I want to get features from a dataset (here MNIST) to put them into a cluster algorithm like k-means. The feature generation should be unsuperviesed, so I choose autoencoding to do it. I want that the Autoencoder is only trained by the loss in the second output layer 'output_layer2' and after the training I want to get the features from the first output layer 'output_layer1'. To get two output layer I choose funtional API in keras. But I don't know how to get the features and how to train only on one loss. Furthermore I get error massages like the ones under my code:

import numpy as np
import sys

import sklearn
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Input, Reshape, Conv2D, MaxPool2D, Conv2DTranspose
from tensorflow.keras.optimizers import SGD

assert sys.version_info >= (3, 5)
# Scikit-Learn ≥0.20 is required
assert sklearn.__version__ >= "0.20"
# TensorFlow ≥2.0-preview is required
assert tf.__version__ >= "2.0"


def get_MNISTdata(data_sz=10000):
    (X_train_full, y_train_full), (
        X_test,
        y_test,
    ) = keras.datasets.mnist.load_data()
    X_train_full = X_train_full.astype(np.float32) / 255
    X_test = X_test.astype(np.float32) / 255
    data_tr = X_train_full.shape[0] - data_sz
    X_train, X_valid = X_train_full[:-data_tr], X_train_full[-data_tr:]
    y_train, y_valid = y_train_full[:-data_tr], y_train_full[-data_tr:]
    return X_train, X_valid, y_train, y_valid


def rounded_accuracy(y_true, y_pred):
    return keras.metrics.binary_accuracy(tf.round(y_true), tf.round(y_pred))


def convoluntional_autoencoder(
    X_train,
    X_valid,
    shape1=28,
    shape2=28,
    channels=1,
    initial_features=16,
    kernel_sz=3,
    padding1="SAME",
    padding2="VALID",
    activation1="selu",
    activation2="sigmoid",
    pool_sz=2,
    strides=2,
    loss1="binary_crossentropy",
    loss2="softmax",
    lr=1.0,
    epochs=3,
):

    tf.random.set_seed(42)
    np.random.seed(42)

    # encoder
    input_layer = Input(shape=(shape1, shape2, channels))
    Layer1 = Conv2D(
        initial_features,
        kernel_size=kernel_sz,
        padding=padding1,
        activation=activation1,
    )(input_layer)
    Layer2 = MaxPool2D(pool_size=pool_sz)(Layer1)
    Layer3 = Conv2D(
        initial_features * 2,
        kernel_size=kernel_sz,
        padding=padding1,
        activation=activation1,
    )(Layer2)
    Layer4 = MaxPool2D(pool_size=pool_sz)(Layer3)
    Layer5 = Conv2D(
        initial_features * 4,
        kernel_size=kernel_sz,
        padding=padding1,
        activation=activation1,
    )(Layer4)
    output_layer1 = MaxPool2D(pool_size=pool_sz)(Layer5)

    n_poolingLayer = 3

    # decoder
    Layer7 = Conv2DTranspose(
        initial_features * 2,
        kernel_size=kernel_sz,
        strides=strides,
        padding=padding2,
        activation=activation1,
        input_shape=[
            int(shape1 / (2 ** n_poolingLayer)),
            int(shape2 / (2 ** n_poolingLayer)),
            initial_features * 2 ** (n_poolingLayer - 1),
        ],
    )(output_layer1)
    Layer8 = Conv2DTranspose(
        initial_features,
        kernel_size=kernel_sz,
        strides=strides,
        padding=padding1,
        activation=activation1,
    )(Layer7)
    output_layer2 = Conv2DTranspose(
        channels,
        kernel_size=kernel_sz,
        strides=strides,
        padding=padding1,
        activation=activation2,
    )(Layer8)

    conv_ae = Model(inputs=input_layer, outputs=[output_layer1, output_layer2])
    conv_ae.compile(
        loss={"output_layer1": loss1, "output_layer2": loss1},
        loss_weights=[0, 1],
        optimizer=SGD(lr=lr),
        metrics=[rounded_accuracy],
    )

    conv_ae.fit(
        X_train,
        X_train,
        epochs=epochs,
        validation_data=(X_valid, X_valid),
    )

    conv_ae.summary()

    # features = ?

    return # features

If I do this

X_train, X_valid, y_train, y_valid = get_MNISTdata(data_sz=10000)

and this

features = convoluntional_autoencoder(
    X_train,
    X_valid,
    shape1=28,
    shape2=28,
    channels=1,
    initial_features=16,
    kernel_sz=3,
    padding1="SAME",
    padding2="VALID",
    activation1="selu",
    activation2="sigmoid",
    pool_sz=2,
    strides=2,
    loss1="binary_crossentropy",
    loss2="softmax",
    lr=1.0,
    epochs=1,
)

I get at the column conv_ae.fit(...) the error:

ValueError: Found unexpected losses or metrics that do not correspond to any Model 
output: dict_keys(['output_layer1', 'output_layer2']). Valid mode output names: ['max_pooling2d_5', 'conv2d_transpose_5']. 
Received struct is: {'output_layer1': 'binary_crossentropy', 'output_layer2': 'binary_crossentropy'}.

If I change the conv_ae.compile-column to that:

conv_ae.compile(
        loss=loss1,
        loss_weights=[0, 1],
        optimizer=SGD(lr=lr),
        metrics=[rounded_accuracy],
    )

I get at the column conv_ae.fit(...) the error:

ValueError: Dimensions must be equal, but are 28 and 3 for '{{node binary_crossentropy/mul}} 
= Mul[T=DT_FLOAT](IteratorGetNext:1, binary_crossentropy/Log)' with input shapes: [?,28,28], [?,3,3,64].
Marie C.
  • 21
  • 4

0 Answers0