LoginSignup
3
2

More than 3 years have passed since last update.

【Ruby】t-SNEでMNISTを次元圧縮して可視化してみた

Last updated at Posted at 2019-05-19

はじめに

image.png
Rumaleという、Rubyで書かれた高速な機械学習のライブラリがあります。

こちらに軽い気持ちでt-SNEをリクエストしたところ、あっという間に実装されていました。
責任を感じてQiitaに記事を書いています。

t-SNEは教師なし学習のアルゴリズムです。
この記事ではRumaleでMNISTを3D可視化してみます。こんな感じでMNISTの画像が分類できているのがわかります。
rumale.gif

Rumale とは

https://github.com/yoshoku/rumale
Rubyで機械学習ができると評判のライブラリ。
scikit-learn の教科書を片手にRubyで機械学習の勉強ができる。

リファレンス:
ターミナルで yard server -gd と打って、ブラウザで http://localhost:8808 を開く

t-SNE とはなにか?

t-SNEは高次元データの次元削減と可視化ができる人気のアルゴリズムです。
ではt-SNEはどんな仕組みで動いているのでしょうか? ぜんぜんわかりませんっ!(こころの悲鳴)
なので申し訳ありませんがt-SNEの中味についてはほかの記事の解説をご参照ください(…こんなことでいいのだろうか)。

Red-datasets

Red-datasetsでMNISTを読み込んでいます。

コードを書く

t-SNEの実行速度は、OpenBLASを使用しているかどうかで圧倒的な差が出ますので今後Rumaleを真剣に使っていく場合はOpenBLASとnumo-linalgをインストールしてください。しかし、Rumaleを試すだけなら、OpenBLASは要りません。
t-SNEにかける前に、主成分分析で50〜80程度に次元を下げます。

# require 'numo/linalg' # OpenBLAS
require 'rumale'
require 'datasets'
require 'numo/gnuplot'

# 省略してみる
N = Numo
R = Rumale

# 最初のn個のデータを使う
n = 2000
pixels = []
labels = []

# mnistからデータを用意する
mnist = Datasets::MNIST.new
mnist.take(n).map do |record|
  pixels << record.pixels
  labels << record.label
end

# Rubyの配列を Numo::NArrayの配列に変換する
samples = N::DFloat[*pixels]
labels  = N::Int32[*labels]

# 主成分分析
pca = R::Decomposition::PCA.new(
  n_components: 50
)
samples = pca.fit_transform(samples)

# t-SNE
tsne = R::Manifold::TSNE.new(
  n_components: 3, perplexity: 50.0, max_iter: 500, verbose: true
)
low_samples = tsne.fit_transform(samples)

t-SNEの max_iterperplexity を変更すると、プロットの様子が変わります。
再現性を重視する場合はrandom_seedを設定することができます。今回は3Dなので、n_components に3を指定します。

続いて、numo-gnuplotを用いて3Dプロットをします。

# Gnuplot用のデータを用意する
data_for_gnuplot = (0..9).map do |i|
  w = labels.eq(i).where
  x = low_samples[w, 0]
  y = low_samples[w, 1]
  z = low_samples[w, 2]
  [x, y, z, { t: i.to_s, pt: 7 }]
end

# Gnuplotで表示する
N.gnuplot do
  reset
  splot *data_for_gnuplot
  gets # 待ち
end

こんな感じのウィンドウが立ち上がれば成功です!
output.gif
うおおお!! なんとなく同じラベルの色が固まっていて、いい感じに分類されていることがわかります。

しかし、よくみると0と8, 1と9が同じ色になっていたりして、表示としてはイマイチです。なので色や透過性を指定して、出力をcairopngに変更して、連番で出力した画像をGIFアニメーションに変換したりといろいろ見た目を整えてパラメータも若干変えると冒頭の画像になります。(コードがゴチャゴチャして時間も割とかかるので省略。)

rumale.gif

こんな感じで簡単に機械学習のアルゴリズムをいろいろ実行できます。とても便利!

参考資料

この記事はRumaleの公式ブログ:洋食の日記 Rumaleにt-SNEを実装したを参照しながら書きました。公式資料の方が詳しいのでご参照ください。

この記事は以上です。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2