from nn.activation import SoftMax import plotly.express as px from sklearn import datasets from sklearn.preprocessing import OneHotEncoder from sklearn.model_selection import train_test_split import numpy as np import gradio as gr import nn # custom neural network module from vis import ( # classification visualization funcitons show_digits, hits_and_misses, loss_history_plt, make_confidence_label, ) def _preprocess_digits( seed: int, ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: digits = datasets.load_digits() n_samples = len(digits.images) data = digits.images.reshape((n_samples, -1)) y = OneHotEncoder().fit_transform(digits.target.reshape(-1, 1)).toarray() X_train, X_test, y_train, y_test = train_test_split( data, y, test_size=0.2, random_state=seed, ) return X_train, X_test, y_train, y_test X_train, X_test, y_train, y_test = _preprocess_digits(seed=1) def classification( Seed: int = 0, Hidden_Layer_Activation: str = "Relu", Activation_Func: str = "SoftMax", Loss_Func: str = "CrossEntropyWithLogitsLoss", Epochs: int = 100, Hidden_Size: int = 8, Learning_Rate: float = 0.001, ) -> tuple[gr.Plot, gr.Plot, gr.Label]: assert Activation_Func in nn.ACTIVATIONS assert Hidden_Layer_Activation in nn.ACTIVATIONS assert Loss_Func in nn.LOSSES classifier = nn.NN( epochs=Epochs, learning_rate=Learning_Rate, hidden_activation_fn=nn.ACTIVATIONS[Hidden_Layer_Activation], activation_fn=nn.ACTIVATIONS[Activation_Func], loss_fn=nn.LOSSES[Loss_Func], hidden_size=Hidden_Size, input_size=64, # 8x8 image of pixels output_size=10, # digits 0-9 seed=Seed, ) classifier.train(X_train=X_train, y_train=y_train) pred = classifier.predict(X_test=X_test) hits_and_misses_fig = hits_and_misses(y_pred=pred, y_true=y_test) loss_fig = loss_history_plt( loss_history=classifier._loss_history, loss_fn_name=classifier.loss_fn.__class__.__name__, ) label_dict = make_confidence_label(y_pred=pred, y_test=y_test) return ( gr.Plot(loss_fig, show_label=False), gr.Plot(hits_and_misses_fig, show_label=False), gr.Label(label_dict, label="Classification Confidence Rankings"), ) if __name__ == "__main__": with gr.Blocks() as interface: gr.Markdown("# Backpropagation Playground") gr.Markdown( """ ## What is this?
The Backpropagation Playground is a GUI built around a neural network framework that I have built from scratch in [numpy](https://numpy.org/). In this GUI, you can test different hyper parameters that will be fed to this framework and used to train a neural network on the [MNIST](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html) dataset of 8x8 pixel images. ## ⚠️ PLEASE READ ⚠️ This application is impossibly slow on the HuggingFace CPU instance that it is running on. It is advised to clone the repository and run it locally. In order to get a decent classification score on the validation set of the MNIST data (hard coded to 20%), you will have to do somewhere between 15,000 epochs and 50,000 epochs with a learning rate around 0.001, and a hidden layer size over 10. (roughly the example that I have provided). Running this many epochs with a hidden layer of that size is pretty expensive on 2 cpu cores that this space has. So if you are actually curious, you might want to clone this and run it locally because it will be much much faster. `git clone https://huggingface.co/spaces/Jensen-holm/Backprop-Playground` After cloning, you will have to install the dependencies from requirements.txt into your environment. (venv reccommended) `pip3 install -r requirements.txt` Then, you can run the application on localhost with the following command. `python3 app.py` """ ) with gr.Tab("Classification"): with gr.Row(): data_plt = show_digits() gr.Plot(data_plt) with gr.Row(): seed_input = [gr.Number(minimum=0, label="Random Seed")] # inputs in the same row with gr.Row(): with gr.Column(): numeric_inputs = [ gr.Slider( minimum=100, maximum=100_000, step=50, label="Epochs" ), gr.Slider( minimum=2, maximum=64, step=2, label="Hidden Network Size" ), gr.Number(minimum=0.00001, maximum=1.5, label="Learning Rate"), ] with gr.Column(): fn_inputs = [ gr.Dropdown( choices=["Relu", "Sigmoid", "TanH"], label="Hidden Layer Activation", ), gr.Dropdown(choices=["SoftMax"], label="Output Activation"), gr.Dropdown( choices=["CrossEntropy", "CrossEntropyWithLogitsLoss"], label="Loss Function", ), ] inputs = seed_input + fn_inputs + numeric_inputs with gr.Row(): train_btn = gr.Button("Train", variant="primary") with gr.Row(): gr.Examples( examples=[ [ 2, "Relu", "SoftMax", "CrossEntropyWithLogitsLoss", 15_000, 14, 0.001, ] ], inputs=inputs, ) # outputs in row below inputs with gr.Row(): plt_outputs = [ gr.Plot(label="Loss History / Epoch"), gr.Plot(label="Hits & Misses"), ] with gr.Row(): label_output = [gr.Label(label="Class Confidences")] train_btn.click( fn=classification, inputs=inputs, outputs=plt_outputs + label_output, ) with gr.Tab("Regression"): gr.Markdown("### Coming Soon") interface.launch(show_error=True)