TensorFlow for R を使ってみた ~ Google の機械学習ライブラリが R に対応 / Now Google's machine learning library TensorFlow supports R

TensorFlow R を使ってみた ~ Google の機械学習ライブラリが R に対応 / Now Google's machine learning library TensorFlow supports R

先日もカリフォルニア州・モスコーンで Google Cloud Next 2017 と言うイベントを開催して、ますます人工知能・機械学習界隈を席巻してる感ある Google 先生。その大きなきっかけの一つとなったのは、ディープラーニングのライブラリ TensorFlow の公開だと思うのですが、その TensorFlow が Python と並び多くのデータサイエンティストに人気の言語 R をサポートしていました。
あまりにもひっそりとしたリリースであまり話題になっていない様子ですが、データサイエンティストの中には Python よりも R を好んで使う人も多い様子で、TensorFlow がその R をサポートすることは大きな意味があると言えそうです。
早速 R 版の TensorFlow を用いて、インストールから MNIST のサンプルまで試してみました。

** Sorry, this note is Japanese only, but please take a look at some code snippets. Hope it helps you.

参考:TensorFlow( TensorFlow for R 公式サイト)

インストールまだの人はこちらからお先にどうぞ。

datalove.hatenadiary.jp

TensorFlow for R の概要とインストール方法

R 版 TensorFlow と言うと、TensorFlow 自体が R にも移植されたような印象を与えますが、厳密には Python 版の TensorFlow を通じて TensorFlow の API を R から呼び出している、と言う表現が正しいようです。
TensorFlow for R は、TensorFlow の API を呼び出すためのインターフェースの役割のみを持っており、RStudio の開発元である と Google の協業によって開発された模様です。

なので、インストールの手順も、 1. まず Python 版 TensorFlow をインストールする
2. R のパッケージである TensorFlow for R をインストールする

と言う手順となります。

Python 版 TensorFlow のインストール

詳しくは[こちらの記事]にまとめていますが、バージョン 1.0 のリリースに伴い、インストールは随分簡単になっており特別なオプションの指定が必要ないなら、pip コマンドだけですみます。

$ pip install -U tensorflow

またお手持ちの PC の元の環境を壊す危険性を避けるために、anaconda をインストールした上で、anaconda の Python 環境で上記のインストールを行うと良いでしょう。

datalove.hatenadiary.jp

TensorFlow for R のインストール

Python 版 TensorFlow がインストールできたらいよいよ TensorFlow for R をインストールします。
TensorFlow for R は、github のソースコードリポジトリからインストールする必要があるので、まず devtools をインストールしてから、それを用いてインストールします。具体的には以下のような手順です。

$ R # R をシェルから起動する  
> install.packages('devtools') # devtools のインストール  
> devtools::install_github("rstudio/tensorflow") # devtools を用いて TensorFlow for R をインストール  

依存するパッケージのインストールなども行われるので少し時間がかかりますが、以下のような表記が表示されればインストールは無事に完了です。

* installing *source* package ‘tensorflow’ ...
** R
** inst
** tests
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (tensorflow)

TensorFlow for R の動作確認

上にも書いたように、TensorFlow for R は、Python を通して TensorFlow の API を呼び出しているため、Python の実行環境のパスを環境変数に設定しなければならない。そこで RStudio を起動したらまず次のような命令を実行して環境変数の設定を行う。

> Sys.setenv(TENSORFLOW_PYTHON='/PATH_TO_YOUR_PYTHON/python')

環境変数が設定できたら、次のような簡単なコードを実行してテストしてみよう。

> library('tensorflow')
> hello = tf$constant('Hello TensorFlow for R.')
> sess = tf$Session()
> sess$run(hello)
b'Hello TensorFlow for R.'

コードが無事に実行できればインストールに成功です。
たまに、使用環境の CPU の種類によっては次のような警告メッセージが表示されることがあるが、「計算が速くなるからこうしたほうがいいよ」という推奨であって、これがなければ使えない、というわけではないのでそのままにしておいて大丈夫。
どうしてもこの警告を無視したくない場合は、ソースからインストールする必要があるので、こちらの手順を参考にどうぞ。

datalove.hatenadiary.jp

MNIST で動作をためす

TensorFlow for R の公式サイトには本家(?)TensorFlow と同じようにいくつかのtutorial が紹介されている。
その中の一番簡単な例である、MNIST の手書き文字認識を例に、さらに動作を確認してみる。

教師データの読み込み

TensorFlow for R は、TensorFlow の API に対応しており、.(ドット)を R の表記である $ に読み替えると大抵の機能は使えるようになっている。
例えば、tf.Session() であれば前述のように tf$Session() といった具合に。
TensorFlow には tf.contrib.learn.datasets 以下にいくつかのサンプルデータがあります。R でも同じように tf$contrib$learn$datasets でサンプルデータにアクセスすることができ、MNITST の場合は次のようになります。

datasets <- tf$contrib$learn$datasets
mnist <- datasets$mnist$read_data_sets("MNIST-data", one_hot = TRUE)

モデルを定義する

モデルを作る部分も Python とほぼ同じです。変数を定義し、活性化関数 softmax の引数に Wx + b (入力ベクトル:x 、重み:W、バイアス:b)が設定されるように合成関数のように定義していきます。

