from __future__ import annotations import numpy as np import gradio as gr from sklearn.svm import SVC import plotly.graph_objects as go def plot_decision( clf: SVC, X: np.ndarray, y: np.array, x_range: np.array, y_range: np.array, weights: np.array, title: str ): # plot the decision function xx, yy = np.meshgrid(x_range, y_range) Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) fig = go.Figure() fig.add_trace( go.Contour( x=x_range, y=y_range, z=Z, colorscale="Viridis", opacity=0.75, showscale=False, ) ) fig.add_trace( go.Scatter( x=X[:, 0], y=X[:, 1], mode="markers", marker=dict( color=y, colorscale="viridis", size=(weights + 5) * 2 ), ) ) # Remove x and y ticks fig.update_xaxes(showticklabels=False) fig.update_yaxes(showticklabels=False) # Add title fig.update_layout(title=title) return fig def app_fn(seed: int, weight_1: int, weight_2: int): # we create 20 points np.random.seed(seed) X = np.r_[np.random.randn(10, 2) + [1, 1], np.random.randn(10, 2)] y = [1] * 10 + [-1] * 10 sample_weight_last_ten = abs(np.random.randn(len(X))) sample_weight_constant = np.ones(len(X)) sample_weight_last_ten[15:] *= weight_1 sample_weight_last_ten[9] *= weight_2 # This model does not take into account sample weights. clf_no_weights = SVC(gamma=1) clf_no_weights.fit(X, y) # This other model takes into account some dedicated sample weights. clf_weights = SVC(gamma=1) clf_weights.fit(X, y, sample_weight=sample_weight_last_ten) # Plotting x_range = np.arange(-4, 5, 0.1) fig_no_weights = plot_decision( clf_no_weights, X, y, x_range, x_range, sample_weight_constant, "SVM without Weights" ) fig_weights = plot_decision( clf_weights, X, y, x_range, x_range, sample_weight_last_ten, "SVM with Weights" ) return fig_no_weights, fig_weights title = "SVM with Weighted Samples" with gr.Blocks(title=title) as demo: gr.Markdown(f"# {title}") gr.Markdown( """ ### This is a demo of how SVMs can be trained with weighted samples \ and the impact on the decision boundary. To represent that a synthetic \ dataset is generated with 20 points, 10 of which are assigned to the \ positive class and 10 to the negative class. A weight is assigned to \ each sample, which is the importance of that sample in the dataset. \ A model with and without weights is trained and the decision boundary \ is plotted. The size of the points is proportional to the weight of \ the sample. Created by [@eduardopacheco](https://huggingface.co/EduardoPacheco) based on [scikit-learn-docs](https://scikit-learn.org/stable/auto_examples/svm/plot_weighted_samples.html#sphx-glr-auto-examples-svm-plot-weighted-samples-py) """ ) with gr.Row(): seed = gr.inputs.Slider(0, 100, 1, default=0, label="Seed") weight_1 = gr.inputs.Slider(0, 20, 1, default=5, label="Weight for last 5 Samples") weight_2 = gr.inputs.Slider(0, 20, 1, default=15, label="Weight for Sample 10") # btn = gr.Button("Run") with gr.Row(): fig_no_weights = gr.Plot(label="SVM without Weights") fig_weights = gr.Plot(label="SVM with Weights") seed.change(fn=app_fn, outputs=[fig_no_weights, fig_weights], inputs=[seed, weight_1, weight_2]) weight_1.change(fn=app_fn, outputs=[fig_no_weights, fig_weights], inputs=[seed, weight_1, weight_2]) weight_2.change(fn=app_fn, outputs=[fig_no_weights, fig_weights], inputs=[seed, weight_1, weight_2]) demo.load(fn=app_fn, outputs=[fig_no_weights, fig_weights], inputs=[seed, weight_1, weight_2]) demo.launch()