Semi-Supervised Learning with Scikit-learn’s SelfTrainingClassifier: A Visual Guide

Chang In Moon Chang In Moon #python#machine-learning

In many real-world scenarios, we often find ourselves with a lot of unlabeled data and a small portion of labeled data.

In many real-world scenarios, we often find ourselves with a lot of unlabeled data and a small portion of labeled data. Manually labeling this data can be expensive and time-consuming. This is where semi-supervised learning shines. It leverages both labeled and unlabeled data to improve the model’s performance.

Scikit-learn offers the SelfTrainingClassifier, a semi-supervised learning method that iteratively pseudo-labels the unlabeled data and refines the model. In this tutorial, we’ll understand how the SelfTrainingClassifier works and visualize its pseudo-labeling process using an animation.

Setting up the Environment

Before we dive in, ensure you have the necessary packages installed:

pip install numpy matplotlib scikit-learn

Generating Synthetic Data

Let’s start by creating a synthetic dataset with two clusters:

from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=400, centers=2, cluster_std=5, random_state=42)
y[123:] = -1 # Unlabeled samples

We’ve deliberately left a large portion of the samples as unlabeled (denoted by -1).

Initializing the Base Classifier

For this tutorial, we’ll use a logistic regression model with an elastic net penalty:

from sklearn.linear_model import LogisticRegression
base_classifier = LogisticRegression(penalty='elasticnet',
solver='saga',
max_iter=10000,
class_weight='balanced',
l1_ratio=0.1,
C=0.001)

The SelfTrainingClassifier

The SelfTrainingClassifier in Scikit-learn takes in the base classifier and iteratively pseudo-labels the unlabeled data:

from sklearn.semi_supervised import SelfTrainingClassifier
self_training_clf = SelfTrainingClassifier(base_classifier, criterion="k_best", k_best=2, max_iter=10)

Here, the k_best criterion means that in each iteration, the two most confidently predicted samples will be pseudo-labeled.

Training and Collecting Iteration Data

We’ll manually run the classifier for 10 iterations, capturing the state of the labels at each step:

iterations_data = []
def train_one_iteration():
prev_labels = y.copy()
self_training_clf.fit(X, y)
new_labels = self_training_clf.transduction_
y[:] = new_labels
pseudo_labeled_indices = np.where((prev_labels == -1) & (new_labels != -1))
return pseudo_labeled_indices
for i in range(10):
indices = train_one_iteration()
iterations_data.append((y.copy(), indices))

Visualizing the Process

Using Matplotlib, we can animate the pseudo-labeling process:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
scatter = ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired, edgecolors='k')
highlighted, = ax.plot([], [], 'ro', markersize=5)
def init():
return scatter, highlighted
def update(frame):
scatter.set_array(iterations_data[frame][0])
highlighted.set_data(X[iterations_data[frame][1], 0], X[iterations_data[frame][1], 1])
ax.set_title(f"SelfTrainingClassifier Iteration: {frame+1}")
return scatter, highlighted
ani = FuncAnimation(fig, update, frames=len(iterations_data), init_func=init, blit=False)
ani.save('self_training_animation.gif', writer='imagemagick', fps=1)

This will save the animation as a GIF. The red dots in the animation represent the samples that have been pseudo-labeled in each iteration.

Conclusion

The SelfTrainingClassifier is a powerful tool for semi-supervised learning, especially when you have a large amount of unlabeled data. By visualizing its pseudo-labeling process, we gain insights into how the classifier is gradually confident about labeling the unlabeled samples. This can be especially useful for understanding and debugging your semi-supervised learning models.

Comments