post Image
教師なし学習で画像分類をする

教師なし学習の主な目的はEDAです。しかし、類似画像を教師なし学習で表示するようなサービスもあります。ここでは、教師なし学習であるKmeans, AgglomerativeClustering, DBSCANを比較します。


顔画像データの準備

まず、利用するデータをインポートしてデータについて少々理解を得ていきましょう。

In[1]:

%matplotlib inline

from sklearn.datasets import fetch_lfw_people
import matplotlib.pyplot as plt

people = fetch_lfw_people(min_faces_per_person=20, resize=0.7)

image_shape = people.images[0].shape
fix, axis = plt.subplots(2, 5, figsize=(15, 8), subplot_kw={'xticks':(), 'yticks':()})
for target, image, ax in zip(people.target, people.images, axis.ravel()):
ax.imshow(image)
ax.set_title(people.target_names[target])

Out[1]:

download.png

上のような顔画像データをインポートしています。顔画像のそれぞれの人物のサイズを見てみます。

In[2]:

import numpy as np

counts = np.bincount(people.target)

for i, (count, name) in enumerate(zip(counts, people.target_names)):
print("{0:25} {1:3}".format(name, count), end=' ')
if (i+1) % 3 == 0:
print()

Out[2]:

Alejandro Toledo           39   Alvaro Uribe               35   Amelie Mauresmo            21   

Andre Agassi 36 Angelina Jolie 20 Ariel Sharon 77
Arnold Schwarzenegger 42 Atal Bihari Vajpayee 24 Bill Clinton 29
Carlos Menem 21 Colin Powell 236 David Beckham 31
Donald Rumsfeld 121 George Robertson 22 George W Bush 530
Gerhard Schroeder 109 Gloria Macapagal Arroyo 44 Gray Davis 26
Guillermo Coria 30 Hamid Karzai 22 Hans Blix 39
Hugo Chavez 71 Igor Ivanov 20 Jack Straw 28
Jacques Chirac 52 Jean Chretien 55 Jennifer Aniston 21
Jennifer Capriati 42 Jennifer Lopez 21 Jeremy Greenstock 24
Jiang Zemin 20 John Ashcroft 53 John Negroponte 31
Jose Maria Aznar 23 Juan Carlos Ferrero 28 Junichiro Koizumi 60
Kofi Annan 32 Laura Bush 41 Lindsay Davenport 22
Lleyton Hewitt 41 Luiz Inacio Lula da Silva 48 Mahmoud Abbas 29
Megawati Sukarnoputri 33 Michael Bloomberg 20 Naomi Watts 22
Nestor Kirchner 37 Paul Bremer 20 Pete Sampras 22
Recep Tayyip Erdogan 30 Ricardo Lagos 27 Roh Moo-hyun 32
Rudolph Giuliani 26 Saddam Hussein 23 Serena Williams 52
Silvio Berlusconi 33 Tiger Woods 23 Tom Daschle 25
Tom Ridge 33 Tony Blair 144 Vicente Fox 32
Vladimir Putin 49 Winona Ryder 24

偏りが大きいので、サイズを50に制限します。

In[3]:

from sklearn.decomposition import PCA

mask = np.zeros(people.target.shape, dtype=np.bool)
for target in np.unique(people.target):
mask[np.where(people.target == target)[0][:50]] = 1
X_people = people.data[mask]
y_people = people.target[mask]

X_people = X_people / 255

pca = PCA(n_components=100, whiten=True, random_state=0)
X_pca = pca.fit_transform(X_people)


DBSCAN

まず、DBSCANを試してみます。近接度epsを設定する必要がありますが、クラスタ数は自動的に決定されます。

In[4]:

from sklearn.cluster import AgglomerativeClustering,DBSCAN,KMeans

for eps in [1, 3, 5, 7, 9, 11, 13, 15, 17]:
print("eps:{}".format(eps))
dbscan = DBSCAN(eps=eps, min_samples=3)
labels = dbscan.fit_predict(X_pca)
print("Clusters present:{}".format(np.unique(labels)))
print("Clusters size:{}".format(np.bincount(labels + 1)))
print()

Out[4]:

eps:1

Clusters present:[-1]
Clusters size:[2063]

