logo

Julia FluxでMLPを実装しMNISTを学習する方法 📂機械学習

Julia FluxでMLPを実装しMNISTを学習する方法

MNISTデータセットの読み込み

古い例では、この部分でFlux.Dataを使用するコードを見かけることがあるが、今ではFluxでサポートされていない。

julia> Flux.Data.MNIST.images()
┌ Warning: Flux's datasets are deprecated, please use the package MLDatasets.jl

公式ドキュメント1では`MLDatasets.jl’パッケージを使用するよう案内している。

julia> using Flux

julia> using MLDatasets

julia> imgs = MLDatasets.MNIST.traintensor()
28×28×60000 reinterpret(FixedPointNumbers.N0f8, ::Array{UInt8, 3})

julia> labs = MLDatasets.MNIST.trainlabels()
60000-element Vector{Int64}

画像とラベルをこのまま使うことはできない。画像はデータ型を32ビット浮動小数点数に変換する必要があり、ラベルはワンホットエンコーディングを行う必要がある。

julia> X = float.(imgs)
28×28×60000 Array{Float32, 3}

julia> Y = Flux.onehotbatch(labs, 0:9)
10×60000 OneHotMatrix(::Vector{UInt32}) with eltype Bool

では、データとラベルをまとめて訓練集合を作ろう。次の二通りの方法がある。

  1. repeated((X, Y), n)
julia> using Base.Iterators: repeated

julia> Train_Data = repeated((X,Y), 1)

(X, Y)をn回繰り返して並べる。したがってn=10と置いてデータセットを作り学習させると、10epoch分学習するのと同じである。

  1. Flux.DataLoader((X, Y); batchsize=1, shuffle=false, partial=true, rng=GLOBAL_RNG)
julia> Train_Data = Flux.DataLoader((X,Y), batchsize=60000)

データ60,000個を一度に学習させるので、バッチサイズを60,000と置いた。

MLPの実装

MLPはChain()関数で実装できる。我々はデータ$X$を平坦化していないので、最初の層にFlux.flattenを追加する必要がある。

julia> MLP = Chain(Flux.flatten,
                   Dense(28*28, 28, relu),
                   Dense(28, 10),
                   softmax)
Chain(
  Flux.flatten,
  Dense(784, 28, relu),                 # 21_980 parameters
  Dense(28, 10),                        # 290 parameters
  NNlib.softmax,
)                   # Total: 4 arrays, 22_270 parameters, 87.242 KiB.

参考までに、flatten()をデータに適用するには、残りの部分は同じに保ち、XChain()を次のように修正すればよい。ただし速度に大きな違いはない。

X = flatten(float.(imgs))

julia> MLP = Chain(Dense(28*28, 28, relu),
                   Dense(28, 10),
                   softmax)

損失関数とオプティマイザの定義

損失関数クロスエントロピーで、オプティマイザはADAMと定義しよう。

julia> LOSS(x,y) = Flux.crossentropy(MLP(x), y)
LOSS (generic function with 1 method)

julia> LOSS(X,Y)
2.3614984f0

julia> opt = ADAM()
ADAM(0.001, (0.9, 0.999), IdDict{Any, Any}())

訓練

train!()メソッドでモデルを訓練させる。

julia> Flux.train!(LOSS, params(MLP), Train_Data, opt)

学習過程の出力2

ただし、このようにすると学習過程が分からない。次のようにコールバックを設定すると、1秒に一度ずつロスを出力する。

julia> Flux.train!(LOSS, params(MLP), Train_Data, opt, cb = Flux.throttle(() -> @show(LOSS(X, Y)), 1))
LOSS(X, Y) = 2.2364092f0

エポックの設定

@epochsマクロでエポックを設定できる。

julia> using Flux: @epochs

julia>  @epochs 5 Flux.train!(LOSS, params(MLP), Train_Data, opt, cb = Flux.throttle(() -> @show(LOSS(X, Y)), 1))
[ Info: Epoch 1
LOSS(X, Y) = 2.1822426f0
[ Info: Epoch 2
LOSS(X, Y) = 2.13155f0
[ Info: Epoch 3
LOSS(X, Y) = 2.0831218f0
[ Info: Epoch 4
LOSS(X, Y) = 2.0359747f0
[ Info: Epoch 5
LOSS(X, Y) = 1.9894044f0

訓練時間の測定

@timeマクロで訓練時間を測定できる。

julia> @epochs 5 @time Flux.train!(LOSS, params(MLP), Train_Data, opt, cb = Flux.throttle(() -> @show(LOSS(X, Y)), 1))
[ Info: Epoch 1
LOSS(X, Y) = 1.9431362f0
  0.366819 seconds (238.95 k allocations: 269.987 MiB, 33.97% compilation time)
[ Info: Epoch 2
LOSS(X, Y) = 1.8971274f0
  0.300713 seconds (418 allocations: 257.373 MiB, 18.77% gc time)
[ Info: Epoch 3
LOSS(X, Y) = 1.8515143f0
  0.247089 seconds (418 allocations: 257.373 MiB)
[ Info: Epoch 4
LOSS(X, Y) = 1.8064859f0
  0.284937 seconds (418 allocations: 257.373 MiB, 13.61% gc time)
[ Info: Epoch 5
LOSS(X, Y) = 1.7620988f0
  0.258424 seconds (418 allocations: 257.373 MiB)

コード全文

using Flux
using MLDatasets

using Base.Iterators: repeated
using Flux: @epochs

# Loading MNIST data set
imgs = MLDatasets.MNIST.traintensor()
labs = MLDatasets.MNIST.trainlabels()

# Convert to usable
X = float.(imgs)
Y = Flux.onehotbatch(labs, 0:9)

# Making training set
Train_Data = Flux.DataLoader((X,Y), batchsize=60000)
# or Train_Data = repeated((X,Y), 1)

# Define MLP, loss function, optimizer
MLP = Chain(Flux.flatten,
            Dense(28*28, 28, relu),
            Dense(28, 10),
            softmax)

LOSS(x,y) = Flux.crossentropy(MLP(x), y)

opt = ADAM()

# Training
@epochs 5 @time Flux.train!(LOSS, params(MLP), Train_Data, opt, cb = Flux.throttle(() -> @show(LOSS(X, Y)), 5))

環境

  • OS: Windows10
  • Version: Julia 1.7.1, Flux 0.12.8, MLDatasets 0.5.14