【画像生成】Encoderで生成された潜在空間をクラスタリングして遊んでみた♬

**Encodeすると潜在空間に射影される。**
**潜在空間では自動的（教師なし）に分類されている。**
今回は、それを明示的に見るために潜在空間に射影されたデータをk-meansでクラスタリングしてみた。
代表的な結果として、潜在空間３次元でMNISTの７のみの学習に対してクラスター数３で分類した例は、以下のような図となった。
![mnist_7_cluster3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/c1b75164-f744-1f96-bec6-08aebbf28547.gif)
そして、PCA分析して二次元でプロットすると以下のような図になった。
![keiba3_std2_PCA12_plotSn3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/b3fa192a-27d7-ff05-9a27-d4b1455a4add.jpeg)
この記事では、以下の結果に至るコードの解説とその他遊んだことを記録するものである。
###やったこと
・encoderの学習とz-meansデータ取得の肝
・k-means及びPCA分析の実施
・いわゆるMNISTデータの場合
###・encoderの学習とz-meansデータ取得の肝
ここは、これまでの記事を見ていただければまんまです。
そして、z-meansのデータは以下のように取得することができます。
コード全体は以下に置いています。
・[MachineLearning/keras_conv2d_latent_CSV_z3.py](https://github.com/MuAuan/MachineLearning/blob/master/keras_conv2d_latent_CSV_z3.py)

```py
import csv
z_mean = encoder.predict(x_test, batch_size=batch_size)
    
with open('./k-means/data/csv_out3.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerows(z_mean) 
```
これで、以下のようなデータが１００００個取得できます。

```
0.4188518,2.1097643,2.7087715
0.64801884,-1.6204545,-1.5555127
1.6474173,-0.45524627,0.27085924
-3.5128038,0.42994714,5.804726
-2.1056812,2.8321767,-0.13669921
2.0783038,0.020626616,0.48062828
0.40148857,1.4354955,0.54852843
1.841552,0.86197054,-4.8935328
...
```
###・k-means及びPCA分析の実施
これも以前競馬騎手リーディングの分析と同じコードで実施できます。
コード全体は以下のとおりです。
・[MachineLearning/k-means_plot3d.py](https://github.com/MuAuan/MachineLearning/blob/master/k-means_plot3d.py)
まず、データ読み込みは以下のとおり

```py
df = pd.read_csv("./k-means/data/csv_out3.csv", sep=',', na_values=".")
X=df.iloc[:, 0:]
```
次に、クラスタリングの分類数の予測するために、distortionを計算します。
結果は、以下のとおりで７だけの学習でもクラスタリング数はだらだらしていて、決められません。
![keiba3__Distortion.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/9369ef7f-7137-440a-921c-07d99de271b1.jpeg)
一方、０-９の学習では、以下ような図になります。
![keiba3__Distortion.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/93e85a50-4f56-e484-27f3-0381fb65dfa0.jpeg)
クラスタ数は５－７辺りが適当なようです。
※本来、１０カテゴリなんですが、。。。
ということで、クラスタ数３として以下のようにk-meansで分類します。

```py
s=3
# この例では s個のグループに分割 (メルセンヌツイスターの乱数の種を 10 とする)
kmeans_model = KMeans(n_clusters=s, random_state=10).fit(df.iloc[:, :])
```
さらに、分類ラベルを取得しサンプルごとに色コードを割り当てます。

```py
# 分類結果のラベルを取得する
labels = kmeans_model.labels_
print(labels)     ##################  print(labels) ###################
# それぞれに与える色を決める。
color_codes = {0:'#00FF00', 1:'#007777', 2:'#0000FF', 3:'#00FFFF' , 4:'#FF0000', 5:'#f0FF00', 6:'#FF7700', 7:'#0070FF', 8:'#08FFFF' , 9:'#077777',10:'#177777', 11:'#277777', 12:'#377777', 13:'#477777' , 14:'#577777'}
# サンプル毎に色を与える。
colors = [color_codes[x] for x in labels]
```
一旦、二次元の相関図描画後、以下でlabelsを一意に（重複を削除したものに）定義しなおします。
※画像の分類だとカテゴリ間の相関は今回は意味がないので掲載しません

```py
# 分類結果のラベルを取得する
labels = np.unique(kmeans_model.labels_)
```
以下のようにPCA分析します。
そして、PCAの主軸方向のベクトルを定義し、潜在空間内のベクトル（座標）を計算しています。

```py
#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, :])
PCA(copy=True, n_components=None, whiten=False)
v_pca0 = pca.components_[0]
v_pca1 = pca.components_[1]
v_pca2 = pca.components_[2]
X_pca1=[0,0+10*v_pca0[0]]
Y_pca1=[0,0+10*v_pca0[1]]
Z_pca1=[0,0+10*v_pca0[2]]
X_pca2=[0,0+10*v_pca1[0]]
Y_pca2=[0,0+10*v_pca1[1]]
Z_pca2=[0,0+10*v_pca1[2]]
X_pca3=[0,0+10*v_pca2[0]]
Y_pca3=[0,0+10*v_pca2[1]]
Z_pca3=[0,0+10*v_pca2[2]]
```
そして、全データを主軸への写像計算し、描画します。

```py
feature = pca.transform(df.iloc[:, 0:])
x,y,z = feature[:, 0], feature[:, 1], feature[:, 2]
X=np.c_[x,y,z]
```

```py
for angle in range(0, 360, 1):
    show_with_angle(angle)
```

```py
def show_with_angle(angle):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.view_init(elev = 10., azim = angle)
    #以下でクラスタ中心にクラスタ名を記載しています
    for kx, ky,kz, name in zip(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], kmeans_model.cluster_centers_[:,2], labels):
        ax.text(kx, ky,kz, name, alpha=0.8, size=20)
    #以下で主軸ベクトルを記載しています
    ax.plot(X_pca1,Y_pca1,Z_pca1, c='b', marker='o', alpha=0.5, label='1st pricipal')  
    ax.plot(X_pca2,Y_pca2,Z_pca2, c='r', marker='o', alpha=0.5, label='2nd principal') 
    ax.plot(X_pca3,Y_pca3,Z_pca3, c='g', marker='o', alpha=0.5, label='3rd principal') 
    #以下データをプロット
    ax.scatter3D(df.iloc[:, 0], df.iloc[:, 1], df.iloc[:, 2],  c=colors, marker='o', alpha=1, cmap=plt.cm.jet)
    #以下、クラスタ中心に＊を表示
    ax.scatter3D(np.ravel(kmeans_model.cluster_centers_[:,0]), np.ravel(kmeans_model.cluster_centers_[:,1]),np.ravel( kmeans_model.cluster_centers_[:,2]), c = labels, marker = "*", s = 400, cmap=plt.cm.jet)
    ax.set_xlabel('1st')
    ax.set_ylabel('2nd')
    ax.set_zlabel('3rd')
    ax.legend()
    plt.pause(0.01)
    plt.savefig('./k-means/data/keiba3_PCA3d_angle_'+str(angle)+'.jpg')
    plt.close()
```
そして、最後に再度PCA分析して２次元面（第一主成分、第二主成分）に写像して、再度クラスタリングしてプロットします。

```py
# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 0:])
x,y = feature[:, 0], feature[:, 1]
X=np.c_[x,y]
kmeans_model = KMeans(n_clusters=s, random_state=10).fit(X) #PCA平面（ｘ、ｙ）で再度クラスタリング
```

```py
plt.figure(figsize=(6, 6))
for kx, ky, name in zip(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], labels):
    plt.text(kx,ky, name, alpha=0.8, size=20)
plt.scatter(x, y, alpha=0.8, color=colors)
plt.scatter(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], c =labels , marker = "*", s = 400)
plt.title("Principal Component Analysis")
plt.xlabel("The first principal component score")
plt.ylabel("The second principal component score")
plt.pause(1)
plt.savefig('./k-means/data/keiba3_std2_PCA12_plotSn'+str(s)+'.jpg')
plt.close()
```
###・いわゆるMNISTデータの場合
０－９の１０個のデータを使うと以下のような画像が得られました。
![mnist_all_cluster10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/9683f63b-2e48-9c53-fa31-532987d30a91.gif)
そして、PCA分析した後のクラスタリング結果は、以下の通りになりました。
![keiba3_std2_PCA12_plotSn10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/79bdb233-a064-8e14-87ea-48a8ec01b7c6.jpeg)
そして、７だけを学習した場合もクラスタ数１０でやってみると、
![mnist_7_cluster10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/a774640e-7aea-e4e3-0752-8d7c3e56b319.gif)
PCA分析後の二次元クラスタリングは以下のとおり
![keiba3_std2_PCA12_plotSn10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/1417ba50-58c1-4617-745c-0959b7babcb5.jpeg)

以上のグラフから潜在空間では一定の分類がされているということが分かります。
クラスタ数は１０は少し多すぎるようです。
３だと上記のように分類は明確なのでこの辺りが妥当だと思われます。
###まとめ
・Encoderで生成された潜在空間をクラスタリングしてみた
・MNISTの場合もともと０－９の１０分類であり、クラスタ数１０で分析すると分類できた
・同じように、７のみ学習した場合も同様にクラスタリングしてみると、クラスタ数３だと綺麗に分類できた

・この分類で得られる入力画像及び同時に学習したDecoderで出力される画像をそれぞれ具体的に描画することにより、カテゴライズの内容を具体的に確認しようと思う