A small from-scratch implementation of the core idea behind Deep Clustering for Unsupervised Learning of Visual Features (Caron, Bojanowski, Joulin, Douze — ECCV 2018), applied to MNIST with PyTorch.
Core idea: instead of labels, use k-Means on the network's own features to generate pseudo-labels. Then train the network to predict them, and repeat.
All code is in: notebooks/deepcluster.ipynb.
- Supervised baseline — a 4-layer CNN trained on the real MNIST labels, as a reference point for what this architecture can do.
- k-Means from scratch — a plain NumPy implementation of the k-Means algorithm and a plot
of within-cluster variance for
k = 1..30on raw pixels. - DeepCluster loop — no labels are used. Each step encodes a batch, L2-normalises the features, clusters them with k-Means, and trains the classifier head to predict the cluster index. Centroids carry over between steps and are only re-fitted at the start of each epoch.
- Probe — the encoder is frozen, the head is replaced with a freshly initialised one and trained on the real labels. The head never sees the images, so its accuracy measures how much class structure the unsupervised encoder picked up.
| Setup | Test accuracy |
|---|---|
| Supervised CNN, all weights trained on labels | 0.9872 |
| DeepCluster encoder (frozen) + head trained on labels | 0.9582 |
Seeds are fixed (SEED = 0).
Training the encoder on pseudo-labels alone gets it most of the way to a usable representation: a head that only ever sees the frozen 6400-dimensional feature vector recovers the digit classes with high accuracy.
git clone https://github.com/DMHamann/deepcluster.git
cd deepcluster
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
jupyter lab notebooks/deepcluster.ipynbMNIST is downloaded automatically into data/raw/ on the first run. The notebook uses relative
paths, so run it from the notebooks/ directory.
Caron, M., Bojanowski, P., Joulin, A., & Douze, M. (2018). Deep Clustering for Unsupervised Learning of Visual Features. ECCV. arXiv:1807.05520