tensorflowをRstudioで

R Tips
Author

Kentaro Kamada

Published

February 23, 2024

pythonをRStudioで使うのはreticulateパッケージによりだいぶ楽になった。

ただpythonにおけるdeep learningの代表的パッケージであるtensorflowをRStudioで使う際に少しつまづいたのでメモです。

pythonの環境をどうやって構築するか?

Rではrenvパッケージを使っている。ではpythonでは?

pythonはRよりも環境が複雑で変化も早そうなので、環境構築は重要。

今回はpython公式が推奨しているっぽいvenvを使う。

Note

最初global環境でそのままやろうとしたが上手くいかず挫折。Dockerとかも有力だと思う。

venvを使って仮想環境を用意

  • pythonがインストールされているか確認
    • homebrewなりでインストールしておく
    • PATHを通しておく
  • 作業ディレクトリにて、terminalで以下のコマンドを実行し.venvフォルダを作成
terminal
python3 -m venv .venv

pythonライブラリをインストール

  • 以下のコマンドを実行し、仮想環境を起動
    • pythonの場所が.venv内のフォルダになる
terminal
source .venv/bin/activate
Note

source .venv/bin/activateは、ライブラリをインストールするときは毎回実行する必要があります!

まちがってglobal環境を汚さないように!

  • ライブラリをインストール
    • tensorflowのほか、numpyも必須(tensorflowをインストールしたときに入る)
    • M1 macでGPUを使いたい場合はtensorflow-metalもインストールする
terminal
pip install tensorflow-macos
pip install tensorflow-metal
  • 仮想環境を抜けるときは以下のコマンドを実行
terminal
deactivate

RStudioでpythonを使う

pythonの場所を指定

  • RStudioでpythonを使うには、RStudioにpythonの場所を教えてやる必要がある
    • 今回は.venv内のpythonを使いたいので、作業ディレクトリに.Rprofileを作成し、以下のコードを書く
    • renvを使っている場合は、.Rprofileが既に作成されていると思うので、その中に追記する
.Rprofile
# renv起動
source("renv/activate.R")
# pythonの場所を指定
Sys.setenv(RETICULATE_PYTHON = ".venv/bin/python3")
Note

pythonの場所の指定はrenvの起動より後に行う必要がある。もし先にpythonの場所を指定してしまうと、renvを起動したときにpythonの場所が上書きされてしまい、上手くいかなくなる。

pythonを起動

  • RStudioでpythonのコードを実行すると、reticulate::repl_python()が走ってコンソールがpythonになる
python
import sys
print(sys.version)
3.11.12 (main, Apr  8 2025, 14:15:29) [Clang 16.0.0 (clang-1600.0.26.6)]
  • tensorflowを起動して、GPUが使えるかを確認
  • physical_deviceでCPUとGPUの両方が表示されてればOK
