|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
import streamlit as st |
|
import tensorflow as tf |
|
from sklearn import datasets |
|
from sklearn.model_selection import train_test_split |
|
from tensorflow.keras.layers import Dense |
|
from tensorflow.keras.models import Sequential |
|
|
|
|
|
|
|
def create_datasets(n_samples=1500): |
|
noisy_circles = datasets.make_circles( |
|
n_samples=n_samples, factor=0.5, noise=0.05, random_state=170 |
|
) |
|
noisy_moons = datasets.make_moons(n_samples=n_samples, noise=0.05, random_state=170) |
|
blobs = datasets.make_blobs(n_samples=n_samples, random_state=170) |
|
rng = np.random.RandomState(170) |
|
no_structure = rng.rand(n_samples, 2), np.zeros(n_samples) |
|
X, y = datasets.make_blobs(n_samples=n_samples, random_state=170) |
|
transformation = [[0.6, -0.6], [-0.4, 0.8]] |
|
X_aniso = np.dot(X, transformation) |
|
aniso = (X_aniso, y) |
|
return [noisy_circles, noisy_moons, blobs, no_structure, aniso] |
|
|
|
|
|
|
|
def create_model(input_shape, layers): |
|
model = Sequential() |
|
|
|
if layers == 'one-layer neural network': |
|
model.add(Dense(1, input_shape=input_shape, activation="sigmoid")) |
|
elif layers == 'three-layer neural network': |
|
model.add(Dense(128, input_shape=input_shape, activation="relu")) |
|
model.add(Dense(128, activation="relu")) |
|
model.add(Dense(128, activation="relu")) |
|
model.add(Dense(1, activation="sigmoid")) |
|
elif layers == 'five-layer neural network': |
|
model.add(Dense(128, input_shape=input_shape, activation="relu")) |
|
model.add(Dense(128, activation="relu")) |
|
model.add(Dense(128, activation="relu")) |
|
model.add(Dense(128, activation="relu")) |
|
model.add(Dense(128, activation="relu")) |
|
model.add(Dense(1, activation="sigmoid")) |
|
return model |
|
|
|
|
|
def soft_quantized_influence_measure_sigmoid( |
|
y_true: tf.Tensor, y_pred: tf.Tensor, threshold: float = 0.5 |
|
) -> tf.Tensor: |
|
|
|
y_true = tf.cast(y_true, tf.float32) |
|
y_pred = tf.cast(y_pred, tf.float32) |
|
|
|
|
|
y_global_mean = tf.reduce_mean(y_true) |
|
y_std = tf.math.reduce_std(y_true) |
|
|
|
|
|
error = y_true - y_pred |
|
sigmoid_error = tf.sigmoid(error) |
|
|
|
|
|
is_small_error = sigmoid_error <= threshold |
|
|
|
|
|
n1 = tf.reduce_sum(tf.cast(is_small_error, tf.float32)) |
|
n2 = tf.reduce_sum(tf.cast(~is_small_error, tf.float32)) |
|
|
|
|
|
true_error_loss = tf.square(error) * tf.square(n1) |
|
false_error_loss = tf.square(error) * tf.square(n2) |
|
|
|
|
|
true_error_loss = tf.cast(true_error_loss, tf.float32) |
|
false_error_loss = tf.cast(false_error_loss, tf.float32) |
|
|
|
|
|
final_loss = tf.where(is_small_error, true_error_loss, false_error_loss) |
|
|
|
|
|
num_elements = tf.cast(tf.size(y_true), tf.float32) |
|
final_loss = tf.reduce_mean(final_loss) / tf.square(y_std) ** 2 / num_elements |
|
|
|
return final_loss |
|
|
|
|
|
def soft_loss_wrapper(threshold: float) -> callable: |
|
""" |
|
Creates and returns a loss function based on a given threshold. |
|
|
|
The returned loss function applies a sigmoid transformation to measure influence in a soft, quantized manner. |
|
|
|
Parameters |
|
---------- |
|
threshold : float |
|
A threshold value used within the returned loss function for calculating the influence. |
|
|
|
Returns |
|
------- |
|
callable |
|
A loss function that can be used in optimization problems where a soft measurement of influence is desired. |
|
|
|
Example |
|
------- |
|
>>> loss_function = soft_loss_wrapper(0.5) |
|
>>> # Now `loss_function` can be used as a parameter in optimization routines. |
|
""" |
|
|
|
|
|
return soft_quantized_influence_measure_sigmoid |
|
|
|
|
|
|
|
def main(): |
|
|
|
st.set_page_config(layout="wide") |
|
st.title("Classification Data and Neural Network Training Visualization") |
|
|
|
|
|
st.sidebar.header('Configuration') |
|
n_samples = st.sidebar.slider('Number of Samples', min_value=500, max_value=3000, value=1500, step=100) |
|
threshold = st.sidebar.slider('Threshold', min_value=0.0, max_value=1.0, value=0.1, step=0.01) |
|
|
|
|
|
model_option = st.sidebar.selectbox( |
|
'Choose the neural network model:', |
|
('one-layer neural network', 'three-layer neural network', 'five-layer neural network') |
|
) |
|
epochs = st.sidebar.slider('Number of Epochs', min_value=10, max_value=100, value=20, step=5) |
|
|
|
|
|
dataset_list = create_datasets(n_samples=n_samples) |
|
|
|
|
|
st.header("Datasets") |
|
scatter_cols = st.columns(5) |
|
|
|
st.header("Training and Validation Loss with MSE") |
|
mse_loss_cols = st.columns(5) |
|
|
|
st.header("Training and Validation Loss with Custom Loss") |
|
custom_loss_cols = st.columns(5) |
|
|
|
dataset_names = [ |
|
"Noisy Circles", |
|
"Noisy Moons", |
|
"Blobs", |
|
"No Structure", |
|
"Anisotropic", |
|
] |
|
|
|
|
|
for col_scatter, col_mse_loss, col_custom_loss, dataset, name in zip( |
|
scatter_cols, mse_loss_cols, custom_loss_cols, dataset_list, dataset_names |
|
): |
|
X, y = dataset |
|
|
|
|
|
with col_scatter: |
|
fig, ax = plt.subplots() |
|
if y is not None: |
|
ax.scatter(X[:, 0], X[:, 1], c=y, cmap="viridis", edgecolor="k", s=20) |
|
else: |
|
ax.scatter(X[:, 0], X[:, 1], cmap="viridis", edgecolor="k", s=20) |
|
ax.set_xticks([]) |
|
ax.set_yticks([]) |
|
ax.set_title(name) |
|
st.pyplot(fig) |
|
|
|
if y is not None: |
|
|
|
X_train, X_test, y_train, y_test = train_test_split( |
|
X, y, test_size=0.2, random_state=42 |
|
) |
|
|
|
|
|
model_mse = create_model((2,), model_option) |
|
model_mse.compile( |
|
optimizer="sgd", loss="binary_crossentropy", metrics=["accuracy"] |
|
) |
|
history_mse = model_mse.fit( |
|
X_train, y_train, validation_split=0.2, epochs=epochs, verbose=0 |
|
) |
|
|
|
|
|
with col_mse_loss: |
|
test_loss_mse, test_acc_mse = model_mse.evaluate( |
|
X_test, y_test, verbose=0 |
|
) |
|
fig, ax = plt.subplots() |
|
ax.plot(history_mse.history["loss"], label="Training Loss") |
|
ax.plot(history_mse.history["val_loss"], label="Validation Loss") |
|
ax.set_title(f"MSE\nTest Loss: {test_loss_mse:.4f}") |
|
ax.legend() |
|
st.pyplot(fig) |
|
|
|
|
|
model_custom = create_model((2,), model_option) |
|
model_custom.compile( |
|
optimizer="sgd", |
|
loss=soft_loss_wrapper(threshold), |
|
metrics=["accuracy"], |
|
) |
|
history_custom = model_custom.fit( |
|
X_train, y_train, validation_split=0.2, epochs=epochs, verbose=0 |
|
) |
|
|
|
|
|
with col_custom_loss: |
|
test_loss_custom, test_acc_custom = model_custom.evaluate( |
|
X_test, y_test, verbose=0 |
|
) |
|
fig, ax = plt.subplots() |
|
ax.plot(history_custom.history["loss"], label="Training Loss") |
|
ax.plot(history_custom.history["val_loss"], label="Validation Loss") |
|
ax.set_title(f"Custom Loss\nTest Loss: {test_loss_custom:.4f}") |
|
ax.legend() |
|
st.pyplot(fig) |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|