eps:3
Clusters present:[-1]
Clusters size:[2063]

eps:5
Clusters present:[-1]
Clusters size:[2063]

eps:7
Clusters present:[-1 0 1 2 3 4 5 6 7 8 9 10 11 12]
Clusters size:[2003 4 14 7 4 3 3 4 4 3 3 5 3 3]

eps:9
Clusters present:[-1 0 1 2]
Clusters size:[1306 751 3 3]

eps:11
Clusters present:[-1 0]
Clusters size:[ 413 1650]

eps:13
Clusters present:[-1 0]
Clusters size:[ 120 1943]

eps:15
Clusters present:[-1 0]
Clusters size:[ 31 2032]

eps:17
Clusters present:[-1 0]
Clusters size:[ 6 2057]

-1はノイズを表しています。まともにクラスタが出力されているのはeps=7だけのようです。

In[5]:

dbscan = DBSCAN(eps=7, min_samples=3)

labels = dbscan.fit_predict(X_pca)

for cluster in range(max(labels)+1):
mask = labels == cluster
n_images = np.sum(mask)
fig, axes = plt.subplots(1, n_images, figsize=(n_images + 1.5, 4),
subplot_kw={'xticks':(), 'yticks':()})
for image, label, ax in zip(X_people[mask], y_people[mask], axes):
ax.imshow(image.reshape(image_shape), vmin=0, vmax=1)
ax.set_title(people.target_names[label].split()[-1])

Out[5]:

Screenshot from 2017-11-15 07-44-20.png

出力が大きいので一部のみ表示しています。小泉は日本人なので特徴があり、正しく分類されています。


Kmeans

つぎに、kmeansを用いてみます。kmeansはクラスタセンタを生成します。

In[6]:

km = KMeans(n_clusters=10, random_state=0)

labels_km = km.fit_predict(X_pca)
print("Cluster size k-means:{}".format(np.bincount(labels_km)))

Out[6]:

Cluster size k-means:[113 256 188 147 216 180 258 211 139 355]

In[7]:

import mglearn

mglearn.plots.plot_kmeans_faces(km, pca, X_pca, X_people, y_people, people.target_names)

Out[8]:

download (2).png

一番左の出力がクラスタセンタ、その次の5つが最もクラスタセンタに近い画像、右の5つが最も遠い画像です。視線の方向や顔の角度が影響していることがわかります。


AgglomerativeClustering

最後に、AgglomerativeClusteringを試します。

In[8]:

agglomerative = AgglomerativeClustering(n_clusters=10)

labels_agg = agglomerative.fit_predict(X_pca)
print("Cluster size:{}".format(np.bincount(labels_agg)))

Out[8]:

Cluster size:[478 254 317 119  96 191 424  17  55 112]

ランドスコアをチェックし、Kmeansの結果と比較します。

In[9]:

from sklearn.metrics import adjusted_rand_score

adjusted_rand_score(labels_agg, labels_km)

Out[9]:

0.06975311521947071

0.069なので、Kmeansとは全く異なる結果を出力したことがわかります。分類された画像を見てみましょう。

In[10]:

n_clusters = 10

for cluster in range(n_clusters):
mask = labels_agg == cluster
fig, axes = plt.subplots(1, 10, subplot_kw={'xticks':(), 'yticks':()}, figsize=(15, 8))
axes[0].set_ylabel(np.sum(mask))
for image, label, asdf, ax in zip(X_people[mask], y_people[mask], labels_agg[mask], axes):
ax.imshow(image.reshape(image_shape), vmin=0, vmax=1)
ax.set_title(people.target_names[label].split()[-1], fontdict={'fontsize':9})

Out[10]:

Screenshot from 2017-11-15 07-53-26.png


おわりに

ここでは、3つの教師なし学習を用いて画像分類しました。EDAで教師なし学習を使うと、データについてなんらかの理解を得られる可能性があります。しかし、実運用で教師なし学習を用いる場合、スコアリングができないという点に注意が必要です。また、複数のクラスタリングアルゴリズムがまったく異なる出力をすることにも注意したほうがよいでしょう。


参考

https://github.com/amueller/introduction_to_ml_with_python/blob/master/03-unsupervised-learning.ipynb


『 Python 』Article List