python
import tensorflow as tf
tf.config.list_physical_devices()
[PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU'), PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

ニューラルネットをやってみる

  • チュートリアルとして、手書きのアルファベットを分類するモデルを作成してみる
  • Rでデータを読み込んで、pythonに渡してtensorflowで分析
  • 参考
R
library(tidyverse)
library(rsample)
library(reticulate)

データのダウンロード

R
# データのダウンロード
if (!dir.exists('data')) dir.create('data')
download.file('https://ai.stanford.edu/~btaskar/ocr/letter.data.gz', destfile = 'data/letter.data')

データの読み込み

  • 列名はhttps://ai.stanford.edu/~btaskar/ocr/letter.namesより取得できる
  • 詳細は以下の通り
    1. id: each letter is assigned a unique integer id
    2. letter: a-z
    3. next_id: id for next letter in the word, -1 if last letter
    4. word_id: each word is assigned a unique integer id (not used)
    5. position: position of letter in the word (not used)
    6. fold: 0-9 – cross-validation fold
    7. p_i_j: 0/1 – value of pixel in row i, column j
  • letterとp_i_j(pixel)のみ使うのでそれ以外は削除
R
colname <- read_lines('https://ai.stanford.edu/~btaskar/ocr/letter.names')
data <- 
  read_tsv('data/letter.data', col_names = colname) |> 
  # letterとpixelだけ残す
  select(id, letter, matches('p_\\d+_\\d+'))

データの前処理

  • letterを数値に変換
R
df <- 
  data |> 
  mutate(
    letter = factor(letter),
    # pythonは0からはじまるので-1する(Rは1から)
    letter_num = as.numeric(letter) - 1
  )
  • 訓練データとテストデータに分割
R
split <- rsample::initial_split(df, prop = 0.9)
train <- rsample::training(split)
test <- rsample::testing(split)
  • pythonに渡せる形にデータを変換
    • reticulate::np_array()であらかじめndarrayにしておくと便利
R
train_x <- 
  train |> 
  select(!c(id, letter, letter_num)) |>
  as.matrix() |> 
  np_array()

train_y <-
  train |>
  pull(letter_num) |>
  np_array()

test_x <-
  test |> 
  select(!c(id, letter, letter_num)) |>
  as.matrix() |> 
  np_array()

test_y <-
  test |>
  pull(letter_num) |>
  np_array()

ニューラルネットで学習

  • 中間層が1つのニューラルネットを作成
    • 入力層は16x8=128(ピクセル)
    • 中間層は64次元
    • 出力層はa-zの26分類
python
import tensorflow as tf
import numpy as np

# モデルの作成
model = tf.keras.Sequential([
  tf.keras.layers.Dense(64, activation='relu'),
  tf.keras.layers.Dense(26, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss='sparse_categorical_crossentropy',
  metrics=['accuracy']
)
  • rで作成したデータをpythonに渡して学習
  • r.train_xでRのtrain_xを参照できる
  • pythonのオブジェクトを渡すときはpy$train_x
python
# モデルの学習
model.fit(r.train_x, r.train_y, epochs=10, verbose=2)
Epoch 1/10
1467/1467 - 8s - loss: 1.3177 - accuracy: 0.6413 - 8s/epoch - 6ms/step
Epoch 2/10
1467/1467 - 6s - loss: 0.9427 - accuracy: 0.7486 - 6s/epoch - 4ms/step
Epoch 3/10
1467/1467 - 6s - loss: 0.8788 - accuracy: 0.7642 - 6s/epoch - 4ms/step
Epoch 4/10
1467/1467 - 6s - loss: 0.8475 - accuracy: 0.7729 - 6s/epoch - 4ms/step
Epoch 5/10
1467/1467 - 6s - loss: 0.8340 - accuracy: 0.7759 - 6s/epoch - 4ms/step
Epoch 6/10
1467/1467 - 6s - loss: 0.8259 - accuracy: 0.7777 - 6s/epoch - 4ms/step
Epoch 7/10
1467/1467 - 6s - loss: 0.8233 - accuracy: 0.7786 - 6s/epoch - 4ms/step
Epoch 8/10
1467/1467 - 6s - loss: 0.8240 - accuracy: 0.7773 - 6s/epoch - 4ms/step
Epoch 9/10
1467/1467 - 6s - loss: 0.8218 - accuracy: 0.7789 - 6s/epoch - 4ms/step
Epoch 10/10
1467/1467 - 6s - loss: 0.8242 - accuracy: 0.7779 - 6s/epoch - 4ms/step
<keras.src.callbacks.History object at 0x177fd5910>

テストデータで評価

  • テストデータでの正答率は77%くらい
python
# モデルの評価
model.evaluate(r.test_x, r.test_y, verbose=2)
163/163 - 1s - loss: 0.8293 - accuracy: 0.7688 - 513ms/epoch - 3ms/step
[0.8292935490608215, 0.7687883377075195]