Почему я получаю нестабильные значения в закодированном фрейме данных каждый раз, когда запускаю автоэнкодер?

Я пытаюсь найти оптимальное количество кластеров в своих данных с помощью метода локтя и оценки силуэта при использовании KMeans. Хотя я тестирую эти методы с помощью уменьшения размерности.

Если я попробую PCA несколько раз, я каждый раз буду получать одни и те же графики для метода локтя и силуэта. Но если я попробую энкодер со структурой нейронной сети для той же цели, я каждый раз получаю разные графики. И, следовательно, у меня нет уверенности в использовании этого метода кодирования, поскольку он приводит к разным оптимальным числам кластеров.

Почему это происходит? Даже если я нормализую свои данные, результаты будут меняться.

Что я могу сделать, чтобы правильно использовать этот метод кодирования? Я знаю, что мог бы просто выбрать PCA для этого, но я хотел бы понять и посмотреть, не делаю ли я что-то не так.

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

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn.metrics import silhouette_score, silhouette_samples

import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import backend as K

iris = datasets.load_iris()
X = pd.DataFrame(iris.data)

def autoencoding(data):
    n_input_layer = data.shape[1]
    n_encoding_layer = 2
    n_output_layer = n_input_layer

    # AUTOENCODER
    autoencoder = tf.keras.models.Sequential([
        # ENCODER
        Dense(n_input_layer, input_shape = (n_input_layer,), activation = 'relu'),   # Input layer    
    
        # CENTRAL LAYER
        Dense(n_encoding_layer, activation = 'relu', name = 'central_layer'), 
    
        # DECODER
        Dense(n_output_layer, activation = 'relu')  # Output layer
    ])

    n_epochs = 2000
    loss = tf.keras.losses.MeanSquaredError()
    optimizer = tf.optimizers.Adam(learning_rate = 0.001, decay = 0.0001, clipvalue = 0.5)

    loss_history = []  # save loss improvement

    data = np.array(data, dtype=np.float)

    for epoch in range(n_epochs):
    
        with tf.GradientTape() as tape:
            current_loss = loss(autoencoder(data), data)
        
        gradients = tape.gradient(current_loss, autoencoder.trainable_variables)    # get the gradient of the loss function
        optimizer.apply_gradients(zip(gradients, autoencoder.trainable_variables))  # update the weights
    
        loss_history.append(current_loss.numpy())  # save current loss in its history
    
        # show loss improvement every 200 epochs
        if (epoch+1) % 200 == 0:
            print(str(epoch+1) + '.\tLoss: ' + str(current_loss.numpy()))

    print('\nEncoding complete')
    return autoencoder

X_autoencoded = autoencoding(X)

# ENCODER EXTRACTION
def encoded(autoencoder, data):

    # create a Keras function
    extract_encoded_data = K.function(inputs = autoencoder.layers[0].input, 
                                  outputs = autoencoder.layers[1].output)
    # extract encoded dataframe
    encoded_dataframe = extract_encoded_data(data.values)
    encoded_data = pd.DataFrame(encoded_dataframe)
    return encoded_data

X_encoded = encoded(X_autoencoded, X)

# ELBOW METHOD AND SILHOUETTE SCORE
inertia =[]
sil =[]

for k in range(2,14):
    kmeans_rand = KMeans(n_clusters=k, init='k-means++', random_state=42)
    kmeans_rand.fit(X_encoded)
    y_pred = kmeans_rand.predict(X_encoded)

    inertia.append(kmeans_rand.inertia_)
    sil.append((k, silhouette_score(X_encoded, y_pred)))

sil_samples = silhouette_samples(X_encoded, y_pred)

fig, ax = plt.subplots(1, 2, figsize=(12,4))
ax[0].plot(range(2,14), inertia)
ax[0].set_title('Elbow Method')
ax[0].set_xlabel('Number of clusters')
ax[0].set_ylabel('Inertia')

x_sil = [x[0] for x in sil]
y_sil = [x[1] for x in sil]
ax[1].plot(x_sil, y_sil)
ax[1].set_xlabel('Number of Clusters')
ax[1].set_ylabel('Silhouetter Score')
ax[1].set_title('Silhouetter Score Curve')

person user026    schedule 27.07.2020    source источник


Ответы (1)


попробуйте установить семя, используя эти строки в верхней части кода:

tf.random.set_seed(33)
os.environ['PYTHONHASHSEED'] = str(33)
np.random.seed(33)
random.seed(33)

session_conf = tf.compat.v1.ConfigProto(
    intra_op_parallelism_threads=1, 
    inter_op_parallelism_threads=1
)
sess = tf.compat.v1.Session(
    graph=tf.compat.v1.get_default_graph(), 
    config=session_conf
)
tf.compat.v1.keras.backend.set_session(sess)

Я использую tf.keras (TF 2.2) без графического процессора и получаю одинаковые результаты при каждом запуске.

https://colab.research.google.com/drive/1S9iB7AsLLkdTAY827eOBN_VRRi2EVWRA?usp=sharing

person Marco Cerliani    schedule 28.07.2020
comment
@ user026 дайте мне знать, если возникнут проблемы - person Marco Cerliani; 28.07.2020
comment
Это сработало отлично! Кстати, я использую TF 2.1. Большое спасибо! - person user026; 28.07.2020