x <- tf$placeholder(tf$float32, shape(NULL, 784L))
W <- tf$Variable(tf$zeros(shape(784L, 10L)))
b <- tf$Variable(tf$zeros(shape(10L)))
y <- tf$nn$softmax(tf$matmul(x, W) + b)

Python 版 TensorFlow やその他のニューラルネットワークを試している方にはおなじみかもしれませんが、一応補足しておくと、

  • 入力ベクトル x(と、バイアス項の b )から、y を出力する、単純パーセプトロンと呼ばれるシンプルなニューラルネットワークになっていて
  • 出力層に出てくる値は、活性化関数 softmax を通して一定の出力レベル以上のものだけが出力されるようになっている
  • x:入力層から入ってくる input データは、28 ×28 = 784 ピクセルの画像データを1列に並べた、1次元のベクトル(= TensorFlow 的には1階のテンソル、という)
  • y:0−9の10種類の文字種別を格納するベクトルで、例えば、(0, 0, 0, 0, 0, 0, 0, 1) –> 0、(0, 0, 0, 0, 0, 0, 1, 0) –> 1、・・・という具合に、10の要素の一つ一つが手書き文字の0−9に対応している。なお、実際の計算結果はこんなに綺麗に0と1になるのではなく、各要素がそれぞれの文字である確率となり、0<p<1 の確率値となって出力される。
  • W:入力 x と 出力 y を結びつける、「重み」と呼ばれる係数。784次元のベクトル –> 10次元のベクトルへの変換を担う行列なので、784 × 10 の行列になっている。
  • で、その W と x をかけて、バイアス項 b を足し、活性化関数 softmax を通した結果が y となる

という感じです。

TensorFlow for R による学習

さて、いよいよ定義したモデルにデータを与えて学習させる部分です。
すごく雑にいうと、機械学習(の中の、教師あり学習っていう分野は、ですが)って結局、

  1. 数式によるモデルを定義する
  2. モデルに input データを与えて、モデルに基づいた予測値を計算する
  3. 実際のデータの値と、モデルに基づいた予測値を比較してその差分を計算
    –> これを最小化するように、1.に戻ってモデルの数式をちょこっと修正 –> 2. - 3. を実行

という流れがあって、どんな手法でも概ねこの流れをフォローしています。
あとは解きたい問題ごとに、1.の数式と3.の学習ロジックをどう組むか?という話で、特に学習結果を評価する3.の差分 - コスト関数、とか呼ばれる - は機械学習の内容を大きく特徴付ける要素になるようです。
MNIST のサンプルでは、このコスト関数に、cross entropy(クロス エントロピー)と呼ばれる関数を使っていて、その数式は、こんな感じです。

{ \displaystyle
H(y, y') = - \sum_i y'_i\log(y_i)
}

このクロス エントロピー部分のコードは TensorFlow for R では次のようになります。

y_ <- tf$placeholder(tf$float32, shape(NULL, 10L))  
cross_entropy <- tf$reduce_mean(-tf$reduce_sum(y_ * tf$log(y), reduction_indices=1L))  

次はこのクロス エントロピーを最小化するロジックを書く必要がありますが、その部分も TensorFlow 自身が便利な機能を持っていて、

  • Optimizer というオブジェクトを生成し、
  • Optimizer$minimize メソッドで、引数に与えられたコスト関数(今は クロス エントロピー)を最小化する
    という形になります。コードはこんな感じ。
optimizer <- tf$train$GradientDescentOptimizer(0.5)
train_step <- optimizer$minimize(cross_entropy)

あとは TensorFlow のセッション オブジェクトの run メソッドで、コスト関数が十分小さくなるまで train_step を繰り返し実行します。

init <- tf$global_variables_initializer() # 変数を全て初期化するメソッドを定義  
sess <- tf$Session() # セッション オブジェクトの生成
sess$run(init) # 変数の初期化
for (i in 1:1000) {
  batches <- mnist$train$next_batch(100L)
  batch_x <- batches[[1]]
  batch_y <- batches[[2]]
  sess$run(train_step,
           feed_dict = dict(x=batch_x, y_=batch_y))
}

モデルの評価

モデルの評価は、モデルで予測した手書き文字の分類結果と、テストデータを比較して、どれくらい予測した分類が実際のテストデータに合致してるかをチェックします。
ただ、実際のテストデータは、0ー9それぞれに合致する要素が1、それ以外が0という具合に、キレイなバイナリ列になっているのに対し、予測値は softmax 関数で計算された値なので0 < 予測値 < 1 の小数値です。
なので、両者の比較にはちょっと工夫が必要で、TensorFlow のチュートリアルでは、tf$argmax というメソッドを用いて、softmax 関数の値が最大になる要素のインデックスと、テストデータが1になるインデックスが一致するか否かで正否の判定をしています。

correct_prediction <- tf$equal(tf$argmax(y, 1L), tf$argmax(y_, 1L))
accuracy <- tf$reduce_mean(tf$cast(correct_prediction, tf$float32))
sess$run(accuracy, feed_dict=dict(x = mnist$test$images, y_ = mnist$test$labels))
## [1] 0.9184

まとめ

ほぼ写経しただけみたいになってしまいましたが・・・英語を読むのがめんどくさい人の助けになれば。
TensorFlow 関係はこちらの記事もどうぞ。

機械学習 ・ 人工知能 関連の他の記事

datalove.hatenadiary.jp datalove.hatenadiary.jp datalove.hatenadiary.jp datalove.hatenadiary.jp