• トップ
  • ブログ一覧
  • Julia入門~高速な動的型付け言語~【Fluxでの機械学習編】
  • Julia入門~高速な動的型付け言語~【Fluxでの機械学習編】

    広告メディア事業部広告メディア事業部
    2020.11.23

    IT技術

    Fluxで機械学習編~Juliaに入門してみよう~

    前回は、Julia と Jupyter Notebook を連携して、グラフ描画する方法を紹介しました。

    Julia入門~高速な動的型付け言語~【Jupyter Notebookを使ったグラフ描画編】2020.11.10Julia入門~高速な動的型付け言語~【Jupyter Notebookを使ったグラフ描画編】Jupyter Notebookを使ったグラフ描画編~Juliaに入門してみよう~前回は、Julia の Web フレ...

    今回は、Julia の機械学習フレームワーク「Flux」を紹介していきます!

    ※本記事で使用するのは、「Julia ver 1.5」です。

    Fluxをインストールする

    Flux は、Julia 向けに提供されている、機械学習フレームワーク。

    Github の README を読むと、

    Flux は100% Julia で書かれており、簡単に機械学習モデルを構築できる。

    と、記載されています。

    【Github:Flux】
    https://github.com/FluxML/Flux.jl

    ちなみに、今回は試しませんが、GPU コンピューティングもできるそうです。

    機械学習フレームワークでは、なかなかの完成度と言えそうですね!

    インストール

    いつも通り、パッケージモードで追加します。

    1(@v1.5) pkg> add Flux

    これだけで OK です。

    本記事では、執筆時点で最新の「v 0.11.0」を使用しています。

    Fluxを使ってみる!

    それでは早速、Jupyter Notebook を立ち上げて、実際に触ってみましょう!

    1$ jupyter notebook

    まずは、Flux を読み込みます。

    そこそこ時間がかかりますが、気長に待ちましょう…

    1using Flux

    基本演算 (勾配演算)

    Julia は、数学演算に特化しているため、「勾配計算」も Flux と組み合わせれば、簡単に計算ができます。

    1f(x) = 3x^2 + 2x + 1
    2df(x) = gradient(f, x)[1]    # 一階微分 df/dx = 6x + 2
    3d2f(x) = gradient(df, x)[1]  # 二階微分 d²f/dx² = 6
    4
    5println(df(2))   # > 14
    6println(d2f(2))  # > 6

    もちろん、多変数関数の微分もできますし、一度にまとめて計算することもできます。

    1f(x, y) = sum((x .- y).^2)  # f(x,y) = (x-y)²
    2
    3println(gradient(f, [2, 1], [2, 0]))  # df(2, 1) & df(2, 0)
    4
    5# > ([0, 2], [0, -2])

    ただ、機械学習でのパラメータ数は、「何百・何千・何万」という単位ですので、いちいち計算してられませんね…。

    一方の Flux では、パラメータを一つにまとめることができるので、手間が省けるのです。

    1x = [2, 1]
    2y = [2, 0]
    3
    4gs = gradient(params(x, y)) do
    5         f(x, y)
    6end
    7
    8println(gs[x])  # > [0, 2]
    9println(gs[y])  # > [0, -2]

    単純なモデルで試してみる

    それでは、少し機械学習寄りのコードも書いてみましょう!

    線分回帰モデルを試す

    ここでは、シンプルな「線形回帰モデル」を定義していきます。

    1W = rand(2, 5)  # 重み
    2b = rand(2)     # バイアス
    3
    4predict(x) = W*x .+ b
    5
    6function loss(x, y)
    7    ŷ = predict(x)
    8    sum((y .- ŷ).^2)  # 二乗誤差 (Juliaでは最後の結果がreturnされる)
    9end
    10
    11x, y = rand(5), rand(2) # 適当なデータ
    12
    13println("x = $(x)")
    14println("y = $(y)")
    15println("ŷ = $(predict(x))")
    16println("loss = $(loss(x, y))")
    1# 出力例
    2x = [0.6147959006414276, 0.07791447535736151, 0.28634504031397356, 0.7806187614798725, 0.06985734225178786]
    3y = [0.7047761745357362, 0.1583882051433998]
    4ŷ = [1.6040926838038974, 1.2723395138879994]
    5loss = 2.0496577020960767

    上のコードを見ると、.+ や.- という表記が気になるかもしれません。

    これは、加減演算子が関数として定義されているためで、配列データなどを繰り返し計算するために、ドット. をつけています。

    今はまだ、ランダムで初期化された「重み」と「バイアス」なので、誤差がかなり大きいですね…。

    勾配降下法を実装する

    誤差が大きいので、勾配を計算して、「勾配降下法」を実装してみます。

    1gs = gradient(() -> loss(x, y), params(W, b))

    この勾配の計算は、以下のような書き方でも、同じ意味になります。

    1gs = gradient(params(W, b)) do
    2    loss(x, y)
    3end

    次は、勾配降下法で、一度だけ重みを更新してみましょう!

    1W̄ = gs[W]       # Wについて勾配を計算
    2W .-= 0.1 .* W̄  # w ← w - η∇w
    3
    4println(loss(x, y))
    1# 出力例
    21.2596519626536098

    しっかりと、誤差が小さくなっていますね!

    コード量としては、かなり少ないのにもかかわらず、簡単に勾配計算ができてしまいました。

    この線形回帰モデルのコードは、以下のとおり、たったこれだけです。

    1using Flux
    2
    3W = rand(2, 5)  # 重み
    4b = rand(2)     # バイアス
    5
    6predict(x) = W*x .+ b
    7
    8function loss(x, y)
    9    ŷ = predict(x)
    10    sum((y .- ŷ).^2)  # 二乗誤差 (Juliaでは最後の結果がreturnされる)
    11end
    12
    13x, y = rand(5), rand(2) # 適当なデータ
    14
    15# 勾配計算
    16gs = gradient(() -> loss(x, y), params(W, b))
    17
    18# 勾配降下法
    19W̄ = gs[W]       # Wについて勾配を計算
    20W .-= 0.1 .* W̄  # w ← w - η∇w

    とてもコンパクトですね!

    層を定義してみる

    機械学習といえば、ニューラルネットワークで、多層にしたモデルが一般的です。

    それを、Flux で単純に実装していきましょう!

    1# 2層構造のシンプルな全結合ニューラルネットワーク
    2# In(5) - fc(3) - fc(2)
    3
    4W1 = rand(3, 5)
    5b1 = rand(3)
    6layer1(x) = W1 * x .+ b1  # Layer1の出力
    7
    8W2 = rand(2, 3)
    9b2 = rand(2)
    10layer2(x) = W2 * x .+ b2  # Layer2の出力
    11
    12model(x) = layer2(σ.(layer1(x))) # モデルの定義 (σはシグモイド関数)
    13
    14println(model(rand(5)))  # >: [1.857204783239992, 1.8739117950968038]

    コード自体は、とてもシンプルで、実際に適切に動作します。

    ただ、もし多層にしたくなったとき、少し面倒ですね…

    これを回避するために、一つのアイデアとして、以下のように関数で全結合層を定義すると良いでしょう。

    1# 2層構造のシンプルな全結合ニューラルネットワーク
    2# In(5) - fc(3) - fc(2)
    3
    4function linear(in, out)
    5    W = randn(out, in)
    6    b = randn(out)
    7    x -> W * x .+ b  # xを引数とする無名関数を返す
    8end
    9
    10linear1 = linear(5, 3)
    11linear2 = linear(3, 2)
    12
    13model(x) = linear2(σ.(linear1(x)))
    14
    15println(model(rand(5)))
    16
    17println(linear1.W)  # のようにパラメータもアクセス可能

    かなりシンプルで、可読性に長けた形になりました!

    ちなみFlux では、Dense() という名前で、すでに全結合層が用意されています

    層を積み上げてみる

    それでは、Flux に用意されている便利な機能を存分に使って、ネットワークを構築してみます。

    例えば、3層のニューラルネットワークであれば、以下のコードだけでOKです。

    1model2 = Chain(
    2    Dense(10, 5, σ),
    3    Dense(5, 2),
    4    softmax)
    5  
    6println(model2(rand(10)))  # >: Float32[0.7592539, 0.24074602]

    Flux では、モデルを単なる関数として扱える点が、大きな特徴です。

    PyTorch なんかもそうですが、「パラメータアクセスができる関数」といったところでしょうか。

    さいごに

    今回は、Juila の機械学習フレームワーク Flux について、簡単に紹介しました。

    「何かしらデータセットを学習させて…」といったことはしませんでしたが、Flux の使い勝手の良さが、少なからず伝わったかと思います。

    ちなみに、公式ドキュメントでは、他にも充実した実装サンプルが掲載されています。

    もし、興味を持った方は、ぜひ試してみてくださいね!

    【 Flux 公式サイト】
    https://fluxml.ai/Flux.jl/stable/

    さて、今回で「高速な動的型付け言語 Julia に入門する」シリーズは終わりになります。

    今後また、応用編として、Julia の記事を書くかもしれません。

    その時をお楽しみに!

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
    featureImg2020.07.27IT・コンピューターの歴史特集IT・コンピューターの歴史をまとめていきたいと思います!弊社ブログにある記事のみで構成しているため、まだ「未完成状態」...
    featureImg2020.07.28機械学習 特集知識編人工知能・機械学習でよく使われるワード徹底まとめ!機械学習の元祖「パーセプトロン」とは?【人工知能】ニューラルネ...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    広告メディア事業部

    広告メディア事業部

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background