Juliaでの機械学習パッケージは色々あるが、今回はPyCall.jlを使って、Pythonの機械学習フレームワークTensorFlowと使ってみよう。そして、TensorFlowの高レベルAPIであるKerasを使うことで、Juliaからもお気楽に機械学習ができることをみてみる。
Juliaを使うことで、Python特有のforループをなるべく使わない、とか、numpyでの配列の作り方、などにとらわれる必要がなくなり、Juliaで作った配列をTensorFlowに投げ込むことができるようになる。
この記事の一番最後に、全体のコードを載せておいた。
[2019年9月2日追記]以下の記事ではPythonのA.B
を表現するためにA[:B]
を使っているが、最新のPyCall.jlでは、A.B
をJuliaでも使うことができる。
[2021年5月27日追記]Julia 1.6での動作確認をしたコードを追記。
機械学習フレームワークとこれまでの記事
Juliaでの機械学習フレームワークはいくつかあり、
Flux.jl:
「Juliaで機械学習:深層学習フレームワークFlux.jlを使ってみる その1:基本編」
https://qiita.com/cometscome_phys/items/e99d6177325e78ebb228
「Juliaで機械学習:深層学習フレームワークFlux.jlを使ってみる その2:線形回帰編」
https://qiita.com/cometscome_phys/items/f58174c0dad7ecb811ed
「Juliaで機械学習:深層学習フレームワークFlux.jlを使ってみる その3:ニューラルネットとバッチ正規化編」
https://qiita.com/cometscome_phys/items/1b7ad193dc1db9b184db
や
Knet.jl:
「Juliaで機械学習:深層学習フレームワークKnet.jlを使ってみる」
https://qiita.com/cometscome_phys/items/f09e801bc5b3f57f6350
そして、
TensorFlow.jl:
「JuliaでTensorFlow その1」
https://qiita.com/cometscome_phys/items/358bc4a1feaec1c7fa14
「JuliaでTensorFlow その2: 線形回帰をやってみる」
https://qiita.com/cometscome_phys/items/244cfed8ab309156735c
「JuliaでTensorFlow その3: 過学習について」
https://qiita.com/cometscome_phys/items/638dca2c980ab0f98a9e
「JuliaでTensorFlow その4: 線形基底関数を用いた回帰」
https://qiita.com/cometscome_phys/items/92dba9f82cd58d877ec5
「JuliaでTensorFlow その5: ニューラルネットワークの導入と深層学習」
https://qiita.com/cometscome_phys/items/45017aa9741c5fdc7eb9
という記事をすでに書いている。
今回は、Juliaの機械学習フレームワークではなく、Pythonの機械学習フレームワークをJuliaから使ってみることとする。TensorFlow以外の有名なフレームワークとしては、PyTorchがあり、
「PyCall.jlでPyTorch使ってDeep Learningする」
https://qiita.com/yatra9/items/0a1a9a5ba19e9efe08c0
を参考にさせていただいた。
バージョン
Julia 1.1.0
TensorFlow 1.12.0
を用いる。コードはMac OS 10.14.3の上で実行した。
TensorFlowのインストール
まず、TensorFlowが入っていない方のために、TensorFlowのインストールから述べる。色々なインストール方法があると思うが、ここではAnacondaを用いることとする。
まず、
https://www.anaconda.com
から自分のOSに合ったAnacondaを入れる。
インストールが終わったら、
conda create -n keras
として、新しいcondaの環境を作る。
そして、
conda activate keras
でアクティベートする。
そして、Pythonを3.6に指定して(2019年2月8日現在、TensorFlowはPython 3.7をサポートしていないため)、
conda install python=3.6 tensorflow
として、TensorFlowをインストールする。
インストールが終わったら、
which python
でpythonの入っているpathを見ておく。例えば、Macであれば、
/anaconda3/envs/keras/bin/python
などが表示される。
PyCallのインストール
次に、Juliaを起動して、PyCallのインストールを行う。
まず、先ほど調べたpathをJulia上で
ENV["PYTHON"]="/anaconda3/envs/keras/bin/python"
としてセットする。次に、]を押してパッケージモードにしてから、
add PyCall
をする。もしすでにPyCallが入っている場合には、
build PyCall
で入れ直しができる。これが終わったら、delキーなどを押してパッケージモードを終了する。
PyCallを用いたTensorFlowによる機械学習
バージョンの確認
まず、インストールしたPythonのバージョンを確認しておこう。
using PyCall
PyCall.pyversion
でPythonのバージョンを表示できる。
v"3.6.8"
などが出れば、ちゃんとPython 3.6系が入っていることになる。
TensorFlowとKerasのバージョンを確認しておく。
そのためには、
const tensorflow = pyimport("tensorflow")
としてから、
println( tensorflow[:__version__])
とすればTensorFlowのバージョンが表示される。Pythonではtensorflow.version
となっていたが、PyCallではa.b
を使う代わりに、a[:b]
を使う。a.b.c
であれば、a[:b][:c]
となる。Kerasのバージョンは
println( tensorflow[:keras][:__version__])
で調べることができる。
バージョン
TensorFlow 1.12.0
Keras 2.1.6-tf
Kerasを用いた機械学習
それでは、実際の機械学習をやってみよう。
以後はJupyter notebookでやってもjulia test.jl
などで実行してもよい。
PythonのKerasについては、
「TensorFlowの高レベルAPIの使用方法:Kerasの使い方」
https://qiita.com/cometscome_phys/items/d9553fe7c92e09fc14a9
「TensorFlowの高レベルAPIを使ったBatch Normalizationの実装:Keras版」
https://qiita.com/cometscome_phys/items/47467f1f0e3ab0a695cb
「TensorFlowの高レベルAPIの使用方法:Dataset APIを使ってみる with Keras」
https://qiita.com/cometscome_phys/items/d36af6fcead172847231
の記事を書いているので、参考にすることができる。
この記事では、一番最初の記事でやっていることをJuliaで実行することを目的とする。
再現する関数
再現する関数は、これまでずっと使ってきた、
a0 = 3.0
a1 = 2.0
b0 = 1.0
n = 10
x0 = range(-2, 2, length=n)
y0 = zeros(n,1)
y0[:,1] = a0*x0.+a1*x0.^2 .+ b0 .+ 3*cos.(20*x0)
nm = 300
xmany = range(-2, 2, length=nm)
ymany = zeros(nm,1)
ymany[:,1] = a0*xmany.+a1*xmany.^2 .+ b0 .+ 3*cos.(20*xmany)
using Plots
plot(xmany,ymany)
savefig("test.png")
としよう。グラフは、
これまでの記事と同じように多項式でのフィッティングを行うため、
function make_phi(x0,k)
n = length(x0)
phi = zeros(n,k)
for i=1:n
for j=1:k
phi[i,j] = x0[i]^(j-1)
end
end
return phi
end
という関数を作り、
k = 6
phi = make_phi(x0,k)
phimany = make_phi(xmany,k)
としてインプットデータを作っておこう。
モデルの構築
モデルの構築は
using PyCall
const tensorflow = pyimport("tensorflow")
const keras =tensorflow[:keras]
const layers =keras[:layers]
const optimizers =keras[:optimizers]
function build_model(d_input,d_middle)
inputs = keras[:Input](shape=(d_input,))
x = layers[:Dense](d_middle, activation="relu")(inputs)
y = layers[:Dense](1)(x)
adam = optimizers[:Adam]()
model = keras[:Model](inputs=inputs, outputs=y)
model[:compile](optimizer=adam,
loss="mean_squared_error")
return model
end
でできる。ここで、PyCallで呼び出すものをあらかじめconstで定義しておいた。
また、build_model
はa.b
の代わりにa[:b]
を使っている以外はPythonのコードと変わらない。一つだけ異なるのは、activation="relu"
はPythonではactivation='relu'
となっていたことだけである。Juliaではそのまま使うとエラーとなった。
この関数を使ってKerasのモデルを作るには、
d_input = k
d_middle = 10
model = build_model(d_input,d_middle)
とすればよい。
学習
学習を行うには、
history = model[:fit](phimany, ymany, epochs=2000,batch_size=20,validation_data=(phi, y0))
とすればよい。
結果は、
ytest = model[:predict](phimany)
plot(xmany,ytest)
plot!(xmany,ymany)
savefig("testkeras.png")
testloss = history[:history]["val_loss"]
plot(testloss)
savefig("testloss.png")
でプロットしてみる。
グラフは
となり、lossは
となる。
全体コード
最後に全体コードを載せておく。
a0 = 3.0
a1 = 2.0
b0 = 1.0
n = 10
x0 = range(-2, 2, length=n)
y0 = zeros(n,1)
y0[:,1] = a0*x0.+a1*x0.^2 .+ b0 .+ 3*cos.(20*x0)
nm = 300
xmany = range(-2, 2, length=nm)
ymany = zeros(nm,1)
ymany[:,1] = a0*xmany.+a1*xmany.^2 .+ b0 .+ 3*cos.(20*xmany)
using Plots
plot(xmany,ymany)
savefig("test.png")
function make_phi(x0,k)
n = length(x0)
phi = zeros(n,k)
for i=1:n
for j=1:k
phi[i,j] = x0[i]^(j-1)
end
end
return phi
end
k = 6
phi = make_phi(x0,k)
phimany = make_phi(xmany,k)
using PyCall
const tensorflow = pyimport("tensorflow")
const keras =tensorflow[:keras]
const layers =keras[:layers]
const optimizers =keras[:optimizers]
function build_model(d_input,d_middle)
inputs = keras[:Input](shape=(d_input,))
x = layers[:Dense](d_middle, activation="relu")(inputs)
y = layers[:Dense](1)(x)
adam = optimizers[:Adam]()
model = keras[:Model](inputs=inputs, outputs=y)
model[:compile](optimizer=adam,
loss="mean_squared_error")
return model
end
d_input = k
d_middle = 10
model = build_model(d_input,d_middle)
history = model[:fit](phimany, ymany, epochs=2000,batch_size=20,validation_data=(phi, y0))
ytest = model[:predict](phimany)
plot(xmany,ytest)
plot!(xmany,ymany)
savefig("testkeras.png")
testloss = history[:history]["val_loss"]
plot(testloss)
savefig("testloss.png")
追記
Julia 1.6で動作確認したコードは以下。
a0 = 3.0
a1 = 2.0
b0 = 1.0
n = 10
x0 = range(-2, 2, length=n)
y0 = zeros(n,1)
y0[:,1] = a0*x0.+a1*x0.^2 .+ b0 .+ 3*cos.(20*x0)
nm = 300
xmany = range(-2, 2, length=nm)
ymany = zeros(nm,1)
ymany[:,1] = a0*xmany.+a1*xmany.^2 .+ b0 .+ 3*cos.(20*xmany)
using Plots
plot(xmany,ymany)
savefig("test.png")
function make_phi(x0,k)
n = length(x0)
phi = zeros(n,k)
for i=1:n
for j=1:k
phi[i,j] = x0[i]^(j-1)
end
end
return phi
end
k = 6
phi = make_phi(x0,k)
phimany = make_phi(xmany,k)
using PyCall
const tensorflow = pyimport("tensorflow")
const keras =tensorflow.keras
const layers =keras.layers
const optimizers =keras.optimizers
function build_model(d_input,d_middle)
inputs = keras.Input(shape=(d_input,))
x = layers.Dense(d_middle, activation="relu")(inputs)
y = layers.Dense(1)(x)
adam = optimizers.Adam()
model = keras.Model(inputs=inputs, outputs=y)
model.compile(optimizer=adam,
loss="mean_squared_error")
return model
end
d_input = k
d_middle = 10
model = build_model(d_input,d_middle)
history = model.fit(phimany, ymany, epochs=2000,batch_size=20,validation_data=(phi, y0))
ytest = model.predict(phimany)
plot(xmany,ytest)
plot!(xmany,ymany)
savefig("testkeras.png")
testloss = history.history["val_loss"]
plot(testloss)
savefig("testloss.png")
確認環境は
- Julia 1.6.0
- Python 3.8.9
- Tensorflow 2.5.0
julia> println( tensorflow.__version__)
2.5.0
なお、MacOSでpyenvで入れたPythonの場合は
https://qiita.com/kjunichi/items/7453814cb902158f9836
をする必要があるようだ。